2
0
mirror of https://github.com/boostorg/asio.git synced 2026-01-25 05:52:09 +00:00

Merge asio 1.22.2 from 'develop'.

This commit is contained in:
Christopher Kohlhoff
2022-04-07 00:15:44 +10:00
45 changed files with 1864 additions and 303 deletions

View File

@@ -7,7 +7,32 @@
[section:history Revision History]
[heading Asio 1.22.1 / Boost 1.79 beta]
[heading Asio 1.22.2 / Boost 1.79]
* On Windows, changed the file support to open files using the same sharing mode
as `fopen()`.
* On Linux, fixed the UNIX domain sockets implementation to correctly handle
`EAGAIN` as an indication of an in-progress connect operation.
* Fixed `experimental::basic_channel::reset()` and
`experimental::basic_concurrent_channel::reset()` so that they work correctly
for an unclosed channel.
* Fixed potential undefined behaviour in the `experimental::promise` operations
`race()` and `all()`.
* Changed the `co_spawn` implementation to explicitly dispatch cancellation
signals through the specified executor, if the the completion handler has an
associated executor of its own.
* Added more detailed reference documentation to `make_strand()`,
`make_work_guard()`, `ip::address_v4`, `ip::address_v6`,
`experimental::basic_channel`, and `experimental::basic_concurrent_channel`.
* Re-arranged and extended the Overview documentation to cover files, pipes,
`async_compose`, `experimental::deferred`, `experimental::parallel_group`,
`experimental::promise`, channels, and completion token adapters.
* Reverted the `io_context` reference documentation to use `executor_work_guard`
when preventing the `io_context` from running out of work.
* Removed references to `deadline_timer` from the Overview documentation.
* Added reference documentation cross-references to asynchronous model elements.
[heading Asio 1.22.1]
* Added `bind_allocator`, to simplify associating a custom allocator with a
completion token or handler.
@@ -1550,8 +1575,8 @@
support for returning a C++11 `std::future` from an asynchronous
operation's initiating function. For example:
`future<size_t> = my_socket.async_read_some(my_buffer, asio::use_future);`.
For further information, see [link boost_asio.overview.cpp2011.futures C++
2011 Support - Futures].
For further information, see [link boost_asio.overview.composition.futures
Futures].
* Promoted the stackless coroutine class and macros to be part of Asio's
documented interface, rather than part of the HTTP server 4 example.
For further information, see [link boost_asio.overview.composition.coroutine

View File

@@ -35,16 +35,25 @@
* [link boost_asio.overview.composition Composition and Completion Tokens]
* [link boost_asio.overview.composition.coroutine Stackless Coroutines]
* [link boost_asio.overview.composition.spawn Stackful Coroutines]
* [link boost_asio.overview.composition.futures Futures]
* [link boost_asio.overview.composition.cpp20_coroutines C++20 Coroutines Support]
* [link boost_asio.overview.composition.coro Resumable C++20 Coroutines (experimental)]
* [link boost_asio.overview.composition.deferred Deferred Operations (experimental)]
* [link boost_asio.overview.composition.promises Promises (experimental)]
* [link boost_asio.overview.composition.parallel_group Co-ordinating Parallel Operations (experimental)]
* [link boost_asio.overview.composition.compose Compositions as Asynchronous Operations]
* [link boost_asio.overview.composition.token_adapters Completion Token Adapters]
* [link boost_asio.overview.networking Networking]
* [link boost_asio.overview.networking.protocols TCP, UDP and ICMP]
* [link boost_asio.overview.networking.other_protocols Support for Other Protocols]
* [link boost_asio.overview.networking.iostreams Socket Iostreams]
* [link boost_asio.overview.networking.bsd_sockets The BSD Socket API and Boost.Asio]
* [link boost_asio.overview.timers Timers]
* [link boost_asio.overview.files Files]
* [link boost_asio.overview.pipes Pipes]
* [link boost_asio.overview.serial_ports Serial Ports]
* [link boost_asio.overview.signals Signal Handling]
* [link boost_asio.overview.channels Channels (experimental)]
* [link boost_asio.overview.posix POSIX-Specific Functionality]
* [link boost_asio.overview.posix.local UNIX Domain Sockets]
* [link boost_asio.overview.posix.stream_descriptor Stream-Oriented File Descriptors]
@@ -62,7 +71,6 @@
* [link boost_asio.overview.cpp2011.atomic Atomics]
* [link boost_asio.overview.cpp2011.shared_ptr Shared Pointers]
* [link boost_asio.overview.cpp2011.chrono Chrono]
* [link boost_asio.overview.cpp2011.futures Futures]
* [link boost_asio.overview.implementation Platform-Specific Implementation Notes]
[include overview/rationale.qbk]
@@ -101,13 +109,25 @@
* [link boost_asio.overview.composition.coroutine Stackless Coroutines]
* [link boost_asio.overview.composition.spawn Stackful Coroutines]
* [link boost_asio.overview.composition.futures Futures]
* [link boost_asio.overview.composition.cpp20_coroutines C++20 Coroutines Support]
* [link boost_asio.overview.composition.coro Resumable C++20 Coroutines (experimental)]
* [link boost_asio.overview.composition.deferred Deferred Operations (experimental)]
* [link boost_asio.overview.composition.promises Promises (experimental)]
* [link boost_asio.overview.composition.parallel_group Co-ordinating Parallel Operations (experimental)]
* [link boost_asio.overview.composition.compose Compositions as Asynchronous Operations]
* [link boost_asio.overview.composition.token_adapters Completion Token Adapters]
[include overview/coroutine.qbk]
[include overview/spawn.qbk]
[include overview/futures.qbk]
[include overview/cpp20_coroutines.qbk]
[include overview/coro.qbk]
[include overview/deferred.qbk]
[include overview/promises.qbk]
[include overview/parallel_group.qbk]
[include overview/compose.qbk]
[include overview/token_adapters.qbk]
[endsect]
@@ -126,8 +146,11 @@
[endsect]
[include overview/timers.qbk]
[include overview/files.qbk]
[include overview/pipes.qbk]
[include overview/serial_ports.qbk]
[include overview/signals.qbk]
[include overview/channels.qbk]
[include overview/posix.qbk]
[include overview/windows.qbk]
[include overview/ssl.qbk]

56
doc/overview/channels.qbk Normal file
View File

@@ -0,0 +1,56 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:channels Channels]
[note This is an experimental feature.]
The templates
[link boost_asio.reference.experimental__basic_channel experimental::basic_channel]
and [link boost_asio.reference.experimental__basic_concurrent_channel
experimental::basic_concurrent_channel], with aliases `experimental::channel`
and `experimental::concurrent_channel`, may be used to send messages between
different parts of the same application. A ['message] is defined as a
collection of arguments to be passed to a completion handler, and the set of
messages supported by a channel is specified by its template parameters.
Messages may be sent and received using asynchronous or non-blocking
synchronous operations.
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(boost::asio::error::eof, 123);
assert(!ok);
// The async_send operation is outstanding until
// a receive operation consumes the message.
ch.async_send(boost::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)
{
// ...
});
[heading See Also]
[link boost_asio.reference.experimental__basic_channel experimental::basic_channel],
[link boost_asio.reference.experimental__basic_concurrent_channel experimental::basic_concurrent_channel],
[link boost_asio.examples.cpp20_examples.channels Channels examples (C++20)].
[endsect]

101
doc/overview/compose.qbk Normal file
View File

@@ -0,0 +1,101 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:compose Compositions as Asynchronous Operations]
Application developers may wish to package their own compositions as conforming
[link boost_asio.overview.model.async_ops asynchronous operations] within the [link
boost_asio.overview.model asynchronous model]. Doing so facilitates seamless
composition of these operations together with the operations already provided
by Boost.Asio.
While these operations may be written from scratch to conform with the [link
boost_asio.reference.asynchronous_operations requirements on asynchronous
operations], Boost.Asio includes the [link boost_asio.reference.async_compose
`async_compose`] function to simplify this process. The `async_compose`
implementation automatically provides an intermediate completion handler that
correctly propagates the [link boost_asio.overview.model.associators associated
characteristics] and tracks outstanding work against the I/O executor and
completion executor.
The following example illustrates an asynchronous echo loop (i.e. read,
followed by write, and so on), expressed as a simple state machine.
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 = 0)
{
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;
}
}
};
This implementation is then used in an initiating function, which trivially
wraps `async_compose`:
template <typename CompletionToken>
auto async_echo(tcp::socket& socket,
boost::asio::mutable_buffer buffer,
CompletionToken&& token) ->
typename boost::asio::async_result<
typename std::decay<CompletionToken>::type,
void(boost::system::error_code, std::size_t)>::return_type
{
return boost::asio::async_compose<CompletionToken,
void(boost::system::error_code, std::size_t)>(
async_echo_implementation{socket, buffer,
async_echo_implementation::starting},
token, socket);
}
Here, `async_compose` is first passed the function object that contains the
implementation of the composed asynchronous operation. The first argument to
the function object is a non-const reference to the enclosing intermediate
completion handler. The remaining arguments are any arguments that originate
from the completion handlers of any asynchronous operations performed by the
implementation.
The `async_compose` function is also passed the completion token, and zero or
more I/O objects or I/O executors for which outstanding work must be
maintained.
[heading See Also]
[link boost_asio.reference.async_compose async_compose],
[link boost_asio.examples.cpp11_examples.operations Operations examples (C++11)],
[link boost_asio.examples.cpp14_examples.operations Operations examples (C++14)].
[endsect]

View File

