2

I'm new to ASIO and like to understand how thread-safety works, so that I can figure out what assumptions I can make when using ASIO APIs.

What I found out so far:

Multiple threads can run io_service.run().

Therefore, the handlers within a class such as socket, might be invoked from different threads, but only from the threads that execute io_service.run().

Let's assume that a socket has some internal state that must be protected from concurrent access.

The socket would wrap its handlers with a strand, which serializes the execution of the handlers. It has essentially the same effect as acquiring a mutex in each handler, but with better performance.

But socket also has public methods, such as socket.async_write_some(). It too might be invoked from different threads.

Let's assume that socket.async_write_some() accesses the same internal state, so some protection mechanism is needed.

How do public methods access the internal state in a safe way?

  • can strand be used to serialize invocations of public methods?

  • invoke post([]{ /* actual implementation of the method goes here */}) within the public method?

  • use a mutex in addition to the strand?

What assumptions can I make when invoking public APIs?

Can I assume that a socket protects it's internal state, even if I invoke it from a background thread that does not invoke io_service.run()?

If so, is there some documentation for that? I'd rather not depend on an undocumented implementation detail.

Stefan
  • 4,187
  • 1
  • 32
  • 38
  • In other words, you ask how to learn asio, exact ? Anyway look [that](https://stackoverflow.com/questions/244453/best-documentation-for-boostasio/26753331#26753331) and [that](https://stackoverflow.com/questions/12794107/why-do-i-need-strand-per-connection-when-using-boostasio/12801042#12801042) and – Jean Davy Dec 06 '19 at 10:03

1 Answers1

2

Look at the thread safety guarantees, which are documented with each class, but also in general https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/overview/core/threads.html

This confirms that:

Q. Can I assume that a socket protects it's internal state, even if I invoke it from a background thread that does not invoke io_service.run()?

No you can not assume that, because it doesn't "protect it's internal state" in the sense you likely mean: it does not synchronize access to it.

Also, access from multiple threads running io_service handlers does no mean it's safe. You may need strands (either implicit or explicit) to ensure that.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I used the c++11 thread_local scope on my io_service, worked well for me. I'm assuming it is safe to have multiple io_service objects. Perhaps I should have used strands...? – moodboom Dec 12 '19 at 00:13
  • @moodboom The `io_service` is one of the few Asio objects that's actually documented to be thread-safe for concurrent use. So, no it doesn't make a lot of sense to have that `thread_local` (also, that's not a scope, but a lifetime or storage duration). You CAN have multiple io_services, but they won't do anything unless you `run()` or` `poll()` on them. – sehe Dec 12 '19 at 10:56
  • yeah you're right, i was smoking crack, i don't use thread_local on io_service, sorry. i do have several io_service objects, but only one main one, and others that I stand up for temporary use, for example to make outbound https calls. now i'm thinking maybe i should share the one even with the outbound https calls. anyway, i'm getting too chatty in the comments, sorry. – moodboom Dec 12 '19 at 15:27