I was experimenting with boost asio with fibers and found that boost::this_fiber::yield()
and boost::this_fiber::sleep_for(x)
seem to behave differently when using the round robin asio scheduler provided in fibers examples.
The setup is that we have one thread create two fibers which loop indefinitely:
- Fiber 1 uses async read with a beast websocket.
while (true) { beast::flat_buffer buffer; boost::system::error_code ec; ws.async_read(buffer, boost::fibers::asio::yield[ec]); LOG(INFO) << beast::make_printable(buffer.data()); boost::this_fiber::yield(); }
- Fiber 2 just loops and yields.
while (true) { boost::this_fiber::yield(); }
With this setup, no websocket reads actually happen as we never reach the logging statement right after the async_read
. However if we switch Fiber 2 to be
while (true) {
boost::this_fiber::sleep_for(std::chrono::milliseconds(10));
}
We now are able to print out the websocket reads. Curiously, if we reduce the sleep_for time to a low number like std::chrono::nanoseconds(1)
, the reads no longer happen.
Why does this behavior occur? Is this a subtlety of the round robin asio scheduler? My hypothesis is that somehow Fiber 2 with boost::this_fiber::yield()
will prevent io_context from running any completion handlers, but I'm pretty unsure.
Thanks!
EDIT:
A self contained example with asio async timers can be found here which exhibits the same behavior.