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:
@@ -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
|
||||
|
||||
@@ -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
56
doc/overview/channels.qbk
Normal 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
101
doc/overview/compose.qbk
Normal 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]
|
||||
@@ -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
56
doc/overview/deferred.qbk
Normal 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
49
doc/overview/files.qbk
Normal 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
41
doc/overview/futures.qbk
Normal 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]
|
||||
@@ -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
|
||||
|
||||
65
doc/overview/parallel_group.qbk
Normal file
65
doc/overview/parallel_group.qbk
Normal 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
38
doc/overview/pipes.qbk
Normal 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
79
doc/overview/promises.qbk
Normal 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]
|
||||
@@ -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]
|
||||
|
||||
216
doc/overview/token_adapters.qbk
Normal file
216
doc/overview/token_adapters.qbk
Normal 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]
|
||||
@@ -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
@@ -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]
|
||||
|
||||
|
||||
@@ -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]) > 0">
|
||||
<xsl:text>[link boost_asio.tutorial.</xsl:text>
|
||||
<xsl:choose>
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user