Iwa
Iwa

Reputation: 547

asio::async_write and strand

asio::async_write(m_socket, asio::buffer(buf, bytes),
                custom_alloc(m_strand.wrap(custom_alloc(_OnSend))));

Does this code guarantee that all asynchronous operation handlers(calls to async_write_some) inside async_write are called through strand? (or it's just for my_handler?)

Upvotes: 4

Views: 2765

Answers (2)

Tanner Sansbury
Tanner Sansbury

Reputation: 51971

With the following code:

asio::async_write(stream, ..., custom_alloc(m_strand.wrap(...)));

For this composed operation, all calls to stream.async_write_some() will be invoked within m_strand if all of the following conditions are true:

  • The initiating async_write(...) call is running within m_strand():

    assert(m_strand.running_in_this_thread());
    asio::async_write(stream, ..., custom_alloc(m_strand.wrap(...)));
    
  • The return type from custom_alloc is either:

    • the exact type returned from strand::wrap()

      template <typename Handler> 
      Handler custom_alloc(Handler) { ... }
      
    • a custom handler that appropriate chains invocations of asio_handler_invoke():

      template <class Handler>
      class custom_handler
      {
      public:
        custom_handler(Handler handler)
          : handler_(handler)
        {}
      
        template <class... Args>
        void operator()(Args&&... args)
        {
          handler_(std::forward<Args>(args)...);
        }
      
        template <typename Function>
        friend void asio_handler_invoke(
          Function intermediate_handler,
          custom_handler* my_handler)
        {
          // Support chaining custom strategies incase the wrapped handler
          // has a custom strategy of its own.
          using boost::asio::asio_handler_invoke;
          asio_handler_invoke(intermediate_handler, &my_handler->handler_);
        }
      
      private:
        Handler handler_;
      };
      
      template <typename Handler>
      custom_handler<Handler> custom_alloc(Handler handler)
      {
        return {handler};
      }
      

See this answer for more details on strands, and this answer for details on asio_handler_invoke.

Upvotes: 9

Galimov Albert
Galimov Albert

Reputation: 7357

UPD: This answer is wrong=) For anyone interested you can check details in the tail of comments, thanks to Tanner Sansbury.


No. This guarantees your completion handler will be called with strand lock. This not includes calls to async_write_some.

Also boost::asio does not have something like "write queue" and you need to manage async_write calls in order to prevent writing mixed content.

Upvotes: 4

Related Questions