使用新的c++11中的std::异步,我想我可以尝试实现OutputDebugString的异步版本,以使我摆脱一些性能下降,这些性能下降是由于我通常通过通常的OutputDebugString函数对每一个细节进行重打印而造成的。
下面是我最初的同步OutputDebugString实现(它可以工作):
static void OutputDebugStringN(const char *format, ...)
{
char outstring[256];
memset(outstring, 0, sizeof(outstring));
try
{
va_list args = {0};
va_start(args, format); //args = (va_list) (&format+1);
vsprintf_s(outstring, format, args);
va_end(args);
OutputDebugString(outstring);
}
catch (...) //most likely reference val arg error (va_list doesn't support ref args)
{
OutputDebugString("[OutputDebugStringN] Something went wrong\n");
}
}下面是我对异步版本的天真尝试(它不起作用):
static void OutputDebugStringN(const char *format, ...)
{
auto future = std::async([]{
char outstring[256];
memset(outstring, 0, sizeof(outstring));
try
{
va_list args = {0};
va_start(args, format); //args = (va_list) (&format+1);
vsprintf_s(outstring, format, args);
va_end(args);
OutputDebugString(outstring);
}
catch (...) //most likely reference val arg error (va_list doesn't support ref args)
{
OutputDebugString("[OutputDebugStringN] Something went wrong\n");
}
});
}由于上述操作不起作用,我现在开始认为异步调用OutputDebugStringN可能比尝试在函数内部启动异步作业要好得多(这是可行的,但很麻烦):
auto dstring = std::async([]{ OutputDebugStringN("[NovelScript::ParseTokens] searched bookmark: \"%s\" does not exist\n", bookmark.c_str());} );这里有两个问题我想问:
对上述守则的批评和任何其他评论也是非常欢迎的。
发布于 2013-01-26 11:29:43
我认为您应该为您的消息设置一个队列,而不是在每次调用函数时启动一个线程,这样您的消息就可以按照正确的顺序清晰地输出。
因此,您的函数(例如,OutputDebugStringN(const char *format, ... ) )将创建消息字符串,然后将独立打印出线程从中读取的字符串排队。这个线程会调用OutputDebugString。
这里有一个例子--虽然不完整,但是没有错误处理和print_from_queue应该被修改来运行直到某些终止条件,并且对CPU更友好一些。
std::mutex g_m;
std::deque<std::string> que;
std::atomic<bool> endcond = false;
void queue(std::string msg)
{
std::lock_guard<mutex> _(g_m);
que.push_back(msg);
}
void print_from_queue()
{
while ( !endcond )
{
if ( que.size() )
{
std::lock_guard<mutex> _(g_m);
std::string msg = que.front();
que.pop_front();
OutputDebugStringA(msg.c_str());
}
}
}
int debugf( const char *format,... )
{
std::vector<char> line(256);
va_list args;
va_start( args, format );
int len = vsprintf_s( &line[0], line.size(), format, args );
va_end( args );
queue( &line[0] );
return len;
}
int _tmain(int argc, _TCHAR* argv[])
{
auto thr = std::async( std::launch::async, print_from_queue );
debugf("message1");
debugf("message2");
...发布于 2013-01-26 11:40:46
对上述代码和C++异步函数的批评::p
std::异步的返回值是std::future类型的对象。std::期货的析构函数由std::异步创建,等待任务执行。所以当你这么做的时候
auto future = std::async(...或
auto dstring = std::async([]{它创建一个类型为std::OutputDebugStringN的对象,当您离开OutputDebugStringN的作用域时,它调用std::前途的析构函数,这个析构函数会阻塞直到任务被执行。
在我看来,这是C++的一个缺陷。这有点愚蠢(希望这不会冒犯任何人:p),它完全违背了异步的目的。为了得到大多数人期望的行为(显然,您是预期的),您必须保存一个std::未来对象的列表,然后花费精力(和处理时间)来确定销毁列表中单个std::未来对象的正确时间。这就是执行部分中问题1的答案。对于#2,我认为您不应该在每次调试消息的基础上为此目的使用std::异步。我认为它创造的问题比它解决的多。
我不知道有什么优雅的方法可以绕过这件事。也许其他人可以插话。
至于如何实现异步版本的OutputDebugString,我只需创建一个由字符串组成的生产者-消费者队列。已经有很多问题被问到了,你可以用谷歌( google )的生产者-消费者队列来了解细节。生产者是发出消息的主线程。使用者是一个线程(或多个线程),它从队列中提取元素并调用窗口的OutputDebugString。
编辑:如果我冒犯了任何异步爱好者,我想补充一下,std::异步对于并行计算非常有用,就像使用GPU一样。我怀疑它是为开发并行硬件而设计的。例如:
// merge sort
{
auto left = std::async(.....); // merge_sort left
auto right = std::async(.....); // merge_sort right
}
merge这样,在我们合并之前,必须对左和右进行排序。如果没有,则等待直到它们都被排序,但是它允许同时处理左和右的机会。
如果你做过CUDA或任何you编码,这应该很熟悉.
https://stackoverflow.com/questions/14536402
复制相似问题