@@ -22,8 +22,6 @@
[link boost_asio.overview.cpp2011.chrono Chrono]
[link boost_asio.overview.cpp2011.futures Futures]
[section:move_objects Movable I/O Objects]
@@ -214,37 +212,4 @@ class template may be used with either.
[endsect]
[section:futures Futures]
The `boost::asio::use_future` special value provides first-class support for returning a
C++11 `std::future` from an asynchronous operation's initiating function.
To use `boost::asio::use_future`, pass it to an asynchronous operation instead of
a normal completion handler. For example:
std::future<std::size_t> length =
my_socket.async_read_some(my_buffer, boost::asio::use_future);
Where a handler signature has the form:
void handler(boost::system::error_code ec, result_type result);
the initiating function returns a `std::future` templated on `result_type`.
In the above example, this is `std::size_t`. If the asynchronous operation
fails, the `error_code` is converted into a `system_error` exception and
passed back to the caller through the future.
Where a handler signature has the form:
void handler(boost::system::error_code ec);
the initiating function returns `std::future<void>`. As above, an error
is passed back in the future as a `system_error` exception.
[link boost_asio.reference.use_future use_future],
[link boost_asio.reference.use_future_t use_future_t],
[link boost_asio.examples.cpp11_examples.futures Futures example (C++11)].
[endsect]
[endsect]

56
doc/overview/deferred.qbk Normal file
View File

@@ -0,0 +1,56 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:deferred Deferred Operations]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__deferred `experimental::deferred`],
completion token takes a call to an asynchronous operation's initiating
function and turns it into a function object that accepts a completion token.
For example:
auto deferred_op =
timer.async_wait(
boost::asio::experimental::deferred);
...
std::move(deferred_op)(
[](boost::system::error_code ec){ ... });
or:
auto deferred_op =
timer.async_wait(
boost::asio::experimental::deferred);
...
std::future<void> =
std::move(deferred_op)(
boost::asio::use_future);
The deferred token also supports chaining, to create simple compositions:
auto deferred_op =
timer.async_wait(
boost::asio::experimental::deferred(
[&](boost::system::error_code ec)
{
timer.expires_after(
std::chrono::seconds(1));
return timer.async_wait(
boost::asio::experimental::deferred);
});
...
std::future<void> = std::move(deferred_op)(boost::asio::use_future);
[heading See Also]
[link boost_asio.reference.experimental__deferred experimental::deferred],
[link boost_asio.reference.experimental__deferred_t experimental::deferred_t],
[link boost_asio.examples.cpp14_examples.deferred Deferred examples (C++14)].
[endsect]

49
doc/overview/files.qbk Normal file
View File

@@ -0,0 +1,49 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:files Files]
[note This feature requires I/O completion ports on Windows, and io_uring on
Linux (define `BOOST_ASIO_HAS_IO_URING` to enable).]
Boost.Asio provides support for manipulating stream-oriented and random-access files.
For example, to write to a newly created stream-oriented file:
boost::asio::stream_file file(
my_io_context, "/path/to/file",
boost::asio::stream_file::write_only
| boost::asio::stream_file::create
| boost::asio::stream_file::truncate);
file.async_write_some(my_buffer,
[](error_code e, size_t n)
{
// ...
});
or to read from a random-access file:
boost::asio::random_access_file file(
my_io_context, "/path/to/file",
boost::asio::random_access_file::read_only);
file.async_read_some_at(1234, my_buffer,
[](error_code e, size_t n)
{
// ...
});
[heading See Also]
[link boost_asio.reference.basic_file basic_file],
[link boost_asio.reference.basic_random_access_file basic_random_access_file],
[link boost_asio.reference.basic_stream_file basic_stream_file],
[link boost_asio.reference.file_base file_base],
[link boost_asio.reference.random_access_file random_access_file],
[link boost_asio.reference.stream_file stream_file].
[endsect]

41
doc/overview/futures.qbk Normal file
View File

@@ -0,0 +1,41 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:futures Futures]
The `boost::asio::use_future` completion token provides first-class support for
returning a `std::future` from an asynchronous operation's initiating function.
To use `boost::asio::use_future`, pass it to an asynchronous operation instead of
a completion handler. For example:
std::future<std::size_t> length =
my_socket.async_read_some(my_buffer, boost::asio::use_future);
Where a completion signature has the form:
void handler(boost::system::error_code ec, result_type result);
the initiating function returns a `std::future` templated on `result_type`.
In the above example, this is `std::size_t`. If the asynchronous operation
fails, the `error_code` is converted into a `system_error` exception and
passed back to the caller through the future.
Where a completion signature has the form:
void handler(boost::system::error_code ec);
the initiating function returns `std::future<void>`. As above, an error
is passed back in the future as a `system_error` exception.
[heading See Also]
[link boost_asio.reference.use_future use_future],
[link boost_asio.reference.use_future_t use_future_t],
[link boost_asio.examples.cpp11_examples.futures Futures example (C++11)].
[endsect]

View File

@@ -25,7 +25,7 @@ facilities, such as:
* Completion tokens that facilitate different composition mechanisms, such as
[link boost_asio.overview.composition.cpp20_coroutines C++ coroutines], [link
boost_asio.overview.composition.spawn stackful coroutines], [link
boost_asio.overview.cpp2011.futures futures], and [link
boost_asio.overview.composition.futures futures], and [link
boost_asio.reference.experimental__deferred deferred operations].
* High level support for C++ coroutines that combines support executors and

View File

@@ -0,0 +1,65 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:parallel_group Co-ordinating Parallel Operations]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__make_parallel_group
`experimental::make_parallel_group`] function may be used to launch work that
is performed in parallel, and wait for one or all of the operations to
complete. A `parallel_group` implements automatic cancellation of incomplete
operations. For example:
experimental::make_parallel_group(
[&](auto token)
{
return stream.async_read_some(boost::asio::buffer(data), token);
},
[&](auto token)
{
return timer.async_wait(token);
}
).async_wait(
experimental::wait_for_one(),
[](
std::array<std::size_t, 2> completion_order,
boost::system::error_code ec1, std::size_t n1,
boost::system::error_code ec2
)
{
// ...
}
);
The conditions for completion of the group may be specified using one of the
four provided function objects [link boost_asio.reference.experimental__wait_for_all
`wait_for_all`], [link boost_asio.reference.experimental__wait_for_one
`wait_for_one`], [link boost_asio.reference.experimental__wait_for_one_success
`wait_for_one_success`], [link boost_asio.reference.experimental__wait_for_one_error
`wait_for_one_error`], or with a custom function.
The `parallel_group` facility can also be combined with [link
boost_asio.reference.experimental__deferred `experimental::deferred`] as follows:
experimental::make_parallel_group(
stream.async_read_some(boost::asio::buffer(data), experimental::deferred),
timer.async_wait(experimental::deferred)
).async_wait(
// ...
);
Note: for maximum flexibility, `parallel_group` does not propagate the
executor automatically to the operations within the group.
[heading See Also]
[link boost_asio.reference.experimental__make_parallel_group experimental::make_parallel_group],
[link boost_asio.reference.experimental__parallel_group experimental::parallel_group],
[link boost_asio.examples.cpp14_examples.parallel_groups Parallel Groups examples (C++14)].
[endsect]

38
doc/overview/pipes.qbk Normal file
View File

@@ -0,0 +1,38 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:pipes Pipes]
Boost.Asio provides support for portable anonymous pipes on POSIX and Windows (when
I/O completion ports are available). For example, to create and use a
connected pair of pipe objects:
boost::asio::readable_pipe read_end(my_io_context);
boost::asio::writable_pipe write_end(my_io_context);
boost::asio::connect_pipe(read_end, write_end);
write_end.async_write_some(my_write_buffer,
[](boost::system::error_code e, size_t n)
{
// ...
});
read_end.async_read_some(my_read_buffer,
[](boost::system::error_code e, size_t n)
{
// ...
});
[heading See Also]
[link boost_asio.reference.basic_readable_pipe basic_readable_pipe],
[link boost_asio.reference.basic_writable_pipe basic_writable_pipe],
[link boost_asio.reference.connect_pipe connect_pipe],
[link boost_asio.reference.readable_pipe readable_pipe],
[link boost_asio.reference.writable_pipe writable_pipe].
[endsect]

79
doc/overview/promises.qbk Normal file
View File

@@ -0,0 +1,79 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:promises Promises]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__promise_lt__void_lp_Ts_ellipsis__rp__comma__Executor__gt_
`experimental::promise`] type and [link boost_asio.reference.experimental__use_promise
`experimental::use_promise`] completion token allow eager execution and
synchronisation of asynchronous operations. For example:
auto promise = async_read(
stream, boost::asio::buffer(my_buffer),
boost::asio::experimental::use_promise);
... do other stuff while the read is going on ...
promise.async_wait( // completion the operation
[](error_code ec, std::size_t bytes_read)
{
...
});
Promises can be safely disregarded if the result is no longer required.
Different operations can be combined to either wait for all to complete or for
one to complete (and cancel the rest). For example, to wait for one to
complete:
auto timeout_promise =
timer.async_wait(
boost::asio::experimental::use_promise);
auto read_promise = async_read(
stream, boost::asio::buffer(my_buffer),
boost::asio::experimental::use_promise);
auto promise =
boost::asio::experimental::promise<>::race(
timeout_promise, read_promise);
promise.async_wait(
[](std::variant<error_code, std::tuple<error_code, std::size_t>> v)
{
if (v.index() == 0) {} //timed out
else if (v.index() == 1) // completed in time
});
or to wait for all to complete:
auto write_promise = async_write(
stream, boost::asio::buffer(my_write_buffer),
boost::asio::experimental::use_promise);
auto read_promise = async_read(
stream, boost::asio::buffer(my_buffer),
boost::asio::experimental::use_promise);
auto promise =
boost::asio::experimental::promise<>::all(
write_promise, read_promise);
promise.async_wait(
[](std::tuple<error_code, std::size_t> write_result,
std::tuple<error_code, std::size_t> read_result)
{
// ...
});
[heading See Also]
[link boost_asio.reference.experimental__promise_lt__void_lp_Ts_ellipsis__rp__comma__Executor__gt_ promise],
[link boost_asio.reference.experimental__use_promise use_promise].
[endsect]

