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)
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.
When registering a signal, it is now possible to pass flags that specify
the behaviour associated with the signal. These flags are specified as
an enum type in a new class, signal_set_base, and are passed to the
underlying sigaction() call. For example:
asio::signal_set sigs(my_io_context);
sigs.add(SIGINT, asio::signal_set:🎏:restart);
Specifying flags other than flags::dont_care will fail unless
sigaction() is supported by the target operating system. Since signal
registration is global, conflicting flags (multiple registrations that
pass differing flags other than flags::dont_care) will also result in
an error.
The consign completion token adapter can be used to attach additional
values to a completion handler. This is typically used to keep at least
one copy of an object, such as a smart pointer, alive until the
completion handler is called.
For example:
auto timer1 = std::make_shared<boost::asio::steady_timer>(my_io_context);
timer1->expires_after(std::chrono::seconds(1));
timer1->async_wait(
boost::asio::consign(
[](boost::system::error_code ec)
{
// ...
},
timer1
)
);
auto timer2 = std::make_shared<boost::asio::steady_timer>(my_io_context);
timer2->expires_after(std::chrono::seconds(30));
std::future<void> f =
timer2->async_wait(
boost::asio::consign(
boost::asio::use_future,
timer2
)
);
This is no longer an experimental facility. The names deferred and
deferred_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
This is no longer an experimental facility. The names prepend and
prepend_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
This is no longer an experimental facility. The names append and
append_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
This is no longer an experimental facility. The names as_tuple and
as_tuple_t have been temporarily retained as deprecated entities under
the asio::experimental namespace, for backwards compatibility.
The mutable_registered_buffer and const_registered_buffer classes are
buffer sequence types that represented registered buffers. These buffers
are obtained by first performing a buffer registration:
auto my_registration =
asio::register_buffers(
my_execution_context,
my_buffer_sequence);
The registration object must be maintained for as long as the buffer
registration is required. The supplied buffer sequence represents the
memory location or locations that will be registered, and the caller
must ensure they remain valid for as long as they are registered. The
registration is automatically removed when the registration object is
destroyed. There can be at most one active registration per execution
context.
The registration object is a container of registered buffers. Buffers
may be obtained from it by iterating over the container, or via direct
index access:
asio::mutable_registered_buffer my_buffer
= my_registration[i];
The registered buffers may then be passed directly to operations:
asio::async_read(my_socket, my_buffer,
[](error_code ec, size_t n)
{
// ...
});
Buffer registration supports the io_uring backend when used with read
and write operations on descriptors, files, pipes, and sockets.
This change add supports for pipes on POSIX and Windows (when I/O
completion ports are available). For example, to create and use a
connected pair of pipe objects:
asio::readable_pipe read_end;
asio::writable_pipe write_end;
asio::connect_pipe(read_end, write_end);
write_end.async_write_some(my_write_buffer,
[](error_code e, size_t n)
{
// ...
});
read_end.async_read_some(my_read_buffer,
[](error_code e, size_t n)
{
// ...
});
This change adds support for stream-oriented and random-access files.
For example, to write to a newly created stream-oriented file:
asio::stream_file file(
my_io_context, "/path/to/file",
asio::stream_file::write_only
| asio::stream_file::create
| asio::stream_file::truncate);
file.async_write_some(my_buffer,
[](error_code e, size_t n)
{
// ...
});
or to read from a random-access file:
asio::random_access_file file(
my_io_context, "/path/to/file",
asio::random_access_file::read_only);
file.async_read_some_at(1234, my_buffer,
[](error_code e, size_t n)
{
// ...
});
This feature currently supports I/O completion ports on Windows, and
io_uring on Linux (define BOOST_ASIO_HAS_IO_URING to enable).
This change adds the concept:
* execution::sender
the traits:
* execution::sender_traits
and the tag type:
* execution::sender_base
It also adds the following traits that correspond to the concepts:
* execution::is_sender
This change adds the concepts:
* execution::receiver
* execution::receiver_of
and the trait:
* execution::is_nothrow_receiver_of
It also adds the following traits that correspond to the concepts:
* execution::is_receiver
* execution::is_receiver_of