Previously, co_spawn-ing the following coroutine:
awaitable<void> foo()
{
co_await dispatch(use_awaitable);
}
would result in a call to the completion handler from within co_spawn.
The asio::config class provides access to configuration variables that
are associated with an execution context. The class is intended for use
by asio internals, or by libraries or user-provided abstractions that
build on top of asio. These configuration variables will typically be
used to fine tune behaviour, such as enabling or disabling certain
optimisations.
When constructing an execution context, such as an io_context, the
caller may optionally pass a service_maker to install a concrete
configuration service into the context. For example:
asio::io_context ctx{asio::config_from_env{}};
The configuration variables' values are accessed by using the
asio::config class, passing a section, key and default value:
asio::config cfg{ctx};
bool enable_locking = cfg.get("scheduler", "locking", true);
The initial set of configuration variables recognised by the asio
internals correspond to the concurrency hint and its special values:
"scheduler" / "concurrency_hint" (int)
"scheduler" / "locking" (bool)
"reactor" / "registration_locking" (bool)
"reactor" / "io_locking" (bool)
A service_maker is an object that is passed to an execution context's
constructor, and allows services to be added at context construction
time. Additional constructor overloads have been added to io_context and
thread_pool that accept a service_maker. For example:
class my_service_maker : public execution_context::service_maker
{
public:
void make(execution_context& ctx) override
{
make_service<my_service>(ctx);
}
};
io_context ctx{my_service_maker{}};
The disposition concept describes types that can be used to test whether
an asynchronous operation completed without error. This includes
error_code and exception_ptr, but can be extended to user types via
specialisation of the disposition_traits class template.
Generic code that is intended to work in terms of dispositions should
not use asio::disposition_traits directly, but instead:
* Test whether a disposition holds no error by comparing against
asio::no_error (of type asio::no_error_t).
* Use asio::to_exception_ptr to convert a disposition to a
std::exception_ptr.
* Use asio::throw_exception to throw an exception that corresponds to
the disposition, after first testing the disposition against
asio::no_error.
The asio::use_future completion token and asio::awaitable<>-based
coroutines have been updated to work generically in terms of
dispositions.
The composed function creates an initiation function object from a stateful
implementation. It is similar to co_composed, but for regular function objects
rather than C++20 coroutines.
For example:
struct async_echo_implementation
{
tcp::socket& socket_;
boost::asio::mutable_buffer buffer_;
enum { starting, reading, writing } state_;
template <typename Self>
void operator()(Self& self,
boost::system::error_code error,
std::size_t n)
{
switch (state_)
{
case starting:
state_ = reading;
socket_.async_read_some(
buffer_, std::move(self));
break;
case reading:
if (error)
{
self.complete(error, 0);
}
else
{
state_ = writing;
boost::asio::async_write(socket_, buffer_,
boost::asio::transfer_exactly(n),
std::move(self));
}
break;
case writing:
self.complete(error, n);
break;
}
}
};
template <typename CompletionToken>
auto async_echo(tcp::socket& socket,
boost::asio::mutable_buffer buffer,
CompletionToken&& token)
{
return boost::asio::async_initiate<CompletionToken,
void(boost::system::error_code, std::size_t)>(
boost::asio::composed(
async_echo_implementation{socket, buffer,
async_echo_implementation::starting}, socket),
token, boost::system::error_code{}, 0);
}
The async_compose function has been changed to be a thin wrapper around
composed. However, unlike async_compose, composed allows arguments to be passed
to the stateful implementation when the operation is initiated.