Johan de Vries Johan de Vries - 1 month ago 23
C++ Question

boost::asio::io_service: return control to IO service's run while waiting for future

I have a method that gets called via a third party from IO service. My method is supposed to return a boolean. However, I need to post another task to the same IO service, and wait for it to complete before I know the result. How can I return control to the IO loop while I wait for the other task to finish?

(I can add multiple threads, but then there could be multiple calls to my methods, and you'd still end up with a deadlock)

Call graph before:

<thread> io_service third_party my_stuff
| | | |
|---run----->| | |
| |-->some_posted_method-->| |
| | |--callback-->|
| | |<--boolean---|
| |(next task) | |
| | | |


Call graph preferred:

<thread> io_service third_party my_stuff
| | | |
|---run----->| | |
| |-->some_posted_method-->| |
| | |--callback-->|
| |<----some_way_to_return_control-------|
| |(next task) | |
| |--------some_kind_of_resume---------->|
| | |<--boolean---|
| | | |

Answer

Like Tanner Sansbury mentioned, you can call poll_one from your event handler, and it will execute the available handlers.

Mind that you have to call poll_one, since poll is not guaranteed to return if new handlers keep being added. And since poll_one may not have a handler ready to execute yet, you may want to add a sleep to prevent busy waiting. My code ended up like this:

while( !syncDone ) {
    boost::system::error_code  ec;

    int handlersExecuted = ioService.poll_one(ec);
    if( ec ) {
        //Not sure what error there could be, log it
    }

    if( 0 == handlersExecuted ) {
        std::this_thread::sleep_for(
            std::chrono::milliseconds(10)
        );
    }
}