By default, awaitable<>-based coroutines now throw an exception if they
have been previously cancelled, and then try to perform a co_await
against another awaitable<>.
To disable this behaviour for the current awaitable<>-based "thread",
perform:
co_await boost::asio::this_coro::throw_if_error(false);
It is then the responsibility of the coroutine implementation to ensure
that it checks the cancellation state of the coroutine manually, by
doing something like:
auto cs = boost::asio::this_coro::cancellation_state;
// ...
if (cs.cancelled() != cancellation_type::none)
{
// ... handle cancellation ...
}
The logical operators || and && have been overloaded for awaitable<>, to
allow coroutines to be trivially awaited in parallel.
When awaited using &&, the 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)
);
When awaited using ||, the await expression waits until either operation
succceeds. 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)
);
The operators may be enabled by adding the #include:
#include <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;