其实这个问题好像有两部分:

  • 如何实现模式匹配?
  • 如何实施 发送和接收 (IE。演员模型)?

对于模式匹配部分,我一直在研究各种项目,例如 应用程序支柱. 。这些看起来相当不错,但无法让它们在 g++ 的最新版本 (4.x) 上工作。这 菲利克斯 语言似乎也很好地支持模式匹配,但它并不是真正的 C++。

至于 演员模型, ,现有的实现如 ACT++ 和 塞隆, ,但除了关于前者的论文之外我找不到任何东西, ,后者只是单线程的 [参见答案]。

就我个人而言,我使用线程和线程安全消息队列来实现参与者。消息是类似散列的结构,并将它们与许多预处理器宏一起使用来实现简单的模式匹配。

现在,我可以使用以下代码发送消息:

(new Message(this))
    ->set("foo", "bar")
    ->set("baz", 123)
    ->send(recipient);

下面进行简单的模式匹配(qDebugqPrintable 是 Qt 特定的):

receive_and_match(m)
    match_key("foo")    { qDebug("foo: %s", qPrintable(m->value("foo").toString())); }
    or_match_key("baz") { qDebug("baz: %d", m->value("baz").toInt()); }
    or_match_ignore
end_receive

然而,这对我来说看起来有点老套,而且不是很健壮。

你会怎么做?我错过了任何现有的工作吗?

有帮助吗?

解决方案

关于 erlang 的重要事情之一是如何使用这些功能来构建健壮的系统。

发送/接收模型是非共享的,并且是显式复制的。进程本身是轻量级线程。

如果您确实需要 erlang 模型的强大特性,那么最好使用真实的进程和 IPC 而不是线程。

如果您想要健壮的消息传递,尽管您可能最终想要序列化和反序列化内容。尤其是类型安全。

C++ 中的模式匹配并不总是很漂亮,但会有一个很好的模式 - 您最终将创建一个调度程序对象,它使用某种形式的多态性来获得您想要的内容。

尽管如果你不小心,你最终会在管道上得到 xml :)

真的,如果你想要 erlang 模型,你真的想使用 erlang。如果存在速度慢的情况,我相信您可以使用外部功能互联网来增强您的程序。

重新实现部件的问题是您不会获得良好的内聚库和解决方案。您已经拥有的解决方案看起来不再像 C++。

其他提示

至于Actor模型,有类似ACT ++和Theron等现有实现,但是除了前者的论文外,我什么都找不到,而后者仅是单线阅读。

作为 Theron 的作者,我很好奇你为什么相信它是单线程的?

就个人而言,我已经使用线程和线程安全消息队列实施了参与者

这就是塞隆的实施方式。:-)

我目前正在为 C++ 实现一个名为“acedia”的 actor 库(谷歌上还没有任何关于它的信息),它使用“类型匹配”。该库是我的硕士论文的一个项目,您可以用它向演员发送任何类型的数据。

一个小片段:

recipient.send(23, 12.23f);

在接收方,您可以像这样分析收到的消息:

Message msg = receive();
if (msg.match<int, float>() { ... }

...或者您可以定义一个规则集来为您调用函数或方法:

void doSomething(int, float);

InvokeRuleSet irs;
irs.add(on<int, float>() >> doSomething);
receiveAndInvoke(irs);

也可以同时匹配类型和值:

Message msg = receive();
if (msg.match<int, float>(42, WILDCARD) { ... }
else if (msg.match<int, float>() { ... }

常量“WILDCARD”意味着任何值都将被接受。不传递任何参数等于将所有参数设置为“WILDCARD”;这意味着您只想匹配类型。

这当然是一个小片段。您还可以像 Scala 中一样使用“案例类”。它们相当于 erlang 中的“原子”。这是一个更详细的示例:

ACEDIA_DECLARE_CASE_CLASS(ShutdownMessage)
ACEDIA_DECLARE_CASE_CLASS(Event1)
ACEDIA_DECLARE_CASE_CLASS(Event2)

要对定义的案例类做出反应,您可以编写一个像这样的参与者:

class SomeActor : public Actor
{

  void shutdown() { done = true; }
  void handleEvent1();
  void handleEvent1();

  public:

    SomeActor() : done(false) { }

    virtual void act()
    {
      InvokeRuleSet irs;
      irs
        .add(on<ShutdownMessage>() >> method(&SomeActor::shutdown))
        .add(on<Event1>() >> method(&SomeActor::handleEvent1))
        .add(on<Event2>() >> method(&SomeActor::handleEvent2))
      ;
      while (!done) receiveAndInvoke(irs);
    }

};

要创建一个新的 Actor 并启动它,您只需编写以下内容:

Acedia::spawn<SomeActor>();

尽管该库甚至还没有达到测试阶段,但显示的片段可以工作,并且我在其上运行了第一个应用程序。该库的主要目标之一是支持分布式编程(也可以跨网络)。

你的问题是不久前提出的,但如果你对此感兴趣:让我知道!:)

您可以使用 Qt 的信号/槽机制来模拟行为,特别是因为 Qt 的信号/槽支持多线程。

我肯定有兴趣查看您的“acedia”图书馆,并愿意尽我所能提供帮助。Erlang 有一些很棒的构造,C++ 绝对可以从这样的库中受益。

今天我在 sourceforge 托管该库: https://sourceforge.net/projects/acedia/

正如我之前所说,这是一个早期版本。但请随意批评它!

今天,如果您想要C ++的Erlang风格强大的演员,并且模式匹配,则可能是Rust的答案。

当然,当 OP 约 5 年前询问时,这还没有公开,截至 2014 年 4 月,它仍然不是 v1.0 - 但它进展得很好并且绝对稳定,足够的语言核心是稳定的我思考。

好吧,它不是 C++,但它具有与 C++ 相同的内存管理方法,除了它默认支持没有共享内存的轻量级任务(然后提供用于共享的受控库功能 - “Arc”);它可以直接调用(并直接公开)“extern C”函数。您不能与 C++ 共享模板化库标头 - 但您可以编写模仿 C++ 集合类的泛型(反之亦然)来传递对数据结构的引用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top