10

实际上,这个问题似乎有两个部分:

  • 如何实现模式匹配?
  • 如何实现发送和接收(即Actor模型)?

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

至于Actor 模型,有 ACT++ 和Theron之类的现有实现,但除了前者的论文,我找不到任何东西,而后者只是单线程的[见答案]。

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

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

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

以下是做简单模式匹配的(qDebug并且qPrintable是 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

但是,这对我来说看起来有点骇人听闻,而且不是很健壮。

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

4

7 回答 7

10

至于 Actor 模型,有 ACT++ 和 Theron 之类的现有实现,但我找不到任何关于前者的论文,而后者只是单线程的。

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

就个人而言,我已经使用线程和线程安全的消息队列实现了演员

这就是塞隆的实现方式.. :-)

于 2008-10-08T22:17:26.050 回答
4

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

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

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

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

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

虽然如果你不小心,你最终会在管道上使用 xml :)

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

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

于 2008-09-02T20:49:18.967 回答
3

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

一个小片段:

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>();

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

您的问题是不久前提出的,但如果您对此感兴趣:请告诉我!:)

于 2009-05-26T20:14:00.583 回答
2

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

于 2010-11-10T00:29:37.650 回答
0

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

于 2009-05-30T04:52:44.390 回答
0

今天我在 sourceforge 托管图书馆:https ://sourceforge.net/projects/acedia/

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

于 2009-06-08T20:06:58.887 回答
0

今天,如果你想要在 C++ 中使用 erlang 风格的健壮演员和模式匹配,也许 Rust 就是答案。

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

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

于 2014-04-17T08:01:26.713 回答