|  | Home | Libraries | People | FAQ | More | 
          Support for C++20 Coroutines is provided via the awaitable
          class template, the use_awaitable
          completion token, and the co_spawn()
          function. These facilities allow programs to implement asynchronous logic
          in a synchronous manner, in conjunction with the co_await
          keyword, as shown in the following example:
        
boost::asio::co_spawn(executor, echo(std::move(socket)), boost::asio::detached);
// ...
boost::asio::awaitable<void> echo(tcp::socket socket)
{
  try
  {
    char data[1024];
    for (;;)
    {
      std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data), boost::asio::use_awaitable);
      co_await async_write(socket, boost::asio::buffer(data, n), boost::asio::use_awaitable);
    }
  }
  catch (std::exception& e)
  {
    std::printf("echo Exception: %s\n", e.what());
  }
}
          The first argument to co_spawn() is an executor
          that determines the context in which the coroutine is permitted to execute.
          For example, a server's per-client object may consist of multiple coroutines;
          they should all run on the same strand so that no explicit
          synchronisation is required.
        
          The second argument is an awaitable<R>,
          that is the result of the coroutine's entry point function, and in the
          above example is the result of the call to echo. (Alternatively,
          this argument can be a function object that returns the awaitable<R>.)
          The template parameter R is the type of return value produced
          by the coroutine. In the above example, the coroutine returns void.
        
          The third argument is a completion token, and this is used by co_spawn()
          to produce a completion handler with signature void(std::exception_ptr,
          R). This completion handler is invoked with the result of the coroutine
          once it has finished. In the above example we pass a completion token type,
          boost::asio::detached,
          which is used to explicitly ignore the result of an asynchronous operation.
        
          In this example the body of the coroutine is implemented in the echo
          function. When the use_awaitable completion token is passed
          to an asynchronous operation, the operation's initiating function returns
          an awaitable that may be used with the co_await
          keyword:
        
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data), boost::asio::use_awaitable);
Where an asynchronous operation's handler signature has the form:
void handler(boost::system::error_code ec, result_type result);
          the resulting type of the co_await expression is result_type.
          In the async_read_some example above, this is size_t.
          If the asynchronous operation fails, the error_code is converted
          into a system_error exception and thrown.
        
Where a handler signature has the form:
void handler(boost::system::error_code ec);
          the co_await expression produces a void result.
          As above, an error is passed back to the coroutine as a system_error
          exception.
        
          To perform explicit error handling, rather than the default exception-throwing
          behaviour, use the experimental::as_tuple
          or redirect_error
          completion token adapters.
        
          The experimental::as_tuple completion token adapter packages
          the completion handler arguments into a single tuple, which is then returned
          as the result of the awaited operation. For example:
        
boost::asio::awaitable<void> echo(tcp::socket socket)
{
  char data[1024];
  for (;;)
  {
    std::tuple<boost::system::error_code, std::size_t> result =
      co_await socket.async_read_some(boost::asio::buffer(data),
        boost::asio::experimental::as_tuple(boost::asio::use_awaitable));
    if (!std::get<0>(result))
    {
      // success
    }
    // ...
  }
}
The result can also be captured directly into a structured binding:
boost::asio::awaitable<void> echo(tcp::socket socket)
{
  char data[1024];
  for (;;)
  {
    auto [ec, n] = co_await socket.async_read_some(boost::asio::buffer(data),
        boost::asio::experimental::as_tuple(boost::asio::use_awaitable));
    if (!ec)
    {
      // success
    }
    // ...
  }
}
          Alternatively, the redirect_error completion token adapter
          may be used to capture the error into a supplied error_code
          variable:
        
boost::asio::awaitable<void> echo(tcp::socket socket)
{
  char data[1024];
  for (;;)
  {
    boost::system::error_code ec;
    std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data),
        boost::asio::redirect_error(boost::asio::use_awaitable, ec));
    if (!ec)
    {
      // success
    }
    // ...
  }
}
          All threads of execution created by co_spawn have a cancellation
          state that records the current state of any cancellation requests made
          to the coroutine. To access this state, use this_coro::cancellation_state
          as follows:
        
boost::asio::awaitable<void> my_coroutine()
{
  boost::asio::cancellation_state cs
    = co_await boost::asio::this_coro::cancellation_state;
  // ...
  if (cs.cancelled() != boost::asio::cancellation_type::none)
    // ...
}
          When first created by co_spawn, the thread of execution has
          a cancellation state that supports cancellation_type::terminal
          values only. To change the cancellation state, call this_coro::reset_cancellation_state.
        
          By default, continued execution of a cancelled coroutine will trigger an
          exception from any subsequent co_await of an awaitable<>
          object. This behaviour can be changed by using this_coro::throw_if_cancelled.
        
| ![[Note]](../../../../../doc/src/images/note.png) | Note | 
|---|---|
| This is an experimental feature. | 
          The logical operators || and && have
          been overloaded for awaitable<>, to allow coroutines
          to be trivially awaited in parallel.
        
          When awaited using &&, the co_await expression
          waits until both operations have completed successfully. As a "short-circuit"
          evaluation, if one operation fails with an exception, the other is immediately
          cancelled. For example:
        
std::tuple<std::size_t, std::size_t> results =
  co_await (
    async_read(socket, input_buffer, use_awaitable)
      && async_write(socket, output_buffer, use_awaitable)
  );
          Following completion of a && operation, the results
          of all operations are concatenated into a tuple. In the above example,
          the first size_t represents the non-exceptional component
          of the async_read result, and the second size_t
          is the result of the async_write.
        
          When awaited using ||, the co_await expression
          waits until either operation succeeds. As a "short-circuit" evaluation,
          if one operation succeeds without throwing an exception, the other is immediately
          cancelled. For example:
        
std::variant<std::size_t, std::monostate> results =
  co_await (
    async_read(socket, input_buffer, use_awaitable)
      || timer.async_wait(use_awaitable)
  );
          Following completion of a || operation, the result of the
          first operation to complete non-exceptionally is placed into a std::variant.
          The active index of the variant reflects which of the operations completed
          first. In the above example, index 0 corresponds to the async_read
          operation.
        
          These operators may be enabled by adding the #include:
        
#include <boost/asio/experimental/awaitable_operators.hpp>
          and then bringing the contents of the experimental::awaitable_operators
          namespace into scope:
        
using namespace boost::asio::experimental::awaitable_operators;
co_spawn, detached, redirect_error, awaitable, use_awaitable_t, use_awaitable, this_coro::executor, experimental::coro, Coroutines examples, Resumable C++20 Coroutines, Stackful Coroutines, Stackless Coroutines.