Discussion:
[asio-users] strands - order of handler invocation
Hannes Wengenroth
2012-06-29 08:15:58 UTC
Permalink
Hi,

I'm making heavy use of strands for my project and stumbled over an implementation detail that I was unaware of.

I was relying on the order guarantees outlined in the docs (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/io_service__strand.html)
As far as I can see the call stack for immediate execution is based on the (shared) impl_ pointer of the strand, not on the object itself. So when the documentation says "performed outside the strand" it precisely means "performed outside any strand with the same implementation" (or, for practical purposes: "outside of any strand at all")

Did I get that right and is this the intended behavior? (ie in favor of dispatch performance)
If so, I think it would be nice to update the docs to be more explicit about what "performed outside the strand" actually means.

I've added a simplified example of my confusion below.

Cheers,
Hannes



void foo(const char * _pStr)
{
printf(_pStr);
}

void bar(boost::asio::strand& _rStrand)
{
_rStrand.post(boost::bind(&foo, "first"));
_rStrand.dispatch(boost::bind(&foo, "second"));
}

void main()
{
boost::asio::io_service ios;
boost::asio::strand A(ios);
boost::asio::strand B(ios);

bar(A); //order guaranteed

B.dispatch(boost::bind(&bar, A)); //order will be reversed if A and B share their implementation
}
Hannes Wengenroth
2012-08-21 15:43:03 UTC
Permalink
For what it's worth - or anyone with a similar use case:
(I guess most users don't rely on order of execution and then dispatch and post from inside different strands...)

I ended up wrapping all dispatch calls and using call_stack<boost::asio::strand> to achieve the behavior I was expecting.
It's very intrusive but I had a wrapper in place anyway...
This way I have dispatch&post execution order guarantees on a strand object basis.

Cheers,
Hannes


typedef boost::asio::detail::call_stack<boost::asio::strand> CStrandStack;

#define ASIO_STRAND_CONTEXT(_Strand) CNB::CStrandStack::context _ssc(&##_Strand);

#define ASIO_STRAND_DISPATCH(_Strand, _ObjPtr, _Func, ...) \
if(CNB::CStrandStack::contains(&_Strand)) \
_ObjPtr->##_Func(__VA_ARGS__); \
else \
_Strand##.post( boost::bind(&_Func, _ObjPtr, __VA_ARGS__) );

class ClassA
{
public:
void foo()
{
ASIO_STRAND_DISPATCH(m_Strand, this, &foo_stranded);
}
private:
void foo_stranded()
{
ASIO_STRAND_CONTEXT(m_Strand)
//do stuff
}
boost::asio::strand m_Strand;
};



Von: Hannes Wengenroth
Gesendet: Freitag, 29. Juni 2012 10:16
An: asio-***@lists.sourceforge.net
Betreff: [asio-users] strands - order of handler invocation

Hi,

I'm making heavy use of strands for my project and stumbled over an implementation detail that I was unaware of.

I was relying on the order guarantees outlined in the docs (http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/io_service__strand.html)
As far as I can see the call stack for immediate execution is based on the (shared) impl_ pointer of the strand, not on the object itself. So when the documentation says "performed outside the strand" it precisely means "performed outside any strand with the same implementation" (or, for practical purposes: "outside of any strand at all")

Did I get that right and is this the intended behavior? (ie in favor of dispatch performance)
If so, I think it would be nice to update the docs to be more explicit about what "performed outside the strand" actually means.

I've added a simplified example of my confusion below.

Cheers,
Hannes



void foo(const char * _pStr)
{
printf(_pStr);
}

void bar(boost::asio::strand& _rStrand)
{
_rStrand.post(boost::bind(&foo, "first"));
_rStrand.dispatch(boost::bind(&foo, "second"));
}

void main()
{
boost::asio::io_service ios;
boost::asio::strand A(ios);
boost::asio::strand B(ios);

bar(A); //order guaranteed

B.dispatch(boost::bind(&bar, A)); //order will be reversed if A and B share their implementation
}

Loading...