What if when the destructor of a asio::strand
is called, there are still some ready/unready handlers on this strand?
Per the documentation:
Handlers posted through the strand that have not yet been invoked will still be dispatched in a way that meets the guarantee of non-concurrency.
Does this mean it will still invoke all handlers, including waiting the unready handlers to be ready, just as if it was not being destroyed (maybe except not accepting new handlers)?
Or maybe I am conceptually wrong about "unready handler" --- an async operation won't post its handler on the strand before its completion? If the destructor of the target strand is called, will this async operation be aware of that?
From the documentation:
Handlers posted through the
strand
that have not yet been invoked will still be dispatched in a way that meets the guarantee of non-concurrency.
Basically, a strand
can be thought of as being associated, but not owning, a queue of handlers. If a handler queue has no handlers currently posted into an io_service
, then it will pop one handler from itself and post it into the associated io_service
. This flow guarantees that handlers posted into the same strand
will not be invoked concurrently.
All handlers posted into a strand
are considered ready-to-run. Hence the lack of completion conditions on the strand
API. When strand
s are used with asynchronous operations, the initiating function is often provided a handler returned from strand::wrap()
:
async_op(..., s.wrap(a));
When async_op()
is completed, it will invoke the handler returned from s.wrap(a)
. This handler will then post the user provided handler a
into a strand
that is associated with the same queue as the original s
strand. As the lifetime of the strand
object does not affect the lifetime of the handler queue, async_op()
does not need to concern itself with the lifetime of s
.
When the io_service
associated with the strand
is destroyed, the the uninvoked handlers are destroyed. The documentation states:
Uninvoked handler objects that were scheduled for deferred invocation on the
io_service
, or any associatedstrand
, are destroyed.
To go into a bit more detail, a strand implementation is responsible for queuing handlers and guaranteeing that only one of its handlers have been posted to an io_service
at a time, and a strand
only provides a public API that delegates to the strand implementation. Each strand
is associated with a strand implementation, and a strand implementation may be associated with many strand
s. This relationship allows for a single strand implementation to be shared by many different strand
objects. Hence, the documentation remarks:
The implementation makes no guarantee that handlers posted or dispatched through different strand objects will be invoked concurrently.
Boost.Asio controls the lifetime of these strand implementations, and lazily allocates them within a fixed size pool of strand implementations. The size of the pool can be configured by defining BOOST_ASIO_STRAND_IMPLEMENTATIONS
to the desired number. As the lifetime of a strand
object does not affect the lifetime of the strand implementation, asynchronous operations do not need to concern themselves with the lifetime of the strand
in which the handler was wrapped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With