Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Compositions as Asynchronous Operations

Application developers may wish to package their own compositions as conforming asynchronous operations within the 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 requirements on asynchronous operations, Boost.Asio includes the async_compose function to simplify this process. The async_compose implementation automatically provides an intermediate completion handler that correctly propagates the 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.

See Also

async_compose, Operations examples (C++11), Operations examples (C++14).


PrevUpHomeNext