1

I have an io_context that is run by multiple threads. I'm using sockets and timers. I know that I need to wrap all async_writes by a strand to prevent concurrent writes to the socket.

But can two threads concurrently access the socket to issue an async_read and an async_write at the same time?

Or what about shutdown() or close() being called while another thread calls async_read? Or cancel() on a timer?

Do I need to protect the socket/timer with a mutex or strand in this cases?

1 Answers1

2

This has oft been asked and answered:

Thread Safety

In general, it is safe to make concurrent use of distinct objects, but unsafe to make concurrent use of a single object. However, types such as io_context provide a stronger guarantee that it is safe to use a single object concurrently.

So yes, you need to protect active accesses to you timer/socket objects. However, having asynchronous operations in flight is not a concern: it's about your accesses that require your synchronization.

So,

 asio::post(strand, [&sock] { sock.shutdown();});

is always safe, and when you have only 1 thread running the service, then

post(io_context_, [&sock] { sock.shutdown();});

is also fine. Both will have the effect of safely canceling any asynchronous operations still in flight on sock.

See also the excellent: Why do I need strand per connection when using boost::asio?

sehe
  • 374,641
  • 47
  • 450
  • 633