6

I'm a Boost C++ newbie and, using it to write a Server-like application I am wondering if it is possible to concurrently use boost::asio::ip::tcp::socket::async_read_some(...) and boost::asio::ip::tcp::socket::write_some(...).

In my scenario a Connection object listens continuously via:

    void Connection::doRead()
{
    auto self(shared_from_this());
    socket_.async_read_some(boost::asio::buffer(data_rx_, max_length),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
          if (!ec)
          {
              afterReading(length);
              doRead();
          }
        });
}

At the same time, an asynchronous function callback (running in a different thread) could invoke socket_.read_write while Connection is "reading".

I've read various Boost::Asio docs but this scenario was never covered.

Is this allowed? What should be done to avoid it if not?

EDIT:

I have read, as suggested, various answers including this: Why do I need strand per connection when using boost::asio?, but still can't find an answer as it is not specified wether mixing async and sync (called by different threads) calls is safe or not.

Community
  • 1
  • 1
Francis Straccia
  • 894
  • 1
  • 7
  • 20
  • 1
    This [answer](http://stackoverflow.com/a/12801042/1053968) may be helpful. – Tanner Sansbury Dec 01 '15 at 17:53
  • @TannerSansbury is right and imo this should probably just be closed out as a duplicate. You need to use strands and it definitely doesn't make any sense to write to a client while the client isn't listening, but rather busy writing. –  Dec 01 '15 at 20:28
  • Possible duplicate of [Why do I need strand per connection when using boost::asio?](http://stackoverflow.com/questions/12794107/why-do-i-need-strand-per-connection-when-using-boostasio) –  Dec 01 '15 at 20:28
  • Well, I read the answer but can't find an answer to my question. It is stated that async operations are thread safe when initiated from the same thread, while sync MAY be safe even when initiated from 2 different threads (note 1 of the answer). There is no mention about mixing async and sync calls. So I do not think this is a duplicate. – Francis Straccia Dec 02 '15 at 09:48

1 Answers1

5

It is not safe.

This answer goes into details, but to summarize, it is not safe for multiple threads to make calls concurrently, with the exception that multiple synchronous calls may be safe if supported by the OS. If one thread initiates an asynchronous operation on a socket while another thread is performing a synchronous operation on the same socket, then it falls into the former case and is not safe.

The most elegant solution is to avoid mixing synchronous and asynchronous operations.

  • If using synchronous operations and the OS does not support concurrent synchronous operations, then perform explicit locking, such as by using mutexes.
  • If using asynchronous operations and multiple threads, then use an explicit strand to prevent concurrent invocation of handlers.

Also, one can synchronously block waiting for an asynchronous operation to complete by leveraging Boost.Asio's support for futures. This approach can allow for one to expose a synchronous blocking API to a user, but use asynchronous operations internally. The initiating operation (async_*) would need to be invoked within a strand, and if the caller is not running within the context of the strand, then some form of synchronization will need to be used to allow the caller to wait for Asio to create the future object.

Community
  • 1
  • 1
Tanner Sansbury
  • 51,153
  • 9
  • 112
  • 169
  • "If using asynchronous operations and multiple threads, then use an explicit strand to prevent concurrent invocation of handlers." Also, theorically, the calls to initiating functions (async_) should not be called concurrently, so you should also synchronize the calls, not only the invocation of handlers. Especially when using ssl::stream. – Adrian B. Jun 16 '21 at 21:00