When are the handlers for canceled boost :: asio handlers executed?

In fast-track mode, say it cancels the asynchronous connection, send and receive ends immediately, and handlers for canceled operations will be passed to boost :: asio :: error :: operation_aborted error.

I would like to know if a canceled handler runs (and sees an operation_aborted error) before the other (non-canceled and re-scheduled) completion handlers.

Here is the graph that concerns me:

acceptHandler and readHandler work in the same event loop and on the same thread.

  • time t0 - readHandler works on oldConnectionSocket
  • time t1 - acceptHandler is running
  • time t2 - acceptHandler calls oldConnectionSocket.cancel
  • time t3 - acceptHandler closes oldConnectionSocket
  • time t4 - acceptHandler calls newConnectionSocket.async_read (... readHandler ...)
  • time t5 - readHandler is called (from which context?)

Is it possible in t5 to call readHandler in the context of newConnectionSocket before it is called with an operation_aborted error in the context of oldConnectionSocket?

+2


source to share


1 answer


Canceled operations will immediately dispatch the pending call handlers. However, it io_service

does not make any guarantees about the order in which the handlers are called. Thus, one io_service

can choose to call ReadHandlers in any order. Currently only strand

defines guaranteed ordering under certain conditions.

Within a completion handler, if the goal is to know which I / O object was associated with an operation, consider building a completion handler to have an explicit handle to the I / O object. This is often accomplished by any of the following:

  • custom functor
  • std::bind()

    or boost::bind()

  • C ++ 11 lambda

One common idiom is to manage an I / O object with a single class that inherits from boost::enable_shared_from_this<>

. When a class inherits from boost::enable_shared_from_this

, it provides a member function shared_from_this()

that returns a valid instance shared_ptr

in this

. A copy shared_ptr

is passed to completion handlers such as the capture list in lambdas or passed as an instance handle to boost::bind()

. This allows the handlers to know the I / O object on which the operation was performed and extends the life of the I / O object at least as long as the handler. See Boost.Asio Asynchronous TCP Day Server for an example using this approach.



class tcp_connection
  : public boost::enable_shared_from_this<tcp_connection>
{
public:

  // ...

  void start()
  {    
    boost::asio::async_write(socket_, ...,
        boost::bind(&tcp_connection::handle_write, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }

  void handle_write(
    const boost::system::error_code& error,
    std::size_t bytes_transferred)
  {
    // I/O object is this->socket_.
  }

  tcp::socket socket_;
};

      

On the other hand, if the goal is to determine if one handler was executed before another, then:

  • The application will need to explicitly manage state
  • trying to manage multiple dependent call chains can introduce unnecessary complexity and often indicates a need for redesign
  • custom handlers can be used to prioritize the execution order of handlers. The Boost.Asio Invocation example uses custom handlers that are added to the priority queue, which are then executed at a later point in time.
+4


source







All Articles