何时使用管道,何时使用共享内存?(这是一个提问标题,无需回答)

46

我正在阅读有关各种IPC机制的资料。我试图找出使用共享内存和命名管道(FIFO)的场景。

管道: 多个进程可以写入,但只有一个进程可以读取。写操作是原子的。

共享内存: 多个进程可以读写。用户需要为读写提供互斥。

这是使用共享内存和管道的唯一区别吗?


5
请注意,仅当写入的大小不大于PIPE_BUF时,写操作才是原子性的。 - William Pursell
1个回答

73

本质上,管道 - 无论是命名的还是匿名的 - 就像消息传递一样使用。某人向接收者发送信息,接收者可以接收它。共享内存更像发布数据 - 某人将数据放入共享内存中,读者(可能很多)必须使用同步,例如通过信号量来了解有新数据的事实,并且必须知道如何读取内存区域以查找信息。

对于管道,同步是简单的,并且内置于管道机制本身中-当发生有趣的事情时,您的读取和写入将冻结和解冻应用程序。对于共享内存,更容易异步工作并仅偶尔检查新数据-但代价是更复杂的代码。此外,你可以得到多对多通信,但又需要更多的工作。而且,由于上述原因,基于管道的通信的调试比共享内存更容易。

一个小差异是:管道在文件系统中直接可见,而共享内存区域需要特殊工具(例如ipcs)进行管理,以防您创建了共享内存段,但您的应用程序死亡并且没有清理自己(同样适用于信号量和许多其他同步机制,您可能需要与共享内存一起使用)。

共享内存还可以让您更好地控制缓冲和资源使用-在操作系统允许的限制范围内,您决定分配多少内存以及如何使用它。对于管道,操作系统自动控制事物,因此再次失去了一些灵活性,但减轻了很多工作。

最重要的要点总结:管道用于一对一通信,编码较少且让操作系统处理事物;共享内存用于多对多通信,具备更多手动控制的优势,但需要更多的工作和较难的调试。


2
一些小的更正。管道也可以通过pipe系统调用匿名创建。共享内存也可以通过不私有地nmap文件来驻留在文件系统中。 - johannes
5
FIFO也支持多对一的通信(“摘要”似乎仅适用于一对一)。 - Mark Rajcok
2
@MarkRajcok 虽然理论上可能存在许多具有管道的编写器,但实际上并不是很有用,因为没有内置机制来管理消息级别的同步 - 所有编写器发送的内容都将以不可预测的方式交错。即使实现了外部同步,最好的方法也只能是在每个消息发送时在编写器之间进行互斥锁定,这并不有效,因为同一时间只能有一个编写器在写入。 - Michał Kosmulski
3
如果消息的大小始终小于PIPE_BUF,则我认为您不需要实现自己的锁定 - 消息不会交错。也许我应该说“具有PIPE_BUF大小限制的多对一”。 - Mark Rajcok
5
你是正确的,pipe(7)函数确实说明了如果O_NONBLOCK未被禁用并且要写入的字节数小于PIPE_BUF,则调用write(2)是根据POSIX.1-2001标准保证原子性的。但是,同样的手册中也建议“不同的实现对管道容量有不同的限制。应用程序不应依赖特定容量”。因此,在特定情况下,多个写入者的方案确实可行,但如果没有很好的理由,我不会基于此构建应用程序。你永远不知道你可能需要什么大小的消息。 - Michał Kosmulski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接