Unix/Linux 提供了许多 IPC:管道、套接字、共享内存、dbus、消息队列……
每种最适合的应用程序是什么,它们的性能如何?
以下是七大:
FIFO或命名管道
与普通管道不同,两个不相关的进程可以使用 FIFO。打电话mkfifo(3)
。单向。
双向。用于网络通信,但也可以在本地使用。可用于不同的协议。TCP 没有消息边界。打电话socket(2)
。
操作系统维护离散消息。请参阅sys/msg.h。
Signal 向另一个进程发送一个整数。不能很好地与多线程啮合。打电话kill(2)
。
一种多进程或多线程的同步机制,类似于排队等候洗手间的人。请参阅sys/sem.h。
做你自己的并发控制。打电话shmget(2)
。
选择一种方法而不是另一种方法时的一个决定因素是消息边界问题。您可能期望“消息”彼此分离,但它不适用于 TCP 或 Pipe 这样的字节流。
考虑一对回显客户端和服务器。客户端发送字符串,服务器接收并立即发送回。假设客户端发送“Hello”、“Hello”和“How about an answer?”。
使用字节流协议,服务器可以接收“Hell”、“oHelloHow”和“about an answer?”;或者更现实地说“你好你好,答案怎么样?”。服务器不知道消息边界在哪里。
一个古老的技巧是将消息长度限制为CHAR_MAX
orUINT_MAX
并同意首先在char
or中发送消息长度uint
。因此,如果您在接收方,则必须先阅读消息长度。这也意味着一次只能有一个线程读取消息。
使用 UDP 或消息队列等离散协议,您不必担心这个问题,但以编程方式处理字节流更容易,因为它们的行为类似于文件和标准输入/输出。
共享内存可能是最有效的,因为您在其上构建了自己的通信方案,但它需要大量的关注和同步。解决方案也可用于将共享内存分配给其他机器。
如今,套接字是最便携的,但比管道需要更多的开销。在本地或通过网络透明地使用套接字的能力是一个很大的好处。
消息队列和信号非常适合硬实时应用程序,但它们没有那么灵活。
这些方法自然是为进程之间的通信而创建的,在一个进程中使用多个线程会使事情变得复杂——尤其是信号。
这是一个带有简单基准的网页:https ://sites.google.com/site/rikkus/sysv-ipc-vs-unix-pipes-vs-unix-sockets
据我所知,每个都有其优点:
值得注意的是,许多库在另一种之上实现了一种类型的东西。
共享内存不需要使用可怕的 sysv 共享内存函数 - 使用 mmap() 更优雅(如果你想命名它,将文件 mmap 到 tmpfs /dev/shm ;如果你想 mmap /dev/zero分叉未执行的进程以匿名继承它)。话虽如此,它仍然使您的进程需要同步以避免问题 - 通常通过使用其他一些 IPC 机制来同步访问共享内存区域。