I'm currently trying to get my hands on boost::asio
strands. Doing so, I keep reading about "invoking strand post/dispatch
inside or outside a strand". Somehow I can't figure out how inside a strand differs from through a strand, and therefore can't grasp the concept of invoking a strand function outside the strand at all.
Probably there is just a small piece missing in my puzzle. Can somebody please give an example how calls to a strand can be inside or outside it?
What I think I've understood so far is that posting something through a strand would be
m_strand.post(myfunctor);
or
m_strand.wrap(myfunctor);
io_svc.post(myfunctor);
Is the latter considered a call to dispatch
outside the strand (as opposed to the other being a call to post
inside it)? Is there some relation between the strand's "inside realm" and the threads the strand operates on?
If being inside a strand simply meant to invoke a strand's function, then the strand
class's documentation would be pointless. It states that strand::post
can be invoked outside the strand... That's precisely the part I don't understand.
/strænd/ a fiber or group of fibers twisted together that form one part of a length of rope, cord, thread, etc., or a single string, hair, or line of objects: a strand of hair.
A single hair, a noodle, even a line of thought — any of these things could be called a strand, a long thin length of something. The noun strand describes things that are long and thin like a rope, or a strand of spaghetti, hair, or thread.
countable noun. A strand of something such as hair, wire, or thread is a single thin piece of it.
strand - a poetic term for a shore (as the area periodically covered and uncovered by the tides)
Even I had some trouble in understanding this concept, but became clear once I started working on libdispatch
. It helped me map things with asio
better.
Now lets see how to make some sense out of strand
. Consider strand
as a serial queue of handlers
which needs to be executed.
Now, where does these handlers get executed ? Within the worker
threads.
Where did these worker threads come from ? From the io_service
object you passed while creating the strand.
Something like:
asio::strand s(io_serv_obj);
Now, as you must be knowing, the io_service::run
can be called by a single thread or multiple threads. The threads calling the run
method of the io_serv_obj
are the worker threads for that strand in our case. So, it could be either single threaded or multithreaded.
Coming back to strands, when you post
a handler, that handler is always enqueued in the serial queue which we talked about. The worker threads will pick up the handler from the queue one after the other.
Now, when you do a dispatch
, asio does some optimization for you:
io_service
instance). When it is called outside the current execution context of the strand, thats when it is called outside the strand
. So, in the outside
case, the dispatch will just enqueue the handler like post
when there are other handlers waiting in the queue or will call it directly when it can guarantee that it will not be called concurrently with any other handler from that queue that may be running in one of the worker threads at that moment.UPDATE:
As noted in the comments section, inside
means called within another handler
i.e for eg: I posted a handler A
and inside that handler, I am doing a dispatch
of another handler. Now, as would be explained in #2, if there are no other handlers waiting in the strands serial queue, the dispatch handler will be called synchronously. If this condition is not met, that means, the dispatch
is called from outside
.
dispatch
from outside
of the strand i.e not within the current execution context, asio checks its callstack
to see if any other handler present in its serial queue is running or not. If not, then it will directly call that handler synchronously. So, there is no cost of enqueueing the handler (I think no extra allocation will be done as well, not sure though).Lets see the documentation link now:
s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand
This means that, if dispatch
was called from some outside the current run
OR there are other handlers already enqueued, then it needs to enqueue the handler, it just cannot call it synchronously. Since its a serial queue, a
will get executed before b
.
Had there been another call s.dispatch(c)
along with a and b but before a
and b
(in the mentioned order) enqueued, then c
will get executed before a
and b
, but in no way b
can get executed before a
.
Hope this clears your doubt.
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