我对Linux上的IPC机制有以下要求:

  • 有一个生产者过程,但有多个消费者过程。消费者过程不是生产者过程的子过程。他们是独立成长的。
  • 正在传输的消息是固定大小的POD结构。
  • 我们需要为此机制使用固定数量的内存。环形缓冲区之类的机制在这里似乎很理想。
  • 生产者需要运行得非常快,并且永远不能等待消费者。相反,它需要覆盖固定大小的缓冲区(用于IPC)中的条目,并且使用者需要检测到此问题,并通过跳过中间消息(在回绕的情况下)赶上生产者。
  • 消费者可以随时上下移动,并且在单一生产者和临时消费者上上下下之间不应有明确的握手。因此,当消费者上来时,他们只是从可用的最新消息中开始阅读,并在生产者不知情的情况下,随时随地下来。

  • 我现在有以下解决方案:
  • 我正在创建一个固定大小条目的环形缓冲区,该缓冲区由一个进程写入并由许多进程读取。环形缓冲区建立在/tmp中的内存映射文件的顶部。
  • 环形缓冲区代码使生产者从不阻塞等待任何使用者使用条目的过程。取而代之的是,消费者在读取/处理条目的中间检测到环形缓冲区何时缠绕起来,并追上最新的。我用几个生产者序列来做。如果需要,我可以对此进行扩展,但似乎并没有太大关系。因此,生产者全速奔跑,而落后的消费者则检测到中间读取损坏,并跳至最新条目。

  • 截至目前,该方法工作正常。现在,我试图弄清楚如何向混合中添加一些信号,以便消费者不必旋转读取生产者序列来等待新消息。对于信令部分,我还有一些其他要求:
  • 信令需要某种广播机制。这是从一个生产者/多个消费者的要求出发的。因此,当生产者发出信号时,应该能够唤醒多个过程。鉴于生产者不了解任何消费者,似乎我们需要某种命名资源来进行此信号传递。
  • 信令机制需要与其他常规信号可组合,可以使用select/epoll_wait等待。正在从此IPC机制/ring_buffer读取的使用者正在等待对其他不相关的管道/套接字等的写入,并且他们在这些FD上使用了select。理想的是能够仅通过这种机制来产生FD,而消费者可以将其添加到他们的选择 call 中。同样,如果使用者正在等待多个这样的ring_buffers,我们需要能够阻塞所有它们,并在它们中的任何一个发出信号时立即唤醒。

  • 考虑到这些要求,我消除了一些选择:
  • 条件变量:我们不能阻止来自使用者的多个变量。它们也不是selectable
  • 命名管道:每个消费者都需要一个命名管道,这意味着我们要避免某种生产者/消费者握手。
  • eventfd:eventfds未命名,因此似乎仅当信号在父进程和子进程之间时才作为解决方案。我的方案具有独立启动的流程。
  • Unix域套接字:这里似乎没有任何广播工具,因此,我不确定如果没有每个消费者的显式套接字,这是否可以工作。这违反了无握手要求。

  • 我有点茫然,看不到任何其他好的选择。在我看来,UDP多播似乎可以工作。使用者都可以成为多播组的一部分(使用SO_REUSEADDR创建套接字),唯一的生产者可以在该组上发送消息以向使用者发出信号。但是,这似乎确实很沉重和详尽。还有其他好的机制可以实现这一目标吗?我愿意直接使用Futex API(只要有帮助),只要它可以使用select/epoll阻止其他不相关的FD。

    最佳答案

    我建议发送信号,通过的DBus。当您可以使用已经可以满足您需求的成熟框架时,为什么还要推出自己的IPC?

    此页面应该让你开始:

    https://dbus.freedesktop.org/doc/dbus-tutorial.html

    最后,它包括链接到Qt和GLib库的API。我都没有用过,而是用我自己的基于Boost.ASIO的包装器来包装低级API,尽管这是一项相当艰巨的任务。

    https://dbus.freedesktop.org/doc/api/html/

    顺便说一句,要发送二进制数据块,您需要在消息中附加DBUS_TYPE_ARRAY类型为DBUS_TYPE_BYTE的arg。需要注意的是DBUS_TYPE_STRING不能包含零个字节或无效的Unicode序列。

    更新:最近引起我注意的另一个库称为sd-bus。这里有一个很好的概述和教程:

    http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html

    关于c++ - 在Linux上广播IPC,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42239568/

    10-13 02:05