你将如何在C ++中实现类似Erlang的发送和接收?

时间:2008-09-02 19:52:34

标签: c++ erlang

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

  • 如何实现模式匹配?
  • 如何实施send and receive(即演员模型)?

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

对于Actor model,有现有的实现,如ACT ++和Theron,但我找不到任何东西,只有前者的论文,而后者只是单线程< / strike> [见答案]。

就个人而言,我已经使用线程和线程安全的消息队列实现了actor。消息是类似哈希的结构,并与许多预处理器宏一起使用以实现简单的模式匹配。

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

(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

然而,这对我来说看起来有些苛刻,而且不是很强大。

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

7 个答案:

答案 0 :(得分:11)

  

对于Actor模型,有   现有的实现,如ACT ++   和塞隆,但我找不到   除了前者以外的任何论文,以及   后者只是单线程。

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

  

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

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

答案 1 :(得分:4)

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

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

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

如果你想要强大的消息传递,你可能最终想要序列化和反序列化内容。特别是对于类型安全。

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

虽然如果你不小心你最终得到管道上的xml:)

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

重新实现部件的问题是,您将无法获得良好的内聚库和解决方案。你已经不再像C ++那样的解决方案了。

答案 2 :(得分:4)

我目前正在为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);
    }

};

要创建一个新角色并启动它,您只需编写:

Acedia::spawn<SomeActor>();

虽然图书馆甚至没有到达beta体育场,但显示的片段仍然有效,我在其上运行了第一个应用程序。该库的一个主要目标是支持分布式编程(也可以通过网络)。

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

答案 3 :(得分:2)

您可以使用Qt的信号/插槽机制模仿行为,尤其是因为Qt的信号/插槽支持多线程。

答案 4 :(得分:0)

我肯定会对你的“acedia”图书馆感兴趣并愿意以任何方式提供帮助。 Erlang有一些很棒的结构,C ++肯定会受益于这样的库。

答案 5 :(得分:0)

今天我在sourceforge:https://sourceforge.net/projects/acedia/

寄宿图书馆

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

答案 6 :(得分:0)

今天,如果你想在C ++中使用erlang样式的强大演员,以及模式匹配, 也许Rust就是答案。

当OP在5年前问到这个问题时,当然并没有公开发表,截至2014年4月,它仍然不是v1.0 - 但它的进展非常好,并且肯定稳定,足够我认为语言核心是稳定的。

确定它不是C ++,但它与C ++具有相同的内存管理方法,除了它支持默认情况下没有共享内存的轻量级任务(然后提供用于共享的受控库功能 - &#34; Arc&#34; ); 它可以直接调用(并直接暴露)&#39; extern C&#39;功能。你不能用C ++共享模板化的库头 - 但你可以编写模仿C ++集合类的泛型(反之亦然)来传递对数据结构的引用。