2017-02-15 96 views
2

我有在Linux上的IPC机制以下要求:广播IPC在Linux上

  1. 有一个单一的生产过程,但多消费者的过程。消费者流程不是生产者流程的子女。他们是独立培养的。

  2. 正在传输的消息是固定大小的POD结构。

  3. 我们需要为此机制使用固定数量的内存。像这样的环形缓冲器看起来很理想。

  4. 生产者需要运行得非常快,永远不能等待消费者。相反,它需要覆盖固定大小缓冲区中的条目(对于IPC),并且消费者需要检测这个问题,并且在环绕时跳过中间消息赶上生产者。

  5. 消费者可以随时上来下来,单一生产者和短暂消费者之间应该没有明确的握手。因此,当消费者出现时,他们就开始从最新的消息中读取消息,并在他们想要的时候下降,而不需要生产者知道。

我有以下解决方案现在:

  1. 我创建由一个进程写入和读出许多固定大小的条目的环形缓冲区。环形缓冲区构建在/ tmp中的内存映射文件之上。

  2. 环形缓冲区代码是这样的,生产者永远不会阻止等待任何消费者使用条目。相反,消费者会在阅读/处理一个条目时检测环形缓冲区是什么时候缠绕的,并且赶上最新的。我用几个生产者序列来做。如果需要,我可以对此进行扩展,但似乎并不相关。因此,生产商全速奔驰,而落后的消费者发现中期腐败现象并跳至最新条目。

截至目前这工作正常。现在我正试图弄清楚如何在混音中添加一些信号,以便消费者不必旋转阅读等待新消息的制作人序列。我对信令部分有一些额外的要求:

  1. 信令需要是某种广播机制。这来自一个生产者/多个消费者的要求。因此,当生产者发出信号时,多个流程应该能够被唤醒。鉴于生产者不了解任何消费者,似乎我们需要某种指定资源来执行此信令。

  2. 信令机制需要与可以使用select/epoll_wait等待的其他常规信号组合。从这个IPC机制/ ring_buffer读取的消费者正在等待写入其他不相关的管道/套接字等,并且他们在这些FD上使用select。如果能够从这个机制中产生一个消费者可以添加到他们选择的呼叫中的FD,这将是理想的。同样,如果消费者正在等待多个这样的ring_buffers,我们需要能够阻止所有这些ring_buffers,并在它们中的任何一个发出信号时立即唤醒。

考虑到这些要求,我消灭了几个选项:

  1. 条件变量:我们不能对这些多从消费者的封锁。它们也不是selectable

  2. 命名管道:我们需要为每个消费者命名一个管道,这意味着我们要避免某种生产者/消费者握手。

  3. eventfd:eventfd没有命名,因此如果信号在父进程和子进程之间,那么它们似乎只是一个解决方案。我的场景有独立启动的进程。

  4. Unix域套接字:在这里似乎没有任何广播设备,所以我不确定这是否会在没有每个消费者的显式套接字的情况下工作。这违背了没有握手的要求。

我有点亏了,没有看到其他好的选择。对我来说,似乎UDP多播可能会起作用。消费者都可以是多播群组的一部分(创建套接字为SO_REUSEADDR),唯一的生产者可以在该群组上发送消息来向消费者发送信号。但是这看起来真的很重和精细。有没有其他的好机制可以做到这一点?我愿意直接与Futex API一起工作,只要它有助于使用select/epoll阻塞其他不相关的FD。

回答

1

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

本页面应该让你开始:

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

最后,它包括链接到Qt和GLib库的API。我既没有用过,也没有用低级API编写我自己的基于Boost.ASIO的包装器,尽管这是一个相当复杂的工作。

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

BTW,用于发送二进制数据块,你要追加型的DBUS_TYPE_BYTEDBUS_TYPE_ARRAY的阿根廷,给您的消息。请注意,DBUS_TYPE_STRING不能包含零字节或无效的Unicode序列。

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

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