qi::Actor and qi::Strand¶
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.
Summary¶
class qi::Actor
Functions (class qi::Actor)
class qi::Strand
Functions (class qi::Strand)
Global Classes
Detailed Description¶
Strand Usage¶
A Strand
works exactly as an event loop:
#include <qi/strand.hpp>
qi::Strand strand(*qi::getEventLoop());
qi::Future<void> future = strand.async(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.
Actor Usage¶
You can make a single threaded object by inheriting from Actor
. 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.
#include <qi/actor.hpp>
class MyActor : public Actor
{
public:
void myFunction(const std::string& str);
};
// works with type-erasure
QI_REGISTER_OBJECT(MyActor, myFunction);
// works with futures
future.connect(&MyActor::myFunction, myActor, "my string");
// works with signals
signal.connect(&MyActor::myFunction, myActor, _1);
// works with type-erased signal/property connections
// (work is in progress to simplify the syntax)
myObject.connect("mySignal", myActor.strand()->schedulerFor<void(std::string)>(&MyActor::myFunction, myActor, _1));
// works with periodic tasks
periodicTask.setCallback(&MyActor::myFunction, myActor, _1);
// works with async calls
qi::async(&MyActor::myFunction, myActor, "my string", qi::Seconds(1));
Warning
When connecting your object, do not use bind
functions. 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"));
It is possible to inherit both from Actor
and Trackable
as an Actor is not
Trackable by default.
Reference¶
qi::Strand Class Reference¶
Public Functions¶
-
()Strand
-
(qi::ExecutionContext& executionContext)Strand
-
()~Strand
-
void
(const boost::function<void()>& callback)post
-
qi::Future<void>
(const boost::function<void()>& cb, qi::SteadyClockTimePoint tp)async
-
qi::Future<void>
(const boost::function<void()>& cb, qi::Duration delay)async
-
bool
()isInThisContext
Detailed Description¶
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.
Function Documentation¶
-
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
()¶ Destroys the strand
This will wait for all scheduled tasks to finish
-
void
qi::Strand::
post
(const boost::function<void()>& callback)¶ post a callback to be executed as soon as possible
-
qi::Future<void>
qi::Strand::
async
(const boost::function<void()>& cb, qi::SteadyClockTimePoint tp)¶ call a callback asynchronously to be executed on tp
-
qi::Future<void>
qi::Strand::
async
(const boost::function<void()>& cb, qi::Duration delay = qi::Duration(0)¶ call a callback asynchronously to be executed in delay
qi::Actor Class Reference¶
Public Functions¶
Detailed Description¶
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.