了解 stateful_actor

Understanding the stateful_actor

我在examples/curl/curl_fuse.cpp and libcaf_core/test/stateful_actor.cpp下阅读了stateful_actor的一些用法。看起来 stateful_actor<State> 可以通过在 State struct 中声明字段来为 actor 绑定一些状态。这非常有用。

我们可以将状态声明为 class-based actor 中的字段以获得相同的效果吗?或者在 stateful_actor 中有一些特殊处理(例如线程安全访问)?

以下示例中的参与者是否提供相同的功能?

/* 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 the stateful_actor (e.g. thread-safety access) ?

CAF 的运行时假定 actor 是隔离的,即只允许 actor 本身访问其状态。因此,对参与者状态的访问永远不会同步。参与者间通信使用消息传递,从而通过设计避免竞争条件。

Stateful actor 允许程序员编写更少的 类(因此更少的样板代码),但是 ClassCounterStatefulCounter 之间也有一个显着的区别:变量的生命周期。在ClassCounter中,成员变量i一直存在,直到ClassCounter的析构函数被调用。由于 actor 是引用计数的,如果没有留下对它的引用,则析构函数将运行,即,不存在 actor 的 actoractor_addr 句柄。在 StatefulCounter 中,如果 actor 初始化并销毁,则构造 CounterState 成员。

只要演员还活着,状态就存在。这对于中断循环特别有用。如果你有两个演员 AB,如果 A 通过成员变量持有对 B 的引用,你就有了一个循环,反之亦然。使用有状态的 actor 可以打破这个循环。 A 将在退出时自动释放对 B 的引用,反之亦然。