Search code examples
c++boost-asioc++20coroutinec++-coroutine

Why Do We Need asio::co_spawn?


Usually when working with coroutines, I can think of the way they execute by dividing the coroutine to the part before the first co_await and the part that comes after it. The part before can usually execute directly on the stack of the calling thread whereas the part after it is scheduled for execution by some executor.

This means that if I have a coroutine, I can simply call it directly from a regular function (in a 'detached' manner).

However, in most examples of asio, a coroutine is invoked via asio::co_spawn.

Take for example this coroutine that communicate between server and client:

awaitable<void> server_to_client(proxy_state_ptr state)
{
    std::array<char, 1024> data;

    for (;;)
    {
      auto n = co_await state->server.async_read_some(buffer(data), use_awaitable);

      co_await async_write(state->client, buffer(data, n), use_awaitable);
    }    
}

The function that initiates the read-write sequence does so using asio::co_spawn (always in 'detached' mode). The same goes for the invocation of the coroutine that first accept the connection.

So why and when asio::co_spawn is necessary? When should it be used? What can happen if I invoke an asio coroutine directly without using co_spawn (let's say, from my main thread)?


Solution

  • I can simply call it directly from a regular function (in a 'detached' manner)

    Yes, but if you don't provide an executor, it never continues.

    asio::co_spawn is a simple way of tying an awaitable to an executor, and simple is what you want in an example.