c++中Linux线程间的高性能消息传递

linux high performance message passing between threads in c++

本文关键字:高性能 消息传递 线程 Linux c++      更新时间:2023-10-16

假设我有一个进程产生2个线程

第一个线程在一个紧循环中监听UDP端口上的数据包事件。第二个线程是接收这个UDP包中包含的字节,并解析它/做一些事情。

谁能推荐一种比使用Linux消息队列更快的方法?我认为它们很慢,因为它们在写入队列时复制字节,在从队列 读取时再次复制字节。

我知道zeromq库,但有没有一种圆滑的方法来做到这一点,而没有这种开销?我意识到我可以在两个线程之间使用tcp/ip套接字进行简单的排队通信,但是有更快的方法吗?

我想也许是一个环缓冲区在内存之间的线程和互斥锁用来控制指针到最近更新的元素之间共享?

有人有什么想法吗?

我能想到的最有效的方法是使用一个链表、一个互斥锁和一个条件变量:

  • 线程A:

    1. 分配一个UDP -packet-buffer对象(该对象应包含previousnext指针,以及用于存储UDP数据的字节数组)
    2. recv() UDP数据到对象的字节数组
    3. 锁定互斥锁
    4. 将udp-packet-buffer对象附加到链表的尾部
    5. 解锁互斥锁
    6. 表示条件变量
    7. goto 1
  • 线程B:

    1. 等待条件变量(直到条件变量发出信号)
    2. 锁定互斥锁
    3. 将下一个udp-packet-buffer从链表的头部弹出
    4. 解锁互斥锁
    5. 解析/处理UDP -packet-buffer对象中的UDP数据
  • 删除udp-packet-buffer对象
  • goto 1

这给了你一个零拷贝通信机制。持有互斥锁所花费的时间是最小的,所以争用也应该很低。

如果你想进一步优化,你可以让线程B一次从链表中抓取所有的项目,而不是一次只弹出一个——这是可以在O(1)时间内用链表完成的。然后让线程A在添加最新的udp-packet-buffer对象之前,仅当链表为空时才通知条件变量。这将减少线程在重载时必须锁定/解锁/发出信号的次数。

当我来到这个页面时,这个非常好的答案也是我所期望的https://stackoverflow.com/a/8567548/2893944

一个可能有帮助的小注意事项:摆脱动态内存分配也是一个可以提高性能和避免内存碎片的点(例如:使用静态数组,使用内存池)。

(这应该是一个评论,但不够声誉)

checkout http://www.boost.org/libs/circular_buffer/我使用boost::array<1500>作为一个项目中2个线程之间的通信点,我看不出它在任何方面都很慢。其中第一个线程正在接受UDP包,并快速检查一些位是否应该将其放在缓冲区中。它可以复制进出,但当我配置文件时,它甚至不会显示。

编辑:BoundedBuffer示例是有趣的位http://www.boost.org/libs/circular_buffer/doc/circular_buffer.html#boundedbuffer

为了获得最佳性能,您需要固定大小、无锁、单写、单读的队列。

这篇代码项目文章出现在一个快速谷歌似乎合理,并解释了一些来龙去脉。

我不知道你的用例是什么-但是如果采取了这样一个冗长的措施-你的软件(和环境)需要考虑如何处理由缓慢的消费者引起的满队列将导致数据丢失的情况。