Difference between boost::fiber::yield and boost::fiber:sleep_for when using fibers with boost asio

  boost, boost-asio, boost-beast, boost-fiber, c++

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:

  1. 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();
     }
    
  1. 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!

Source: Windows Questions C++

LEAVE A COMMENT