View File

@@ -16,8 +16,8 @@ relative time one may write:
io_context i;
...
deadline_timer t(i);
t.expires_from_now(boost::posix_time::seconds(5));
steady_timer t(i);
t.expires_after(chrono::seconds(5));
t.wait();
More commonly, a program will perform an asynchronous wait operation on a
@@ -27,26 +27,27 @@ timer:
...
io_context i;
...
deadline_timer t(i);
t.expires_from_now(boost::posix_time::milliseconds(400));
steady_timer t(i);
t.expires_after(chrono::milliseconds(400));
t.async_wait(handler);
...
i.run();
The deadline associated with a timer may also be obtained as a relative time:
The deadline associated with a timer may also be obtained as an absolute time:
boost::posix_time::time_duration time_until_expiry
= t.expires_from_now();
steady_timer::time_point time_of_expiry = t.expiry();
or as an absolute time to allow composition of timers:
which allows composition of timers:
deadline_timer t2(i);
t2.expires_at(t.expires_at() + boost::posix_time::seconds(30));
steady_timer t2(i);
t2.expires_at(t.expiry() + chrono::seconds(30));
[heading See Also]
[link boost_asio.reference.basic_deadline_timer basic_deadline_timer],
[link boost_asio.reference.deadline_timer deadline_timer],
[link boost_asio.reference.basic_waitable_timer basic_waitable_timer],
[link boost_asio.reference.steady_timer steady_timer],
[link boost_asio.reference.system_timer system_timer],
[link boost_asio.reference.high_resolution_timer high_resolution_timer],
[link boost_asio.tutorial.tuttimer1 timer tutorials].
[endsect]

View File

@@ -0,0 +1,216 @@
[/
/ Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:token_adapters Completion Token Adapters]
A ['completion token adapter] is a utility that can be generically applied to a
[link boost_asio.overview.model.completion_tokens completion token], to produce a new
completion token with modified behaviour. Common uses of completion token
adapters include:
* Automatically wrapping the completion handler to add [link
boost_asio.overview.model.associators associated characteristics].
* Transforming the completion signature and arguments passed to the completion
handler.
Boost.Asio includes a number of completion token adapters as described below.
[heading bind_executor, bind_allocator, and bind_cancellation_slot]
The [link boost_asio.reference.bind_executor `bind_executor`] function adapts a
completion token to imbue the completion handler with an [link
boost_asio.overview.model.executors associated executor].
This example shows the `bind_executor` adapter applied to a lambda, to specify
that the handler should execute in the specified strand. The arguments to the
completion handler are passed through as-is.
my_socket.async_read_some(my_buffer,
boost::asio::bind_executor(my_strand,
[](boost::system::error_code error, std::size_t bytes_transferred)
{
// ...
}));
When applied to completion tokens that cause the initiating function to produce
a result, such as [link boost_asio.reference.use_awaitable `use_awaitable`], the
result is returned unmodified.
boost::asio::awaitable<void> my_coroutine()
{
// ...
std::size_t bytes_transferred =
co_await my_socket.async_read_some(my_buffer,
boost::asio::bind_executor(my_strand, boost::asio::use_awaitable));
// ...
}
The [link boost_asio.reference.bind_allocator `bind_allocator`] and [link
boost_asio.reference.bind_cancellation_slot `bind_cancellation_slot`] adapters work
similarly, to imbue the completion handler with an [link
boost_asio.overview.model.allocators associated allocator] or [link
boost_asio.overview.model.cancellation associated cancellation slot] respectively.
[heading redirect_error]
The [link boost_asio.reference.redirect_error `redirect_error`] function adapts a
completion token to capture the `error_code` produced by an operation into a
specified variable. In doing so, it modifies the completion signature to remove
the initial `error_code` parameter.
This example shows the `redirect_error` adapter applied to a lambda, to specify
that the error should be captured into `my_error`. The `error_code` is no
longer passed to the completion handler, but the remaining arguments are passed
through as-is.
boost::system::error_code my_error; // N.B. must be valid until operation completes
// ...
my_socket.async_read_some(my_buffer,
boost::asio::redirect_error(
[](std::size_t bytes_transferred)
{
// ...
}, my_error));
When applied to completion tokens that cause the initiating function to produce
a result, such as [link boost_asio.reference.use_awaitable `use_awaitable`], the
result is returned unmodified. However, if the operation fails, the `co_await`
expression will no longer throw an exception on resumption.
boost::asio::awaitable<void> my_coroutine()
{
// ...
boost::system::error_code my_error;
std::size_t bytes_transferred =
co_await my_socket.async_read_some(my_buffer,
boost::asio::redirect_error(boost::asio::use_awaitable, my_error));
// ...
}
[heading as_tuple]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__as_tuple `experimental::as_tuple`]
adapter can be used to specify that the completion handler arguments should be
combined into a single tuple argument.
For example, the `as_tuple` adapter may be used in conjunction with [link
boost_asio.reference.use_awaitable `use_awaitable`] and structured bindings as
follows:
auto [e, n] =
co_await my_socket.async_read_some(my_buffer,
boost::asio::experimental::as_tuple(boost::asio::use_awaitable));
This adapter may also be used as a default completion token:
using default_token = boost::asio::experimental::as_tuple_t<boost::asio::use_awaitable_t<>>;
using tcp_socket = default_token::as_default_on_t<tcp::socket>;
// ...
boost::asio::awaitable<void> do_read(tcp_socket my_socket)
{
// ...
auto [e, n] = co_await my_socket.async_read_some(my_buffer);
// ...
}
[heading as_single]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__as_single `experimental::as_single`]
adapter can be used to specify that the completion handler
arguments should be combined into a single argument. For completion signatures
with a single parameter, the argument is passed through as-is. For signatures
with two or more parameters, the arguments are combined into a tuple.
For example, when applied to a timer wait operation, the single `error_code`
argument is passed directly to the completion handler:
my_timer.async_wait(
boost::asio::experimental::as_single(
[](boost::system::error_code error)
{
// ...
}));
When applied to a socket read operation, where the completion signature
specifies two parameters, the handler is passed the result as a tuple:
my_socket.async_read_some(my_buffer,
boost::asio::experimental::as_single,
[](std::tuple<boost::system::error_code, std::size_t> result)
{
// ...
}));
[heading append]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__append `experimental::append`]
completion token adapter can be used to pass additional completion handler
arguments at the end of the completion signature.
For example:
timer.async_wait(
boost::asio::experimental::append(
[](boost::system::error_code ec, int i)
{
// ...
},
42)
);
std::future<int> f = timer.async_wait(
boost::asio::experimental::append(
boost::asio::use_future,
42
)
);
[heading prepend]
[note This is an experimental feature.]
The [link boost_asio.reference.experimental__prepend `experimental::prepend`]
completion token adapter can be used to pass additional completion handler
arguments before the existing completion handler arguments.
For example:
timer.async_wait(
boost::asio::experimental::prepend(
[](int i, boost::system::error_code ec)
{
// ...
},
42)
);
std::future<std::tuple<int, boost::system::error_code>> f = timer.async_wait(
boost::asio::experimental::prepend(
boost::asio::use_future,
42
)
);
[heading See Also]
[link boost_asio.reference.bind_executor bind_executor],
[link boost_asio.reference.bind_allocator bind_allocator],
[link boost_asio.reference.bind_cancellation_slot bind_cancellation_slot],
[link boost_asio.reference.redirect_error redirect_error],
[link boost_asio.reference.experimental__as_tuple experimental::as_tuple],
[link boost_asio.reference.experimental__as_single experimental::as_single],
[link boost_asio.reference.experimental__append experimental::append],
[link boost_asio.reference.experimental__prepend experimental::prepend].
[endsect]

View File

