行程間通訊

行程間通訊
相互作用类型
上级分类技术 编辑
Stack Exchange標籤https://stackoverflow.com/tags/ipc 编辑
「Inter-Process Communication」的各地常用名稱
中國大陸进程间通信
臺灣行程間通訊

进程间通信(Inter-Process Communication,简称IPC)是一种技术或方法,用于在至少两个进程或线程之间传输数据或信号。每个进程都有自己独立的系统资源,彼此隔离。为了实现不同进程之间的资源访问和协调工作,需要使用进程间通信。

通常,使用进程间通信的两个应用可以分为客户端和服务器(主从式架构)。客户端进程请求数据,服务器进程响应客户端的数据请求。有些应用既是服务器又是客户端,这种情况在分布式计算中很常见。这些进程可以运行在同一台计算机上,也可以运行在通过网络连接的不同计算机上。

IPC对于微内核和nano内核的设计过程非常重要。微内核减少了内核提供的功能数量,然后通过IPC与服务器通信来获取这些功能。与普通的宏内核相比,IPC的数量大幅增加。

两种基本范式

进程间通信的机制可以归纳为两种基本范式:共享内存和消息传递[1]。

共享内存

在共享内存模型中,操作系统将同一块物理内存区域映射到多个进程的虚拟地址空间中。各进程可以像访问普通变量一样直接读写这块区域,无需经过内核中转,因此共享内存是延迟最低、吞吐量最高的IPC机制[2]。

但由于多个进程同时访问同一区域,必须使用信号量、互斥锁等同步机制来防止竞争条件。以下伪代码展示了使用共享内存的生产者-消费者模式:

/* 生产者进程 */
shared_mem = shm_open("/buffer", O_CREAT | O_RDWR);
ftruncate(shared_mem, SIZE);
buf = mmap(NULL, SIZE, PROT_WRITE, MAP_SHARED, shared_mem);
sem_wait(&empty);          /* 等待缓冲区有空位 */
sem_wait(&mutex);          /* 进入临界区 */
write_data(buf, item);     /* 写入共享内存 */
sem_post(&mutex);          /* 离开临界区 */
sem_post(&full);           /* 通知消费者 */

/* 消费者进程 */
buf = mmap(NULL, SIZE, PROT_READ, MAP_SHARED, shared_mem);
sem_wait(&full);           /* 等待数据可用 */
sem_wait(&mutex);          /* 进入临界区 */
item = read_data(buf);     /* 从共享内存读取 */
sem_post(&mutex);          /* 离开临界区 */
sem_post(&empty);          /* 通知生产者 */

消息传递

在消息传递模型中,进程通过显式的发送(send)和接收(receive)操作交换数据。数据在进程间以离散的消息为单位传递,由操作系统内核负责复制和投递。与共享内存相比,消息传递不需要进程自行管理同步,编程模型更简单,且天然支持跨网络通信,但由于涉及数据复制和系统调用开销,性能通常低于共享内存。

/* 发送方 */
msg.type = DATA;
msg.content = item;
send(receiver_pid, &msg);  /* 内核将消息复制到接收方的消息队列 */

/* 接收方 */
receive(sender_pid, &msg); /* 从消息队列中取出消息 */
item = msg.content;

消息传递可以是同步的(发送方阻塞直到接收方收到消息)或异步的(发送方发出消息后立即继续执行)。同步方式也称为会合(rendezvous),异步方式则通常需要内核维护一个消息缓冲区。

主要的IPC机制

管道

管道(pipe)是最简单的IPC机制之一,提供单向的字节流通道。数据从管道的写端写入,从读端读出,遵循先进先出(FIFO)顺序。管道通常用于有亲缘关系的进程(如父子进程)之间的通信。在Unix系统的命令行中,管道运算符 | 将一个命令的标准输出连接到另一个命令的标准输入:

cat access.log | grep "404" | wc -l

命名管道(named pipe,也称FIFO)与匿名管道类似,但以文件系统中的特殊文件形式存在,允许无亲缘关系的进程通信。

消息队列

消息队列是由操作系统维护的消息链表。与管道传输无结构字节流不同,消息队列保持消息的边界,每条消息可以携带类型标识,接收方可以按类型选择性地接收消息。POSIX和System V分别提供了两套消息队列API。

共享内存

如前所述,共享内存允许多个进程访问同一块内存区域,是速度最快的IPC机制。POSIX提供 shm_open 和 mmap 等系统调用来创建和映射共享内存段。

套接字

套接字(socket)最初为网络通信设计,但也可用于同一主机上的进程间通信。套接字支持双向通信,并提供TCP(面向流)和UDP(面向消息)两种传输方式。Unix域套接字是专为同一主机上的IPC优化的套接字类型,避免了网络协议栈的开销,性能介于管道和TCP套接字之间。

信号

信号(signal)是一种轻量级的异步通知机制。一个进程可以向另一个进程发送信号,通知其发生了特定事件(如终止请求 SIGTERM、子进程结束 SIGCHLD 等)。信号通常不用于传输数据,而是用于控制和通知。

远程过程调用

远程过程调用(Remote Procedure Call,RPC)是一种高层IPC抽象,允许程序调用另一台计算机上的函数或方法,就像调用本地函数一样。调用方的参数被序列化后通过网络发送到服务方,服务方执行后将结果序列化返回。常见的RPC框架包括gRPC、Apache Thrift和JSON-RPC等。

同步与异步

IPC机制可以是同步(阻塞)的或异步(非阻塞)的[3]:

  • 同步IPC:发送方在消息被接收之前阻塞,或接收方在消息到达之前阻塞。管道的 read 操作在无数据可读时默认阻塞,就是同步IPC的典型例子。
  • 异步IPC:发送方发出消息后立即返回,不等待接收方处理。操作系统负责将消息缓存到中间缓冲区。信号是一种典型的异步IPC机制。

可以使用同步原语(如信号量、条件变量)在异步IPC机制上实现同步行为。

各机制比较

机制 通信方向 数据边界 适用范围 相对性能
匿名管道 单向 字节流 亲缘进程 高
命名管道 单向 字节流 同一主机 高
消息队列 单向/双向 保持消息边界 同一主机 中
共享内存 双向 无(需自行定义) 同一主机 最高
Unix域套接字 双向 流或数据报 同一主机 中高
TCP/UDP套接字 双向 流或数据报 同一主机或跨网络 较低
信号 单向 无数据(仅通知) 同一主机 极高(但信息量极小)
RPC 双向(请求-响应) 保持消息边界 跨网络 低

共享内存的延迟通常在亚微秒级别,而同一主机上的TCP套接字延迟通常在数十微秒级别,跨网络通信则受网络延迟影响更大[4]。

参考文献

  1. ^ Abraham Silberschatz; Peter B. Galvin; Greg Gagne. Chapter 3: Processes. Operating System Concepts 10th. Wiley. 2018. ISBN 978-1-119-32091-3. 
  2. ^ Aditya Venkataraman; Kishore Kumar Jagadeesha. Evaluation of Inter Process Communication Mechanisms (PDF). University of Wisconsin-Madison. [2026-06-05]. 
  3. ^ W. Richard Stevens. UNIX Network Programming, Volume 2: Interprocess Communications 2nd. Prentice Hall. 1999. ISBN 0-13-081081-9. 
  4. ^ Aditya Venkataraman; Kishore Kumar Jagadeesha. Evaluation of Inter Process Communication Mechanisms (PDF). University of Wisconsin-Madison. [2026-06-05].