Boost:是否有一个类似于interprocess :: message_queue的机制,用于纯线程通信?

时间:2013-10-24 20:57:25

标签: c++ multithreading boost

boost :: interprocess :: message_queue机制似乎主要是为此而设计的:进程间通信。

问题是它序列化了消息中的对象:

“消息队列只是在进程之间复制原始字节,不发送对象。”

这使得它完全不适合传递大型复合对象的快速和重复的线程间通信。

我想创建一个带有ref / shared_ptr /指针的消息,该指针指向已知且先前创建的对象,并将其安全地从一个线程传递到下一个线程。

你可以使用asio :: io_service并使用绑定完成进行发布,但这是相当笨拙的并且要求所讨论的线程使用asio,这看起来有点奇怪。

我已经编写了自己的,遗憾的是基于asio :: io_service,但更愿意切换到支持boost的普通mechansim。

2 个答案:

答案 0 :(得分:2)

您需要一种为进程间通信而设计的机制,因为单独的进程具有单独的地址空间,除了非常空间的情况外,您不能简单地传递指针。对于线程通信,您可以使用标准容器(如std::stackstd::queuestd::priority_queue)在线程之间进行通信,您只需通过互斥锁提供正确的同步。或者你可以使用无锁的容器,这也是由boost提供的。你还需要什么才能进行线上交流?

答案 1 :(得分:2)

虽然我本身并不是Boost的专家,但是通过管道,消息队列等在进程和线程之间进行通信存在根本的困难,特别是如果假设程序的数据是包含动态分配内存的类(对于使用Boost编写的内容几乎就是这种情况;字符串不是像C语言中的简单对象...)。

在类中复制数据

消息队列和管道确实只是一种将字节集合从一个线程/进程传递到另一个线程/进程的方法。通常,当您使用它们时,您正在寻找目标线程以获得原始数据的副本,而不仅仅是数据引用的副本(它将指向原始数据)。

使用一个简单的C结构,根本不包含任何指针,它很容易; struct的副本包含所有数据,没问题。但是具有复杂数据类型(如字符串)的C ++类现在是一个包含对已分配内存的引用/指针的结构。复制 结构,但您实际上并没有将数据复制到已分配的内存中。

序列化的来源。对于进程间通信,其中两个进程通常可以共享相同的内存序列化,作为一种分配要发送的结构加上它引用的所有数据的方式。可以在另一端解压缩的字节流。对于线程,如果您不希望两个线程同时访问同一个内存,则没有什么不同。序列化是一种方便的方法,可以节省自己必须在类中导航以确切地查看需要复制的内容。

<强>效率

我不知道Boost用于序列化的内容,但显然序列化为XML会非常低效。像ASN.1 BER这样的二进制序列化会快得多。

此外,通过管道复制数据,消息队列不再像过去那样低效。传统上程序员不会这样做,因为感觉浪费了重复复制数据所花费的时间,只是为了与另一个线程共享它。使用单核心机器会涉及大量缓慢且浪费的内存访问。

然而,如果考虑一下&#34;内存访问&#34;在QPI,Hypertransport等的这些日子里,它与首先复制数据并没有太大的不同。在这两种情况下,它都涉及通过串行总线将数据从一个核心的存储器控​​制器发送到另一个核心的高速缓存。

今天的CPU实际上是NUMA机器,其内存访问协议分层在串行网络之上,以伪造SMP环境。通过管道,消息队列等复制消息的方式编程肯定会让人满意NUMA的想法,而且你根本不需要SMP。

此外,如果您将所有线程间通信都作为消息队列进行,那么它们与管道并没有太大的不同,并且管道与网络套接字的区别也不大(至少那些不同) Not-Windows上的案例)。因此,如果您仔细编写代码,最终可能会得到一个程序,该程序可以通过分布式计算机网络或单个进程中的多个线程进行重新部署。这是一种获得可扩展性的好方法,因为当您向上扩展时,您并没有以任何重要方式改变程序的形状或感觉。

附带福利

根据所使用的序列化技术,可能会有一些附加优势。使用ASN.1,您可以指定一个消息模式,在该模式中可以设置消息内容的有效范围。例如,您可以说消息包含一个整数,并且它可以具有0到10之间的值。由不错的ASN.1工具生成的编码器和解码器将自动检查您发送或接收的数据是否满足该约束,如果没有,则返回错误。

如果像Google Protocol Buffers这样的其他连载器没有为您执行类似的约束检查,我会感到惊讶。

好处是,如果您的程序中存在错误并且您尝试发送超出规范的消息,则序列化程序将自动为您发现该错误。这可以节省大量的调试时间。如果您共享内存缓冲区并使用信号量而不是使用消息队列来保护它,那么它肯定是您无法获得的。

<强> CSP

通信顺序进程和Actor模型基于通过消息队列,管道等发送数据副本,就像您正在做的那样。特别值得注意的是CSP,因为它是一种很好的方法,可以避免许多潜伏在源代码中未被发现的多线程软件的陷阱。

您可以使用一些CSP实现。有JCSP,一个Java类库和C ++ CSP,构建在Boost之上,为C ++做CSP。他们都来自肯特大学。

C ++ CSP看起来很有趣。它有一个名为csp :: mobile的模板类,它有点像Boost智能指针。如果您通过一个通道(CSP的消息队列字)将其中一个从一个线程发送到另一个线程,您将发送引用,而不是数据。但是,模板记录了哪些主题&#39;拥有&#39;数据。因此,接收移动设备的线程现在拥有数据(实际上没有移动),并且发送它的线程无法再访问它。因此,您可以获得CSP的好处,而无需复制数据的开销。

它看起来像C ++ CSP能够通过TCP进行通道;这是一个非常有吸引力的功能,向上扩展是一个非常简单的可能性。 JCSP也适用于网络连接。