I've read the some usage of stateful_actor under examples/curl/curl_fuse.cpp and libcaf_core/test/stateful_actor.cpp. It looks like the stateful_actor<State>
can bind some states for actor by declaring fields in State struct
. It is very useful.
Can we declare the states as fields in class-based actor
to get the same effects? Or there is some special handling in the stateful_actor
(e.g. thread-safety access) ?
Do the actors in the following example provide the same functionality?
/* Class based actor */
struct ClassCounter : caf::event_based_actor
{
caf::behavior make_behavior() override {
return {
[=](inc_atom){ i += 1; }
, [=](ret_atom){ return i; }
};
}
const char* name() const override { return "I am class-based"; }
int i = 0;
};
/* Stateful actor */
struct CounterState
{
caf::local_actor* self;
int i = 0;
const char* name = "I am stateful";
};
caf::behavior StatefulCounter(caf::stateful_actor<CounterState>* self)
{
return {
[=](inc_atom){ self->state.i += 1; }
, [=](ret_atom){ return self->state.i; }
};
};
Can we declare the states as fields in
class-based actor
to get the same effects? Or there is some special handling in thestateful_actor
(e.g. thread-safety access) ?
The runtime of CAF assumes actors to be isolated, i.e., only an actor itself is allowed to access its state. Hence, access to the state of an actor is never synchronized. Inter-actor communication uses message passing, thus avoiding race conditions by design.
Stateful actors allow programmers to write less classes (and thus less boilerplate code), but there is also one notable difference between ClassCounter
and StatefulCounter
: lifetime of variables. In ClassCounter
, the member variable i
lives until the destructor of ClassCounter
is called. Since actors are reference counted, the destructor runs if no reference to it is left, i.e., no actor
or actor_addr
handle to the actor exists. In StatefulCounter
, the CounterState
member is constructed if the actor is initialized and destroyed if it terminates.
The state only exists as long as an actor is alive. This is particularly useful for breaking cycles. If you have the two actors A
and B
, you have a cycle if A
holds a reference to B
via a member variable and vice versa. Using stateful actors instead breaks this cycle. A
will release its reference to B
automatically on exit and vice versa.
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