boost::asio::io_service: return control to IO serv

2019-09-09 21:19发布

问题:

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---|
   |            |                        |             |

回答1:

"third_party" should call "my_stuff" asynchronously, specify a handler that will continue as soon as result is ready, and return control to io_service. "third_party" is a little bit worrying here as it's possible you cannot modify it or it's not desirable.

Another approach would be to use another io_service instance for "my_stuff": "my_stuff" interface would be synchronous but implementation would use io_service in the same or another thread to accomplish its task. Never tried this but I don't see any problem from what I know about Boost.Asio.



回答2:

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