C ++ async OutputDebugString

With the new std :: async in C ++ 11, I thought I could try to implement an asynchronous version of OutputDebugString to free me from some of the performance cuts that result from my usual heavy printing of every little thing through the normal OutputDebugString function.

So here is my original implementation of OutputDebugString (which works):

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");
    }
}

      

and following my very unsuccessful attempt in the async version (which doesn't work):

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");
        }
    }); 
}

      

And since the above doesn't work, I'm now at the point where I'm starting to think that calling OutputDebugStringN asynchronously might be better than trying to start asynchronous work inside the function itself like so (which works, but cumbersome):

auto dstring = std::async([]{ OutputDebugStringN("[NovelScript::ParseTokens] searched bookmark: \"%s\" does not exist\n", bookmark.c_str());} );

      

So here are the two questions I would like to ask:

  • How do I go about implementing the async version of OutputDebugString?
  • Should I even try to implement an asynchronous version of OutputDebugString?

Criticism on the above code and any other comments are also welcome.

+3


source to share


3 answers


I think you should have a queue for your messages, not for starting a thread with every call to your function, so that your messages will be output cleanly and in the correct order.

So your function eg. OutputDebugStringN(const char *format, ... )

will create a message line and then run a line from which a separate fingerprint stream will be read. This thread will call OutputDebugString

.



The example here is not complete, however error handling and print_from_queue should not be changed in order to run until some completion condition and be slightly more CPU friendly.

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");
...

      

+6


source


criticism of the above code and async function C ++ :: p

The return value of std :: async is an object of type std :: future. The destructor of std :: future created by std :: async waits until the task is completed. So when you do:

auto future = std::async(...

      

or

auto dstring = std::async([]{

      

it creates an object of type std :: future, and when you leave the scope of OutputDebugStringN, it calls the destructor of the std :: future, which blocks until the task is complete.

In my opinion this is a flaw with C ++. It's somewhat idiotic (hopefully it doesn't hurt anyone: p) and it completely defeats the goal of asynchronous. To get the behavior that most people expect (you probably expected this), you must keep a list of std :: future objects and then spend the time (and processing time) in the correct time to destroy individual std :: future objects in your list. This is the answer to question # 1 in the OP. For # 2, I think you shouldn't be using std :: async for this purpose based on the debug message. I think this creates more problems than it solves.



I don't know there is an elegant way around. Maybe someone else can call back.

As much as I would like to implement an asynchronous version of OutputDebugString, I would just create a string producer queue. Several questions have been asked in this question and you can get information about the google consumer producer queue. The producer is your main thread that emits the message. A consumer is a thread (or multiple threads) that allocates items from the queue and calls Window OutputDebugString.

EDIT: In case I have offended any asynchronous enthusiasts, I would like to add that std :: async is useful for parallel computing, similar to using a GPU. I suspect it is intended to use parallel hardware. For example:

      // merge sort
      {
           auto left =  std::async(.....);  // merge_sort left
           auto right =  std::async(.....);  // merge_sort right
      }

      merge

      

thus, both left and right must be sorted before being merged. if not, wait for both of them to be sorted, but this will make it possible to process both left and right in parallel.

it should look pretty good if you've done CUDA or any GPGPU encoding ...

+2


source


In my opinion, debugging should be synchronous, not asynchronous. Would you appreciate if the debugger gives you a few seconds after it appears? Would you appreciate a log file having stale data about the status of your program after your program crashed (since you created the asnyc file)?

Anyway, you went ahead and made the debug output as asynchronous. What purpose does it solve, other than just throwing data into the debug window, you know that this is not the last, it does not reflect your actions / actions of a user or a program, these are all outdated ! You absolutely cannot rely on this.

+2


source







All Articles