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::flags::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 _buf literal suffix, defined in namespace asio::buffer_literals, may
be used to create const_buffer objects from string, binary integer, and
hexadecimal integer literals. These buffer literals may be arbitrarily
long. For example:
using namespace asio::buffer_literals;
asio::const_buffer b1 = "hello"_buf;
asio::const_buffer b2 = 0xdeadbeef_buf;
asio::const_buffer b3 = 0x01234567'89abcdef'01234567'89abcdef_buf;
asio::const_buffer b4 = 0b1010101011001100_buf;
The memory associated with a buffer literal is valid for the lifetime of
the program. This means that the buffer can be safely used with
asynchronous operations:
async_write(my_socket, "hello"_buf, my_handler);
This means that use_coro does not return a coro object, just like
use_awaitable does, i.e. it's an overhead that buys us type erasure.
Allocators can now be set for coro by including allocator_arg in the
coro signature.
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.
This adds experimental::channel and experimental::concurrent_channel.
Channels may be used to send completions as messages. For example:
// Create a channel with no buffer space.
channel<void(error_code, size_t)> ch(ctx);
// The call to try_send fails as there is no buffer
// space and no waiting receive operations.
bool ok = ch.try_send(asio::error::eof, 123);
assert(!ok);
// The async_send operation blocks until a receive
// operation consumes the message.
ch.async_send(asio::error::eof, 123,
[](error_code ec)
{
// ...
});
// The async_receive consumes the message. Both the
// async_send and async_receive operations complete
// immediately.
ch.async_receive(
[](error_code ec, size_t n)
{
// ...
});
* Added overload so member functions can provide an explicit executor.
* Added co_spawn for coro tasks.
* Added reference and overview documentation.
* Adopted awaitable cancellation model.
* Refactored implementation.
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)
{
// ...
});