c++boostboost-asioboost-thread

boost async_wait() will cause a new thread?


We have a method that needs to be called frequently to do some computations (about 20 times per second). It is a synchronized call. The caller needs to get the result as soon as possible. But that computation process takes longer than expected sometimes. We don't want to change anything else. We just want to add a kind of monitoring mechanism to flag the application the current computation is timeout when it goes over the expected time period.

We have two options right now:

Option 1:

create a monitoring thread in the class level and it will keep running during the entire life of the application. It will start monitor that computation method's performance whenever it is called. It will be reset when the call is returned:

   monitorThread.startMonitoring();
   doComputation();
   monitorThread.stopMonitoring();

When startMonitoring() is called, a working flag will be set to true and start time will be set to current time on that monitorThread. it will be able to know if the current condition is timeout or not when it wake up.

When stopMonitoring() is called, that working flag will be set to false and the monitorThread will not check the timeout.

Option 2:

use boost deadline_timer:

boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(handler);
doComputation();
timer.cancel();

I am not sure if the dateline_timer option will work for us:

  1. can I define the timer at class level and reuse it during the entire running session of the application?
  2. does that async_wait() call will result in a new thread in the background? if yes, is that possible to reuse that thread again and again?

EDIT:

1. If I use the following code within a method body, the handler will be called by the current thread and the doComputation() also runs in the same thread. In the case of doComputation() hang, how the handler is called?

boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(handler);
io_service.run(); // new added
doComputation();  // <<---- may hung sometime
timer.cancel();

In order to reuse the timer and minimize the number of thread. I should instantiate io_service at beginning, i.e. put boost::asio::deadline_timer timer(io_service); in the constructor. And also call io_service.run(); in a new dedicated thread (and let it die after the call)? or just call it in the init main thread because the io_service.run() will start a new thread anyway? In the place the timer is used, the following code piece is enough:

timer.cancel();
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(handler);
doComputation();  // <<---- may hung sometime
timer.cancel();

Am I right?


Solution

  • can I define the timer at class level and reuse it during the entire running session of the application?

    Yes, you can re-use the timer, i.e. call expires_from_now() and async_wait() again (but read the reference to understand their behavior!).

    does that async_wait() call will result in a new thread in the background? if yes, is that possible to reuse that thread again and again?

    No (but in any case that's an implementation detail). The handler will be invoked from within the thread running io_service::run().

    Following your EDIT:

    1. It's highly recommended to take a look at the Asio documentation. Note that io_service::run() is a blocking call - it blocks until all the completion handlers get invoked. You can think of it as a "message loop". Typically, one calls it from a dedicated thread. Alternatively, one can poll io_service manually, calling poll()/poll_one() in some other application-specific loop.

    2. io_service::run() returns when it has no more work, i.e. there are no pending asynchronous operations and no completion handlers to dispatch. In order to keep this "message loop" running for the whole lifespan of your module (so that you'd be able to issue async. operations whenever you want), you need to associate io_service::work object with the io_service.