As others have noted, std::mutex
and other locking mechanics, can be be used within handlers. However, there is a fundamental difference between the two:
- An external locking mechanism within a handler is used to protect resources from race conditions.
- A
strand
is used to remove contention between handlers, resulting in the removal of race conditions between handlers.
If the entire handler is being synchronized as a result of potential race conditions with other handlers, and not threads external to the threadpool, then I would like to accentuate one of the subtle differences in synchronization between an external mechanism and boost::asio::strand
.
Consider the following scenario:
- A threadpool of 2 threads is implemented with Boost.Asio.
- Handlers
A
and B
will be synchronized on the same mutex.
- Handler
C
requires no synchronization.
- Handlers
A
, B
, and C
are posted into the io_service
.
A
and B
are invoked. The threadpool is now exhausted due to external synchronization, as both threads are being used. Unfortunately, one of the threads is blocked on a resource, causing handlers that require no synchronization, such as C
, to sit in the queue.
If a strand is used for synchronization in this scenario, then this instance of starvation would not have occurred. A strand
maintains its own handler queue, and guarantees that only one of its handlers is in the io_service
, resulting in handlers being synchronized before being placed into the io_service
. In the scenario, if A
and B
are posted into the strand
, then the strand
will post A
into the io_service
. This would result in A
and C
being in the io_service
, allowing C
to run concurrently while B
remains in the strand
's queue waiting for A
to complete.
Also, there are use cases where both of these forms of synchronization can be used together. For example, consider the case where resources are shared with a thread running outside of the threadpool. A mutex would still be required by threads internal and external to the threadpool. However, a strand
could be used to remove the contention for the mutex between threads internal to the threadpool.