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 Answer 1

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?

Sign up to request clarification or add additional context in comments.

3 Comments

more idiomatic these days: post(bind_executor(strand_, [&sock]{ .. }));
@RichardHodges Agreed. Wait, can you use the asio::post free function with a single argument... TIL
Yes if you don’t bind the executor you get given a system_executor, which is probably not one of asio’s better ideas.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.