A Strand
allows one to schedule asynchronous work with the guarantee that two
tasks will never be executed in parallel. This is useful to avoid data races,
mutexes, and deadlocks.
An Actor
receives messages and processes them. Basically, it’s just an object
containing a Strand
so that all asynchronous work it receives will be
executed sequentially.
Global Classes
class qi::Actor
Functions (class qi::Actor)
class qi::Strand
Functions (class qi::Strand)
A Strand
works exactly as an event loop:
#include <qi/strand.hpp>
qi::Strand strand(*qi::getEventLoop());
qi::Future<void> future =
strand.asyncDelay(myfunction, qi::MilliSeconds(100));
// you can now cancel future
future.cancel();
// and/or wait for it
future.wait();
A strand’s destructor will block until all work scheduled is finished or cancelled. You must not schedule any work when the strand is being destroyed.
The event loop must not be destroyed before all strands associated to it are destroyed.
To make a single threaded object, you must inherit from Actor
. Then, make sure
you call strand()->join()
in your destructor. All work scheduled on that
object will be executed on a single thread so that there will never be more than
one call in parallel, and no more work will be executed after the join()
call.
#include <qi/actor.hpp>
class MyActor : public Actor
{
public:
~MyActor()
{
strand()->join();
}
void myFunction(const std::string& str);
};
// works with type-erasure
QI_REGISTER_OBJECT(MyActor, myFunction);
// works with futures
future.connect(qi::bind(&MyActor::myFunction, myActor, "my string"));
// works with signals
signal.connect(qi::bind(&MyActor::myFunction, myActor, _1));
// works with type-erased signal/property connections
myObject.connect("mySignal",
boost::function<void(std::string)>(
// you need the MetaCallType_Direct to have ordering guarantees
qi::bind(&MyActor::myFunction, myActor, _1)), MetaCallType_Direct);
// works with periodic tasks
periodicTask.setCallback(qi::bind(&MyActor::myFunction, myActor, _1));
// works with async calls
qi::asyncDelay(qi::bind(&MyActor::myFunction, myActor, "my string"),
qi::Seconds(1));
Warning
When connecting your object, do not use boost::bind
. This code does
not provide single threaded guarantees:
// *NOT* single threaded
future.connect(boost::bind(&MyActor::myFunction, myActor, "my string"));
Calling the object directly does not provide these guarantees either:
// *NOT* single threaded
myActor.myFunction("my string");
Same thing when scheduling directly on the main eventloop.
// *NOT* single threaded
qi::getEventLoop()->async(boost::bind(&MyActor::myFunction, myActor,
"my string"));
To have your calls scheduled on the strand, use qi::bind
.
It is not possible to inherit both from Actor
and Trackable
because an Actor
has the same behavior as Trackable.
You must call strand()->join()
at the beginning of your destructor. This
will ensure that no more function is called on your class (similar to
Trackable::destroy()
). We recommend that you write your destructor in a
synchronous manner, with future.value()
.
Strand
()Strand
(qi::ExecutionContext& executionContext)~Strand
()join
()async
(const boost::function<void()>& cb, qi::SteadyClockTimePoint tp)async
(const boost::function<void()>& cb, qi::Duration delay)isInThisContext
()schedulerFor
(F&& func, boost::function<void()> onFail)Class that schedules tasks sequentially
A strand allows one to schedule work on an eventloop with the guaranty that two callback will never be called concurrently.
Methods are thread-safe except for destructor which must never be called concurrently.
qi::Strand::
Strand
()¶Construct a strand that will schedule work on the default event loop.
qi::Strand::
Strand
(qi::ExecutionContext& executionContext)¶Construct a strand that will schedule work on executionContext.
qi::Strand::
~Strand
()¶Call detroy()
qi::Strand::
join
()¶Joins the strand
This will wait for currently running tasks to finish and will drop all tasks scheduled from the moment of the call on. A strand can’t be reused after it has been join()ed.
It is safe to call this method concurrently with other methods. All the returned futures will be set to error.
qi::Strand::
async
(const boost::function<void()>& cb, qi::SteadyClockTimePoint tp)¶call a callback asynchronously to be executed on tp Deprecatedsince 2.5
qi::Strand::
async
(const boost::function<void()>& cb, qi::Duration delay)¶call a callback asynchronously to be executed in delay Deprecatedsince 2.5
qi::Strand::
isInThisContext
()¶Brief:
Returns: | true if current code is running in this strand, false otherwise. If the strand is dying (destroy() has been called, returns false) |
---|
qi::Strand::
schedulerFor
(F&& func, boost::function<void()> onFail = {})¶Class that represents an actor.
Inherit from this class if you want your class to be an actor (as in the actor model). This means that your class will receive “messages” and not be called. In other words, there will never be to calls to your object in parallel, they will be queued.
()
()
qi::Actor::
Actor
(qi::ExecutionContext& ec)¶()
qi::Actor::
strand
() const
¶()
()
()
()
qi::Actor::
joinTasks
()¶