@@ -30,13 +30,6 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_ALIAS_TEMPLATES`]
]
[
[`BOOST_ASIO_HAS_ALIGNED_NEW`]
[
Support for operator new with alignment argument.
]
[`BOOST_ASIO_DISABLE_ALIGNED_NEW`]
]
[
[`BOOST_ASIO_HAS_ALIGNOF`]
[
@@ -82,7 +75,7 @@ with Boost.Asio's needs.
[
[`BOOST_ASIO_HAS_BOOST_CONFIG`]
[
Boost.Config library is available.
]
[]
]
@@ -198,6 +191,13 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_DEV_POLL`]
]
[
[`BOOST_ASIO_HAS_ENUM_CLASS`]
[
Support enum classes on compilers known to allow them.
]
[`BOOST_ASIO_DISABLE_ENUM_CLASS`]
]
[
[`BOOST_ASIO_HAS_EPOLL`]
[
@@ -212,6 +212,13 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_EVENTFD`]
]
[
[`BOOST_ASIO_HAS_FILE`]
[
Files.
]
[`BOOST_ASIO_DISABLE_FILE`]
]
[
[`BOOST_ASIO_HAS_GETADDRINFO`]
[
@@ -233,6 +240,13 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_IOCP`]
]
[
[`BOOST_ASIO_HAS_IO_URING_AS_DEFAULT`]
[
Linux: io_uring is used instead of epoll.
]
[]
]
[
[`BOOST_ASIO_HAS_KQUEUE`]
[
@@ -268,6 +282,13 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_NOEXCEPT`]
]
[
[`BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE`]
[
Support noexcept on function types on compilers known to allow it.
]
[`BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE`]
]
[
[`BOOST_ASIO_HAS_NULLPTR`]
[
@@ -275,6 +296,13 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_NULLPTR`]
]
[
[`BOOST_ASIO_HAS_PIPE`]
[
Pipes.
]
[`BOOST_ASIO_DISABLE_PIPE`]
]
[
[`BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR`]
[
@@ -359,6 +387,13 @@ with Boost.Asio's needs.
]
[`BOOST_ASIO_DISABLE_STD_ADDRESSOF`]
]
[
[`BOOST_ASIO_HAS_STD_ALIGNED_ALLOC`]
[
Standard library support for aligned allocation.
]
[`BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC`]
]
[
[`BOOST_ASIO_HAS_STD_ALLOCATOR_ARG`]
[

File diff suppressed because it is too large Load Diff

View File

@@ -17,13 +17,13 @@ The tutorial programs in this first section introduce the fundamental concepts r
* [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously]
* [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
* [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler]
* [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
* [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler]
* [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
* [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs]
@@ -94,7 +94,8 @@ All programs that use asio need to have at least one I/O execution context, such
Next we declare an object of type boost::asio::steady\_timer. The core asio classes that provide I/O functionality (or as in this case timer functionality) always take a reference to an io\_context as their first constructor argument. The second argument to the constructor sets the timer to expire 5 seconds from now.
Next we declare an object of type boost::asio::steady\_timer. The core asio classes that provide I/O functionality (or as in this case timer functionality) always take an executor, or a reference to an execution context (such as
[link boost_asio.reference.io_context io_context]), as their first constructor argument. The second argument to the constructor sets the timer to expire 5 seconds from now.
@@ -166,7 +167,7 @@ Return to [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronou
[section:tuttimer2 Timer.2 - Using a timer asynchronously]
This tutorial program demonstrates how to use asio's asynchronous callback functionality by modifying the program from tutorial Timer.1 to perform an asynchronous wait on the timer.
This tutorial program demonstrates how to use asio's asynchronous functionality by modifying the program from tutorial Timer.1 to perform an asynchronous wait on the timer.
@@ -178,7 +179,7 @@ This tutorial program demonstrates how to use asio's asynchronous callback funct
Using asio's asynchronous functionality means having a callback function that will be called when an asynchronous operation completes. In this program we define a function called `print` to be called when the asynchronous wait finishes.
Using asio's asynchronous functionality means supplying a [link boost_asio.overview.model.completion_tokens completion token], which determines how the result will be delivered to a [*completion handler] when an [link boost_asio.overview.model.async_ops asynchronous operation] completes. In this program we define a function called `print` to be called when the asynchronous wait finishes.
@@ -195,7 +196,7 @@ Using asio's asynchronous functionality means having a callback function that wi
Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function to perform an asynchronous wait. When calling this function we pass the `print` callback handler that was defined above.
Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function to perform an asynchronous wait. When calling this function we pass the `print` function that was defined above.
``''''''`` t.async_wait(&print);
@@ -204,9 +205,9 @@ Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link
Finally, we must call the [link boost_asio.reference.io_context.run io_context::run()] member function on the io\_context object.
The asio library provides a guarantee that callback handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Therefore unless the [link boost_asio.reference.io_context.run io_context::run()] function is called the callback for the asynchronous wait completion will never be invoked.
The asio library provides a guarantee that completion handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Therefore unless the [link boost_asio.reference.io_context.run io_context::run()] function is called the completion handler for the asynchronous wait completion will never be invoked.
The [link boost_asio.reference.io_context.run io_context::run()] function will also continue to run while there is still "work" to do. In this example, the work is the asynchronous wait on the timer, so the call will not return until the timer has expired and the callback has completed.
The [link boost_asio.reference.io_context.run io_context::run()] function will also continue to run while there is still "work" to do. In this example, the work is the asynchronous wait on the timer, so the call will not return until the timer has expired and the completion handler has returned.
It is important to remember to give the io\_context some work to do before calling [link boost_asio.reference.io_context.run io_context::run()]. For example, if we had omitted the above call to [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()], the io\_context would not have had any work to do, and consequently [link boost_asio.reference.io_context.run io_context::run()] would have returned immediately.
@@ -224,7 +225,7 @@ Return to the [link boost_asio.tutorial tutorial index]
Previous: [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronously]
Next: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
Next: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler]
@@ -267,7 +268,7 @@ Return to [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchrono
[endsect]
[section:tuttimer3 Timer.3 - Binding arguments to a handler]
[section:tuttimer3 Timer.3 - Binding arguments to a completion handler]
In this tutorial we will modify the program from tutorial Timer.2 so that the timer fires once a second. This will show how to pass additional parameters to your handler function.
@@ -282,15 +283,18 @@ In this tutorial we will modify the program from tutorial Timer.2 so that the ti
To implement a repeating timer using asio you need to change the timer's expiry time in your callback function, and to then start a new asynchronous wait. Obviously this means that the callback function will need to be able to access the timer object. To this end we add two new parameters to the `print` function:
To implement a repeating timer using asio you need to change the timer's expiry time in your completion handler, and to then start a new asynchronous wait. Obviously this means that the completion handler will need to be able to access the timer object. To this end we add two new parameters to the `print` function:
* A pointer to a timer object.
* a pointer to a timer object; and
* A counter so that we can stop the program when the timer fires for the sixth time.
* a counter so that we can stop the program when the timer fires for the sixth time
at the end of the parameter list.
``''''''``void print(const boost::system::error_code& /*e*/,
``''''''`` boost::asio::steady_timer* t, int* count)
@@ -316,11 +320,11 @@ Next we move the expiry time for the timer along by one second from the previous
Then we start a new asynchronous wait on the timer. As you can see, the boost::bind() function is used to associate the extra parameters with your callback handler. The [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function expects a handler function (or function object) with the signature `void(const boost::system::error_code&)`. Binding the additional parameters converts your `print` function into a function object that matches the signature correctly.
Then we start a new asynchronous wait on the timer. As you can see, the boost::bind() function is used to associate the extra parameters with your completion handler. The [link boost_asio.reference.basic_waitable_timer.async_wait steady_timer::async_wait()] function expects a handler function (or function object) with the signature `void(const boost::system::error_code&)`. Binding the additional parameters converts your `print` function into a function object that matches the signature correctly.
See the [@http://www.boost.org/libs/bind/bind.html Boost.Bind documentation] for more information on how to use boost::bind().
In this example, the boost::asio::placeholders::error argument to boost::bind() is a named placeholder for the error object passed to the handler. When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In tutorial Timer.4 you will see that this placeholder may be elided if the parameter is not needed by the callback handler.
In this example, the boost::asio::placeholders::error argument to boost::bind() is a named placeholder for the error object passed to the handler. When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In tutorial Timer.4 you will see that this placeholder may be elided if the parameter is not needed by the completion handler.
``''''''`` t->async_wait(boost::bind(print,
@@ -370,7 +374,7 @@ Return to the [link boost_asio.tutorial tutorial index]
Previous: [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously]
Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler]
@@ -421,15 +425,15 @@ Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a
``''''''`` return 0;
``''''''``}
Return to [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
Return to [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler]
[endsect]
[endsect]
[section:tuttimer4 Timer.4 - Using a member function as a handler]
[section:tuttimer4 Timer.4 - Using a member function as a completion handler]
In this tutorial we will see how to use a class member function as a callback handler. The program should execute identically to the tutorial program from tutorial Timer.3.
In this tutorial we will see how to use a class member function as a completion handler. The program should execute identically to the tutorial program from tutorial Timer.3.
@@ -442,7 +446,7 @@ In this tutorial we will see how to use a class member function as a callback ha
Instead of defining a free function `print` as the callback handler, as we did in the earlier tutorial programs, we now define a class called `printer`.
Instead of defining a free function `print` as the completion handler, as we did in the earlier tutorial programs, we now define a class called `printer`.
@@ -462,7 +466,7 @@ The constructor of this class will take a reference to the io\_context object an
The boost::bind() function works just as well with class member functions as with free functions. Since all non-static class member functions have an implicit `this` parameter, we need to bind `this` to the function. As in tutorial Timer.3, boost::bind() converts our callback handler (now a member function) into a function object that can be invoked as though it has the signature `void(const boost::system::error_code&)`.
The boost::bind() function works just as well with class member functions as with free functions. Since all non-static class member functions have an implicit `this` parameter, we need to bind `this` to the function. As in tutorial Timer.3, boost::bind() converts our completion handler (now a member function) into a function object that can be invoked as though it has the signature `void(const boost::system::error_code&)`.
You will note that the boost::asio::placeholders::error placeholder is not specified here, as the `print` member function does not accept an error object as a parameter.
@@ -525,9 +529,9 @@ See the [link boost_asio.tutorial.tuttimer4.src full source listing]
Return to the [link boost_asio.tutorial tutorial index]
Previous: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
Previous: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a completion handler]
Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs]
@@ -591,18 +595,18 @@ Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in mu
``''''''`` return 0;
``''''''``}
Return to [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
Return to [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler]
[endsect]
[endsect]
[section:tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
[section:tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs]
This tutorial demonstrates the use of the
[link boost_asio.reference.strand strand] class template to synchronise callback handlers in a multithreaded program.
[link boost_asio.reference.strand strand] class template to synchronise completion handlers in a multithreaded program.
The previous four tutorials avoided the issue of handler synchronisation by calling the [link boost_asio.reference.io_context.run io_context::run()] function from one thread only. As you already know, the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Consequently, calling [link boost_asio.reference.io_context.run io_context::run()] from only one thread ensures that callback handlers cannot run concurrently.
The previous four tutorials avoided the issue of handler synchronisation by calling the [link boost_asio.reference.io_context.run io_context::run()] function from one thread only. As you already know, the asio library provides a guarantee that completion handlers will only be called from threads that are currently calling [link boost_asio.reference.io_context.run io_context::run()]. Consequently, calling [link boost_asio.reference.io_context.run io_context::run()] from only one thread ensures that completion handlers cannot run concurrently.
The single threaded approach is usually the best place to start when developing applications using asio. The downside is the limitations it places on programs, particularly servers, including:
@@ -655,7 +659,7 @@ The
When initiating the asynchronous operations, each callback handler is "bound" to an boost::asio::strand<boost::asio::io\_context::executor\_type> object. The boost::asio::bind\_executor() function returns a new handler that automatically dispatches its contained handler through the
When initiating the asynchronous operations, each completion handler is "bound" to an boost::asio::strand<boost::asio::io\_context::executor\_type> object. The boost::asio::bind\_executor() function returns a new handler that automatically dispatches its contained handler through the
[link boost_asio.reference.strand strand] object. By binding the handlers to the same
[link boost_asio.reference.strand strand], we are ensuring that they cannot execute concurrently.
@@ -738,7 +742,7 @@ See the [link boost_asio.tutorial.tuttimer5.src full source listing]
Return to the [link boost_asio.tutorial tutorial index]
Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a completion handler]
@@ -829,7 +833,7 @@ Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function
``''''''`` return 0;
``''''''``}
Return to [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
Return to [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs]
[endsect]

View File

@@ -340,6 +340,16 @@
<xsl:value-of select="@refid"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$refid = 'asynchronous_operation'">
<xsl:text>[link boost_asio.overview.model.async_ops </xsl:text>
<xsl:value-of select="."/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="$refid = 'completion_token'">
<xsl:text>[link boost_asio.overview.model.completion_tokens </xsl:text>
<xsl:value-of select="."/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="count(/doxygen/compounddef[@id=$refid]) &gt; 0">
<xsl:text>[link boost_asio.tutorial.</xsl:text>
<xsl:choose>

View File

@@ -424,9 +424,4 @@ A mailing list specifically for Boost.Asio may be found on
access is provided via [@http://dir.gmane.org/gmane.comp.lib.boost.asio.user
Gmane].
[heading Wiki]
Users are encouraged to share examples, tips and FAQs on the Boost.Asio wiki,
which is located at [@http://think-async.com/Asio/].
[endsect]

View File

@@ -30,8 +30,9 @@ boost::asio::io_context first thing in the main function.
Next we declare an object of type boost::asio::steady_timer. The core asio classes
that provide I/O functionality (or as in this case timer functionality) always
take a reference to an io_context as their first constructor argument. The
second argument to the constructor sets the timer to expire 5 seconds from now.
take an executor, or a reference to an execution context (such as
boost::asio::io_context), as their first constructor argument. The second argument to
the constructor sets the timer to expire 5 seconds from now.
\until boost::asio::steady_timer
@@ -66,41 +67,42 @@ Return to \ref tuttimer1
/**
\page tuttimer2 Timer.2 - Using a timer asynchronously
This tutorial program demonstrates how to use asio's asynchronous callback
functionality by modifying the program from tutorial Timer.1 to perform an
asynchronous wait on the timer.
This tutorial program demonstrates how to use asio's asynchronous functionality
by modifying the program from tutorial Timer.1 to perform an asynchronous wait
on the timer.
\dontinclude timer2/timer.cpp
\skip #include
\until asio.hpp
Using asio's asynchronous functionality means having a callback
function that will be called when an asynchronous operation completes. In this
program we define a function called <tt>print</tt> to be called when the
asynchronous wait finishes.
Using asio's asynchronous functionality means supplying a @ref completion_token,
which determines how the result will be delivered to a <em>completion
handler</em> when an @ref asynchronous_operation completes. In this program we
define a function called <tt>print</tt> to be called when the asynchronous wait
finishes.
\until boost::asio::steady_timer
Next, instead of doing a blocking wait as in tutorial Timer.1,
we call the boost::asio::steady_timer::async_wait() function to perform an
asynchronous wait. When calling this function we pass the <tt>print</tt>
callback handler that was defined above.
function that was defined above.
\skipline async_wait
Finally, we must call the boost::asio::io_context::run() member function
on the io_context object.
The asio library provides a guarantee that callback handlers will <b>only</b>
The asio library provides a guarantee that completion handlers will <b>only</b>
be called from threads that are currently calling boost::asio::io_context::run().
Therefore unless the boost::asio::io_context::run() function is called the callback for
the asynchronous wait completion will never be invoked.
Therefore unless the boost::asio::io_context::run() function is called the completion
handler for the asynchronous wait completion will never be invoked.
The boost::asio::io_context::run() function will also continue to run while there is
still "work" to do. In this example, the work is the asynchronous wait on the
timer, so the call will not return until the timer has expired and the
callback has completed.
completion handler has returned.
It is important to remember to give the io_context some work to do before
calling boost::asio::io_context::run(). For example, if we had omitted the above call
@@ -125,7 +127,7 @@ Return to \ref tuttimer2
*/
/**
\page tuttimer3 Timer.3 - Binding arguments to a handler
\page tuttimer3 Timer.3 - Binding arguments to a completion handler
In this tutorial we will modify the program from tutorial Timer.2 so that the
timer fires once a second. This will show how to pass additional parameters to
@@ -137,15 +139,17 @@ your handler function.
\until bind.hpp
To implement a repeating timer using asio you need to change
the timer's expiry time in your callback function, and to then start a new
asynchronous wait. Obviously this means that the callback function will need
the timer's expiry time in your completion handler, and to then start a new
asynchronous wait. Obviously this means that the completion handler will need
to be able to access the timer object. To this end we add two new parameters
to the <tt>print</tt> function:
\li A pointer to a timer object.
\li a pointer to a timer object; and
\li A counter so that we can stop the program when the timer fires for the
sixth time.
\li a counter so that we can stop the program when the timer fires for the
sixth time
at the end of the parameter list.
\until {
@@ -168,7 +172,7 @@ whole-second mark due to any delays in processing the handler.
Then we start a new asynchronous wait on the timer. As you can
see, the boost::bind() function is used to associate the extra parameters
with your callback handler. The boost::asio::steady_timer::async_wait() function
with your completion handler. The boost::asio::steady_timer::async_wait() function
expects a handler function (or function object) with the signature
<tt>void(const boost::system::error_code&)</tt>. Binding the additional parameters
converts your <tt>print</tt> function into a function object that matches the
@@ -182,7 +186,7 @@ named placeholder for the error object passed to the handler. When initiating
the asynchronous operation, and if using boost::bind(), you must specify only
the arguments that match the handler's parameter list. In tutorial Timer.4 you
will see that this placeholder may be elided if the parameter is not needed by
the callback handler.
the completion handler.
\until boost::asio::io_context
@@ -217,9 +221,9 @@ Return to \ref tuttimer3
*/
/**
\page tuttimer4 Timer.4 - Using a member function as a handler
\page tuttimer4 Timer.4 - Using a member function as a completion handler
In this tutorial we will see how to use a class member function as a callback
In this tutorial we will see how to use a class member function as a completion
handler. The program should execute identically to the tutorial program from
tutorial Timer.3.
@@ -229,7 +233,7 @@ tutorial Timer.3.
\until bind.hpp
Instead of defining a free function <tt>print</tt> as the
callback handler, as we did in the earlier tutorial programs, we now define a
completion handler, as we did in the earlier tutorial programs, we now define a
class called <tt>printer</tt>.
\until public
@@ -244,7 +248,7 @@ The boost::bind() function works just as well with class
member functions as with free functions. Since all non-static class member
functions have an implicit <tt>this</tt> parameter, we need to bind
<tt>this</tt> to the function. As in tutorial Timer.3, boost::bind()
converts our callback handler (now a member function) into a function object
converts our completion handler (now a member function) into a function object
that can be invoked as though it has the signature <tt>void(const
boost::system::error_code&)</tt>.
@@ -286,17 +290,17 @@ Return to \ref tuttimer4
*/
/**
\page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs
\page tuttimer5 Timer.5 - Synchronising completion handlers in multithreaded programs
This tutorial demonstrates the use of the boost::asio::strand class template to
synchronise callback handlers in a multithreaded program.
synchronise completion handlers in a multithreaded program.
The previous four tutorials avoided the issue of handler synchronisation by
calling the boost::asio::io_context::run() function from one thread only. As you
already know, the asio library provides a guarantee that callback handlers will
<b>only</b> be called from threads that are currently calling
already know, the asio library provides a guarantee that completion handlers
will <b>only</b> be called from threads that are currently calling
boost::asio::io_context::run(). Consequently, calling boost::asio::io_context::run() from
only one thread ensures that callback handlers cannot run concurrently.
only one thread ensures that completion handlers cannot run concurrently.
The single threaded approach is usually the best place to start when
developing applications using asio. The downside is the limitations it places
@@ -338,7 +342,7 @@ object.
\until {
When initiating the asynchronous operations, each callback handler is "bound"
When initiating the asynchronous operations, each completion handler is "bound"
to an boost::asio::strand<boost::asio::io_context::executor_type> object. The
boost::asio::bind_executor() function returns a new handler that automatically
dispatches its contained handler through the boost::asio::strand object. By

View File

@@ -24,15 +24,15 @@
namespace boost {
namespace asio {
/// Class used to specify that an asynchronous operation is detached.
/// A @ref completion_token type used to specify that an asynchronous operation
/// is detached.
/**
* The detached_t class is used to indicate that an asynchronous operation is
* detached. That is, there is no completion handler waiting for the
* operation's result. A detached_t object may be passed as a handler to an
* asynchronous operation, typically using the special value
* @c boost::asio::detached. For example:
*
* @code my_socket.async_send(my_buffer, boost::asio::detached);
* @endcode
*/
@@ -94,7 +94,8 @@ public:
}
};
/// A special value, similar to std::nothrow.
/// A @ref completion_token object used to specify that an asynchronous
/// operation is detached.
/**
* See the documentation for boost::asio::detached_t for a usage example.
*/

View File

@@ -24,6 +24,7 @@
# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1
# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1
#else // defined(BOOST_ASIO_STANDALONE)
// Boost.Config library is available.
# include <boost/config.hpp>
# include <boost/version.hpp>
# define BOOST_ASIO_HAS_BOOST_CONFIG 1

View File

@@ -482,7 +482,12 @@ int connect(socket_type s, const socket_addr_type* addr,
get_last_error(ec, result != 0);
#if defined(__linux__)
if (result != 0 && ec == boost::asio::error::try_again)
ec = boost::asio::error::no_buffer_space;
{
if (addr->sa_family == AF_UNIX)
ec = boost::asio::error::in_progress;
else
ec = boost::asio::error::no_buffer_space;
}
#endif // defined(__linux__)
return result;
}

View File

@@ -68,6 +68,8 @@ boost::system::error_code win_iocp_file_service::open(
else if ((open_flags & file_base::read_write) != 0)
access = GENERIC_READ | GENERIC_WRITE;
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD disposition = 0;
if ((open_flags & file_base::create) != 0)
{
@@ -92,7 +94,7 @@ boost::system::error_code win_iocp_file_service::open(
if ((open_flags & file_base::sync_all_on_write) != 0)
flags |= FILE_FLAG_WRITE_THROUGH;
HANDLE handle = ::CreateFileA(path, access, 0, 0, disposition, flags, 0);
HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0);
if (handle != INVALID_HANDLE_VALUE)
{
if (disposition == OPEN_ALWAYS && (open_flags & file_base::truncate) != 0)

View File

@@ -37,8 +37,8 @@ class executor_work_guard;
#if defined(GENERATING_DOCUMENTATION)
/// An object of type @c executor_work_guard controls ownership of executor work
/// within a scope.
/// An object of type @c executor_work_guard controls ownership of outstanding
/// executor work within a scope.
template <typename Executor>
class executor_work_guard
{
@@ -245,6 +245,11 @@ private:
#endif // !defined(GENERATING_DOCUMENTATION)
/// Create an @ref executor_work_guard object.
/**
* @param ex An executor.
*
* @returns A work guard constructed with the specified executor.
*/
template <typename Executor>
BOOST_ASIO_NODISCARD inline executor_work_guard<Executor>
make_work_guard(const Executor& ex,
@@ -256,6 +261,12 @@ make_work_guard(const Executor& ex,
}
/// Create an @ref executor_work_guard object.
/**
* @param ctx An execution context, from which an executor will be obtained.
*
* @returns A work guard constructed with the execution context's executor,
* obtained by performing <tt>ctx.get_executor()</tt>.
*/
template <typename ExecutionContext>
BOOST_ASIO_NODISCARD inline
executor_work_guard<typename ExecutionContext::executor_type>
@@ -269,6 +280,13 @@ make_work_guard(ExecutionContext& ctx,
}
/// Create an @ref executor_work_guard object.
/**
* @param t An arbitrary object, such as a completion handler, for which the
* associated executor will be obtained.
*
* @returns A work guard constructed with the associated executor of the object
* @c t, which is obtained as if by calling <tt>get_associated_executor(t)</tt>.
*/
template <typename T>
BOOST_ASIO_NODISCARD inline
executor_work_guard<typename associated_executor<T>::type>
@@ -288,6 +306,17 @@ make_work_guard(const T& t,
}
/// Create an @ref executor_work_guard object.
/**
* @param t An arbitrary object, such as a completion handler, for which the
* associated executor will be obtained.
*
* @param ex An executor to be used as the candidate object when determining the
* associated executor.
*
* @returns A work guard constructed with the associated executor of the object
* @c t, which is obtained as if by calling <tt>get_associated_executor(t,
* ex)</tt>.
*/
template <typename T, typename Executor>
BOOST_ASIO_NODISCARD inline
executor_work_guard<typename associated_executor<T, Executor>::type>
@@ -301,6 +330,17 @@ make_work_guard(const T& t, const Executor& ex,
}
/// Create an @ref executor_work_guard object.
/**
* @param t An arbitrary object, such as a completion handler, for which the
* associated executor will be obtained.
*
* @param ctx An execution context, from which an executor is obtained to use as
* the candidate object for determining the associated executor.
*
* @returns A work guard constructed with the associated executor of the object
* @c t, which is obtained as if by calling <tt>get_associated_executor(t,
* ctx.get_executor())</tt>.
*/
template <typename T, typename ExecutionContext>
BOOST_ASIO_NODISCARD inline executor_work_guard<typename associated_executor<T,
typename ExecutionContext::executor_type>::type>

View File

@@ -24,7 +24,7 @@ namespace boost {
namespace asio {
namespace experimental {
/// Completion token type used to specify that the completion handler
/// A @ref completion_token adapter used to specify that the completion handler
/// arguments should be combined into a single argument.
/**
* The as_single_t class is used to indicate that any arguments to the
@@ -116,8 +116,8 @@ public:
CompletionToken token_;
};
/// Create a completion token to specify that the completion handler arguments
/// should be combined into a single argument.
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
BOOST_ASIO_CONSTEXPR as_single_t<typename decay<CompletionToken>::type>

View File

@@ -24,7 +24,7 @@ namespace boost {
namespace asio {
namespace experimental {
/// Completion token type used to specify that the completion handler
/// A @ref completion_token adapter used to specify that the completion handler
/// arguments should be combined into a single tuple argument.
/**
* The as_tuple_t class is used to indicate that any arguments to the
@@ -112,8 +112,8 @@ public:
CompletionToken token_;
};
/// Create a completion token to specify that the completion handler arguments
/// should be combined into a single tuple argument.
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
BOOST_ASIO_CONSTEXPR as_tuple_t<typename decay<CompletionToken>::type>

View File

@@ -33,6 +33,67 @@ namespace detail {
} // namespace detail
/// A channel for messages.
/**
* The basic_channel class template is used for sending messages between
* different parts of the same application. A <em>message</em> is defined as a
* collection of arguments to be passed to a completion handler, and the set of
* messages supported by a channel is specified by its @c Traits and
* <tt>Signatures...</tt> template parameters. Messages may be sent and received
* using asynchronous or non-blocking synchronous operations.
*
* Unless customising the traits, applications will typically use the @c
* experimental::channel alias template. For example:
* @code void send_loop(int i, steady_timer& timer,
* channel<void(error_code, int)>& ch)
* {
* if (i < 10)
* {
* timer.expires_after(chrono::seconds(1));
* timer.async_wait(
* [i, &timer, &ch](error_code error)
* {
* if (!error)
* {
* ch.async_send(error_code(), i,
* [i, &timer, &ch](error_code error)
* {
* if (!error)
* {
* send_loop(i + 1, timer, ch);
* }
* });
* }
* });
* }
* else
* {
* ch.close();
* }
* }
*
* void receive_loop(channel<void(error_code, int)>& ch)
* {
* ch.async_receive(
* [&ch](error_code error, int i)
* {
* if (!error)
* {
* std::cout << "Received " << i << "\n";
* receive_loop(ch);
* }
* });
* } @endcode
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* The basic_channel class template is not thread-safe, and would typically be
* used for passing messages between application code that runs on the same
* thread or in the same strand. Consider using @ref basic_concurrent_channel,
* and its alias template @c experimental::concurrent_channel, to pass messages
* between code running in different threads.
*/
template <typename Executor, typename Traits, typename... Signatures>
class basic_channel
#if !defined(GENERATING_DOCUMENTATION)
@@ -254,7 +315,7 @@ public:
/// Cancel all asynchronous operations waiting on the channel.
/**
* All outstanding send operations will complete with the error
* @c boost::asio::experimental::error::channel_canceld. Outstanding receive
* @c boost::asio::experimental::error::channel_cancelled. Outstanding receive
* operations complete with the result as determined by the channel traits.
*/
void cancel()

View File

@@ -33,6 +33,67 @@ namespace detail {
} // namespace detail
/// A channel for messages.
/**
* The basic_concurrent_channel class template is used for sending messages
* between different parts of the same application. A <em>message</em> is
* defined as a collection of arguments to be passed to a completion handler,
* and the set of messages supported by a channel is specified by its @c Traits
* and <tt>Signatures...</tt> template parameters. Messages may be sent and
* received using asynchronous or non-blocking synchronous operations.
*
* Unless customising the traits, applications will typically use the @c
* experimental::concurrent_channel alias template. For example:
* @code void send_loop(int i, steady_timer& timer,
* concurrent_channel<void(error_code, int)>& ch)
* {
* if (i < 10)
* {
* timer.expires_after(chrono::seconds(1));
* timer.async_wait(
* [i, &timer, &ch](error_code error)
* {
* if (!error)
* {
* ch.async_send(error_code(), i,
* [i, &timer, &ch](error_code error)
* {
* if (!error)
* {
* send_loop(i + 1, timer, ch);
* }
* });
* }
* });
* }
* else
* {
* ch.close();
* }
* }
*
* void receive_loop(concurent_channel<void(error_code, int)>& ch)
* {
* ch.async_receive(
* [&ch](error_code error, int i)
* {
* if (!error)
* {
* std::cout << "Received " << i << "\n";
* receive_loop(ch);
* }
* });
* } @endcode
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Safe.
*
* The basic_concurrent_channel class template is thread-safe, and would
* typically be used for passing messages between application code that run on
* different threads. Consider using @ref basic_channel, and its alias template
* @c experimental::channel, to pass messages between code running in a single
* thread or on the same strand.
*/
template <typename Executor, typename Traits, typename... Signatures>
class basic_concurrent_channel
#if !defined(GENERATING_DOCUMENTATION)
@@ -261,7 +322,7 @@ public:
/// Cancel all asynchronous operations waiting on the channel.
/**
* All outstanding send operations will complete with the error
* @c boost::asio::experimental::error::channel_canceld. Outstanding receive
* @c boost::asio::experimental::error::channel_cancelled. Outstanding receive
* operations complete with the result as determined by the channel traits.
*/
void cancel()

View File

@@ -474,7 +474,7 @@ struct is_deferred<deferred_conditional<OnTrue, OnFalse> > : true_type
* operation, typically using the special value @c boost::asio::deferred. For
* example:
*
* @code auto my_sender
* @code auto my_deferred_op
* = my_socket.async_read_some(my_buffer,
* boost::asio::experimental::deferred); @endcode
*
@@ -585,7 +585,8 @@ inline auto operator|(Head head, BOOST_ASIO_MOVE_ARG(Tail) tail)
BOOST_ASIO_MOVE_CAST(Tail)(tail));
}
/// A special value, similar to std::nothrow.
/// A @ref completion_token object used to specify that an asynchronous
/// operation should return a function object to lazily launch the operation.
/**
* See the documentation for boost::asio::experimental::deferred_t for a usage
* example.

View File

@@ -182,10 +182,8 @@ void channel_service<Mutex>::reset(
typename Mutex::scoped_lock lock(impl.mutex_);
if (impl.receive_state_ == closed)
impl.receive_state_ = block;
if (impl.send_state_ == closed)
impl.send_state_ = impl.max_buffer_size_ ? buffer : block;
impl.receive_state_ = block;
impl.send_state_ = impl.max_buffer_size_ ? buffer : block;
impl.buffer_clear();
}

View File

@@ -128,7 +128,7 @@ public:
* operations, it must return a boost::asio::cancellation_type value other
* than <tt>boost::asio::cancellation_type::none</tt>.
*
* @param token A completion token whose signature is comprised of
* @param token A @ref completion_token whose signature is comprised of
* a @c std::array<std::size_t, N> indicating the completion order of the
* operations, followed by all operations' completion handler arguments.
*

View File

@@ -501,7 +501,10 @@ struct promise<void(Ts...), Executor>
throw std::logic_error(
"Can't use race on an empty range with deduced executor");
else
return race(std::begin(range)->get_executor(), std::move(range));
{
auto ex = std::begin(range)->get_executor();
return race(ex, std::move(range));
}
}
template <typename Range>
@@ -518,7 +521,10 @@ struct promise<void(Ts...), Executor>
throw std::logic_error(
"Can't use all on an empty range with deduced executor");
else
return all(std::begin(range)->get_executor(), std::move(range));
{
auto ex = std::begin(range)->get_executor();
return all(ex, std::move(range));
}
}
private:

View File

@@ -32,7 +32,7 @@ class any_io_executor;
namespace experimental {
/// A completion token that represents the currently executing resumable
/// A @ref completion_token that represents the currently executing resumable
/// coroutine.
/**
* The @c use_coro_t class, with its value @c use_coro, is used to represent an
@@ -146,8 +146,8 @@ struct use_coro_t
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
};
/// A completion token object that represents the currently executing resumable
/// coroutine.
/// A @ref completion_token object that represents the currently executing
/// resumable coroutine.
/**
* See the documentation for boost::asio::use_coro_t for a usage example.
*/

View File

@@ -200,6 +200,61 @@ private:
awaitable<T, Executor> awaitable_;
};
template <typename Handler, typename Executor, typename = void>
class co_spawn_cancellation_handler
{
public:
co_spawn_cancellation_handler(const Handler& handler, const Executor& ex)
: ex_(boost::asio::get_associated_executor(handler, ex))
{
}
cancellation_slot slot()
{
return signal_.slot();
}
void operator()(cancellation_type_t type)
{
cancellation_signal* sig = &signal_;
boost::asio::dispatch(ex_, [sig, type]{ sig->emit(type); });
}
private:
cancellation_signal signal_;
typename associated_executor<Handler, Executor>::type ex_;
};
template <typename Handler, typename Executor>
class co_spawn_cancellation_handler<Handler, Executor,
typename enable_if<
is_same<
typename associated_executor<Handler,
Executor>::asio_associated_executor_is_unspecialised,
void
>::value
>::type>
{
public:
co_spawn_cancellation_handler(const Handler&, const Executor&)
{
}
cancellation_slot slot()
{
return signal_.slot();
}
void operator()(cancellation_type_t type)
{
signal_.emit(type);
}
private:
cancellation_signal signal_;
};
template <typename Executor>
class initiate_co_spawn
{
@@ -221,17 +276,26 @@ public:
void operator()(Handler&& handler, F&& f) const
{
typedef typename result_of<F()>::type awaitable_type;
typedef typename decay<Handler>::type handler_type;
typedef co_spawn_cancellation_handler<
handler_type, Executor> cancel_handler_type;
cancellation_state proxy_cancel_state(
boost::asio::get_associated_cancellation_slot(handler),
enable_total_cancellation());
auto slot = boost::asio::get_associated_cancellation_slot(handler);
cancel_handler_type* cancel_handler = slot.is_connected()
? &slot.template emplace<cancel_handler_type>(handler, ex_)
: nullptr;
cancellation_state cancel_state(proxy_cancel_state.slot());
cancellation_slot proxy_slot(
cancel_handler
? cancel_handler->slot()
: cancellation_slot());
cancellation_state cancel_state(proxy_slot);
auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
ex_, std::forward<F>(f), std::forward<Handler>(handler));
awaitable_handler<executor_type, void>(std::move(a), ex_,
proxy_cancel_state.slot(), cancel_state).launch();
awaitable_handler<executor_type, void>(std::move(a),
ex_, proxy_slot, cancel_state).launch();
}
private:

View File

@@ -170,30 +170,12 @@ namespace detail {
* returning when there is no more work to do. For example, the io_context may
* be being run in a background thread that is launched prior to the
* application's asynchronous operations. The run() call may be kept running by
* creating an executor that tracks work against the io_context:
* using the @ref make_work_guard function to create an object of type
* boost::asio::executor_work_guard<io_context::executor_type>:
*
* @code boost::asio::io_context io_context;
* auto work = boost::asio::require(io_context.get_executor(),
* boost::asio::execution::outstanding_work.tracked);
* ... @endcode
*
* If using C++03, which lacks automatic variable type deduction, you may
* compute the return type of the require call:
*
* @code boost::asio::io_context io_context;
* typename boost::asio::require_result<
* boost::asio::io_context::executor_type,
* boost::asio::exeution::outstanding_work_t::tracked_t>
* work = boost::asio::require(io_context.get_executor(),
* boost::asio::execution::outstanding_work.tracked);
* ... @endcode
*
* or store the result in the type-erasing executor wrapper, any_io_executor:
*
* @code boost::asio::io_context io_context;
* boost::asio::any_io_executor work
* = boost::asio::require(io_context.get_executor(),
* boost::asio::execution::outstanding_work.tracked);
* boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
* = boost::asio::make_work_guard(io_context);
* ... @endcode
*
* To effect a shutdown, the application will then need to call the io_context
@@ -202,15 +184,13 @@ namespace detail {
* permitting ready handlers to be dispatched.
*
* Alternatively, if the application requires that all operations and handlers
* be allowed to finish normally, store the work-tracking executor in an
* any_io_executor object, so that it may be explicitly reset.
* be allowed to finish normally, the work object may be explicitly reset.
*
* @code boost::asio::io_context io_context;
* boost::asio::any_io_executor work
* = boost::asio::require(io_context.get_executor(),
* boost::asio::execution::outstanding_work.tracked);
* boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
* = boost::asio::make_work_guard(io_context);
* ...
* work = boost::asio::any_io_executor(); // Allow run() to exit. @endcode
* work.reset(); // Allow run() to exit. @endcode
*/
class io_context
: public execution_context

View File

@@ -65,15 +65,31 @@ public:
#endif
/// Default constructor.
/**
* Initialises the @c address_v4 object such that:
* @li <tt>to_bytes()</tt> yields <tt>{0, 0, 0, 0}</tt>; and
* @li <tt>to_uint() == 0</tt>.
*/
address_v4() BOOST_ASIO_NOEXCEPT
{
addr_.s_addr = 0;
}
/// Construct an address from raw bytes.
/**
* Initialises the @c address_v4 object such that <tt>to_bytes() ==
* bytes</tt>.
*
* @throws out_of_range Thrown if any element in @c bytes is not in the range
* <tt>0 - 0xFF</tt>. Note that no range checking is required for platforms
* where <tt>std::numeric_limits<unsigned char>::max()</tt> is <tt>0xFF</tt>.
*/
BOOST_ASIO_DECL explicit address_v4(const bytes_type& bytes);
/// Construct an address from an unsigned integer in host byte order.
/**
* Initialises the @c address_v4 object such that <tt>to_uint() == addr</tt>.
*/
BOOST_ASIO_DECL explicit address_v4(uint_type addr);
/// Copy constructor.
@@ -145,9 +161,22 @@ public:
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Determine whether the address is a loopback address.
/**
* This function tests whether the address is in the address block
* <tt>127.0.0.0/8</tt>, which corresponds to the address range
* <tt>127.0.0.0 - 127.255.255.255</tt>.
*
* @returns <tt>(to_uint() & 0xFF000000) == 0x7F000000</tt>.
*/
BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT;
/// Determine whether the address is unspecified.
/**
* This function tests whether the address is the unspecified address
* <tt>0.0.0.0</tt>.
*
* @returns <tt>to_uint() == 0</tt>.
*/
BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT;
#if !defined(BOOST_ASIO_NO_DEPRECATED)
@@ -165,6 +194,13 @@ public:
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Determine whether the address is a multicast address.
/**
* This function tests whether the address is in the multicast address block
* <tt>224.0.0.0/4</tt>, which corresponds to the address range
* <tt>224.0.0.0 - 239.255.255.255</tt>.
*
* @returns <tt>(to_uint() & 0xF0000000) == 0xE0000000</tt>.
*/
BOOST_ASIO_DECL bool is_multicast() const BOOST_ASIO_NOEXCEPT;
/// Compare two addresses for equality.
@@ -182,6 +218,11 @@ public:
}
/// Compare addresses for ordering.
/**
* Compares two addresses in host byte order.
*
* @returns <tt>a1.to_uint() < a2.to_uint()</tt>.
*/
friend bool operator<(const address_v4& a1,
const address_v4& a2) BOOST_ASIO_NOEXCEPT
{
@@ -189,6 +230,11 @@ public:
}
/// Compare addresses for ordering.
/**
* Compares two addresses in host byte order.
*
* @returns <tt>a1.to_uint() > a2.to_uint()</tt>.
*/
friend bool operator>(const address_v4& a1,
const address_v4& a2) BOOST_ASIO_NOEXCEPT
{
@@ -196,6 +242,11 @@ public:
}
/// Compare addresses for ordering.
/**
* Compares two addresses in host byte order.
*
* @returns <tt>a1.to_uint() <= a2.to_uint()</tt>.
*/
friend bool operator<=(const address_v4& a1,
const address_v4& a2) BOOST_ASIO_NOEXCEPT
{
@@ -203,6 +254,11 @@ public:
}
/// Compare addresses for ordering.
/**
* Compares two addresses in host byte order.
*
* @returns <tt>a1.to_uint() >= a2.to_uint()</tt>.
*/
friend bool operator>=(const address_v4& a1,
const address_v4& a2) BOOST_ASIO_NOEXCEPT
{
@@ -210,18 +266,36 @@ public:
}
/// Obtain an address object that represents any address.
/**
* This functions returns an address that represents the "any" address
* <tt>0.0.0.0</tt>.
*
* @returns A default-constructed @c address_v4 object.
*/
static address_v4 any() BOOST_ASIO_NOEXCEPT
{
return address_v4();
}
/// Obtain an address object that represents the loopback address.
/**
* This function returns an address that represents the well-known loopback
* address <tt>127.0.0.1</tt>.
*
* @returns <tt>address_v4(0x7F000001)</tt>.
*/
static address_v4 loopback() BOOST_ASIO_NOEXCEPT
{
return address_v4(0x7F000001);
}
/// Obtain an address object that represents the broadcast address.
/**
* This function returns an address that represents the broadcast address
* <tt>255.255.255.255</tt>.
*
* @returns <tt>address_v4(0xFFFFFFFF)</tt>.
*/
static address_v4 broadcast() BOOST_ASIO_NOEXCEPT
{
return address_v4(0xFFFFFFFF);

View File

@@ -68,9 +68,23 @@ public:
#endif
/// Default constructor.
/**
* Initialises the @c address_v6 object such that:
* @li <tt>to_bytes()</tt> yields <tt>{0, 0, ..., 0}</tt>; and
* @li <tt>scope_id() == 0</tt>.
*/
BOOST_ASIO_DECL address_v6() BOOST_ASIO_NOEXCEPT;
/// Construct an address from raw bytes and scope ID.
/**
* Initialises the @c address_v6 object such that:
* @li <tt>to_bytes() == bytes</tt>; and
* @li <tt>this->scope_id() == scope_id</tt>.
*
* @throws out_of_range Thrown if any element in @c bytes is not in the range
* <tt>0 - 0xFF</tt>. Note that no range checking is required for platforms
* where <tt>std::numeric_limits<unsigned char>::max()</tt> is <tt>0xFF</tt>.
*/
BOOST_ASIO_DECL explicit address_v6(const bytes_type& bytes,
scope_id_type scope_id = 0);
@@ -103,6 +117,8 @@ public:
/// The scope ID of the address.
/**
* Modifies the scope ID associated with the IPv6 address.
*
* @param id The new scope ID.
*/
void scope_id(scope_id_type id) BOOST_ASIO_NOEXCEPT
{
@@ -143,9 +159,17 @@ public:
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Determine whether the address is a loopback address.
/**
* This function tests whether the address is the loopback address
* <tt>::1</tt>.
*/
BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT;
/// Determine whether the address is unspecified.
/**
* This function tests whether the address is the loopback address
* <tt>::</tt>.
*/
BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT;
/// Determine whether the address is link local.
@@ -218,12 +242,22 @@ public:
}
/// Obtain an address object that represents any address.
/**
* This functions returns an address that represents the "any" address
* <tt>::</tt>.
*
* @returns A default-constructed @c address_v6 object.
*/
static address_v6 any() BOOST_ASIO_NOEXCEPT
{
return address_v6();
}
/// Obtain an address object that represents the loopback address.
/**
* This function returns an address that represents the well-known loopback
* address <tt>::1</tt>.
*/
BOOST_ASIO_DECL static address_v6 loopback() BOOST_ASIO_NOEXCEPT;
#if !defined(BOOST_ASIO_NO_DEPRECATED)

View File

@@ -24,7 +24,7 @@
namespace boost {
namespace asio {
/// Completion token type used to specify that an error produced by an
/// A @ref completion_token adapter used to specify that an error produced by an
/// asynchronous operation is captured to an error_code variable.
/**
* The redirect_error_t class is used to indicate that any error_code produced
@@ -48,7 +48,7 @@ public:
boost::system::error_code& ec_;
};
/// Create a completion token to capture error_code values to a variable.
/// Adapt a @ref completion_token to capture error_code values to a variable.
template <typename CompletionToken>
inline redirect_error_t<typename decay<CompletionToken>::type> redirect_error(
BOOST_ASIO_MOVE_ARG(CompletionToken) completion_token,

View File

@@ -31,7 +31,7 @@
namespace boost {
namespace asio {
/// A completion token that represents the currently executing coroutine.
/// A @ref completion_token that represents the currently executing coroutine.
/**
* The basic_yield_context class is a completion token type that is used to
* represent the currently executing stackful coroutine. A basic_yield_context
@@ -149,7 +149,8 @@ private:
};
#if defined(GENERATING_DOCUMENTATION)
/// Context object that represents the currently executing coroutine.
/// A @ref completion_token object that represents the currently executing
/// coroutine.
typedef basic_yield_context<unspecified> yield_context;
#else // defined(GENERATING_DOCUMENTATION)
typedef basic_yield_context<

View File

@@ -442,6 +442,11 @@ private:
/*@{*/
/// Create a @ref strand object for an executor.
/**
* @param ex An executor.
*
* @returns A strand constructed with the specified executor.
*/
template <typename Executor>
inline strand<Executor> make_strand(const Executor& ex,
typename constraint<
@@ -452,6 +457,12 @@ inline strand<Executor> make_strand(const Executor& ex,
}
/// Create a @ref strand object for an execution context.
/**
* @param ctx An execution context, from which an executor will be obtained.
*
* @returns A strand constructed with the execution context's executor, obtained
* by performing <tt>ctx.get_executor()</tt>.
*/
template <typename ExecutionContext>
inline strand<typename ExecutionContext::executor_type>
make_strand(ExecutionContext& ctx,

View File

@@ -74,7 +74,7 @@ __declspec(selectany) cancellation_state_t cancellation_state;
/// of the current coroutine.
/**
* Let <tt>P</tt> be the cancellation slot associated with the current
* coroutine's `co_spawn` completion handler. Assigns a new
* coroutine's @ref co_spawn completion handler. Assigns a new
* boost::asio::cancellation_state object <tt>S</tt>, constructed as
* <tt>S(P)</tt>, into the current coroutine's cancellation state object.
*
@@ -96,7 +96,7 @@ reset_cancellation_state();
/// of the current coroutine.
/**
* Let <tt>P</tt> be the cancellation slot associated with the current
* coroutine's `co_spawn` completion handler. Assigns a new
* coroutine's @ref co_spawn completion handler. Assigns a new
* boost::asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
* std::forward<Filter>(filter))</tt>, into the current coroutine's
* cancellation state object.
@@ -121,7 +121,7 @@ reset_cancellation_state(BOOST_ASIO_MOVE_ARG(Filter) filter);
/// of the current coroutine.
/**
* Let <tt>P</tt> be the cancellation slot associated with the current
* coroutine's `co_spawn` completion handler. Assigns a new
* coroutine's @ref co_spawn completion handler. Assigns a new
* boost::asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
* std::forward<InFilter>(in_filter),
* std::forward<OutFilter>(out_filter))</tt>, into the current coroutine's

View File

@@ -33,7 +33,7 @@
namespace boost {
namespace asio {
/// A completion token that represents the currently executing coroutine.
/// A @ref completion_token that represents the currently executing coroutine.
/**
* The @c use_awaitable_t class, with its value @c use_awaitable, is used to
* represent the currently executing coroutine. This completion token may be
@@ -144,7 +144,8 @@ struct use_awaitable_t
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
};
/// A completion token object that represents the currently executing coroutine.
/// A @ref completion_token object that represents the currently executing
/// coroutine.
/**
* See the documentation for boost::asio::use_awaitable_t for a usage example.
*/

View File

@@ -38,8 +38,8 @@ class packaged_handler;
} // namespace detail
/// A completion token type that causes an asynchronous operation to return a
/// future.
/// A @ref completion_token type that causes an asynchronous operation to return
/// a future.
/**
* The use_future_t class is a completion token type that is used to indicate
* that an asynchronous operation should return a std::future object. A
@@ -141,8 +141,8 @@ private:
std_allocator_void, Allocator>::type allocator_;
};
/// A completion token object that causes an asynchronous operation to return a
/// future.
/// A @ref completion_token object that causes an asynchronous operation to
/// return a future.
/**
* See the documentation for boost::asio::use_future_t for a usage example.
*/

View File

@@ -18,6 +18,6 @@
// BOOST_ASIO_VERSION % 100 is the sub-minor version
// BOOST_ASIO_VERSION / 100 % 1000 is the minor version
// BOOST_ASIO_VERSION / 100000 is the major version
#define BOOST_ASIO_VERSION 102201 // 1.22.1
#define BOOST_ASIO_VERSION 102202 // 1.22.2
#endif // BOOST_ASIO_VERSION_HPP