Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What if when the destructor of a asio::strand is called, there are still some ready/unready handlers on this strand?

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?

like image 431
updogliu Avatar asked May 23 '14 06:05

updogliu


1 Answers

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 strands 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 associated strand, 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 strands. 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.

like image 171
Tanner Sansbury Avatar answered Nov 13 '22 08:11

Tanner Sansbury