2025-01-12 20:37:50 +08:00

102 lines
3.6 KiB
Plaintext

[/
/ Copyright (c) 2003-2023 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]