【问题标题】:How would you implement Erlang-like send and receive in C++?你将如何在 C++ 中实现类似 Erlang 的发送和接收?
【发布时间】:2010-09-07 14:42:45
【问题描述】:

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

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

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

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

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

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

(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

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

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

【问题讨论】:

    标签: c++ erlang


    【解决方案1】:

    关于Actor模型,有 现有的实现,如 ACT++ 还有塞隆,但我找不到 除了关于前者的论文,还有 后者仅是单线程的。

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

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

    Theron 就是这样实现的.. :-)

    【讨论】:

    • 说实话,我不知道为什么我认为 Theron 是单线程的。重新阅读该网站并没有给我那种印象。对于造成的混乱,我深表歉意,我认为如果我再给 Theron 一次机会,那将是公平的!
    • 在 Matlab mex 文件中使用 Theron 实现 Actors 并发的愉快体验。
    【解决方案2】:

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

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

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

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

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

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

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

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

    【讨论】:

      【解决方案3】:

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

      一个小sn-p:

      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”;这意味着您只想匹配类型。

      这当然是一个小sn-p。您也可以像在 Scala 中一样使用“案例类”。它们可与 erlang 中的“原子”相媲美。下面是一个更详细的例子:

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

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

      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 体育场,但所示的 sn-ps 工作正常,而且我有第一个应用程序在上面运行。该库的一个主要目标是支持分布式编程(也跨网络)。

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

      【讨论】:

      • 我很感兴趣;它看起来很不错。有没有可以下载图书馆/查看文档的网站?你会开源吗?
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-10-04
            • 2021-05-28
            • 1970-01-01
            • 1970-01-01
            • 2016-03-19
            • 2021-02-22
            • 2018-02-15
            • 1970-01-01
            相关资源
            最近更新 更多