...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Support for the Coroutines TS 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, [socket = std::move(socket)]() mutable { return 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 a nullary function object that returns a boost::asio::awaitable<R>
,
where 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.
co_spawn, detached, redirect_error, awaitable, use_awaitable_t, use_awaitable, this_coro::executor, Coroutines TS examples, Stackful Coroutines, Stackless Coroutines.