每个进程拥有独立的虚拟地址空间,进程之间要交换数据或协调动作,必须借助内核提供的 IPC 机制。本文对比管道、FIFO、消息队列、共享内存、信号量、信号和 Socket 七种方式的差异,并解释共享内存与信号量这对经典组合的分工。

为什么进程间通信必须借助内核

虚拟内存让每个进程活在自己的地址空间里:两个进程中相同的虚拟地址,映射的是不同的物理页。A 进程写的变量,B 进程根本看不见。隔离保证了安全与稳定,但也意味着进程要协作时只能靠内核出面:要么内核代收代发数据(管道、消息队列、Socket),要么内核建立一份双方都能访问的共享对象(共享内存)。

七种 IPC 方式逐个看

管道与命名管道

管道是内核里的一段缓冲区,表现为单向字节流。pipe() 返回读、写两个文件描述符,父进程 fork() 后子进程继承描述符,因此匿名管道天然适合父子等有亲缘关系的进程,Shell 里的 ps aux | grep java 走的就是它。命名管道(FIFO)用 mkfifo 在文件系统里建一个特殊文件,没有亲缘关系的进程按路径打开即可通信——路径只负责命名,数据仍在内存缓冲区,并不落盘。两者都不保留消息边界,写三次不等于读三次。

消息队列

消息队列把数据封装成一条条消息存放在内核队列中,发送方 msgsnd(),接收方 msgrcv(),System V 版本还支持按消息类型选择性接收。相比管道,它保留了消息边界,收发可以异步解耦;代价是每条消息要在用户态和内核态之间拷贝两次,且受内核参数限制,只适合控制命令、状态事件这类小消息,不要把它当成 Kafka 那种消息中间件。

共享内存

共享内存让多个进程把同一段物理内存映射进各自的地址空间。映射完成后,读写就是普通的内存访问,不必每次陷入内核、也不经过中间拷贝,是所有 IPC 中数据通路最短的一种,适合本机大块数据交换(视频帧、日志批、数据库缓存)。但它只解决”看得见同一份数据”,不解决”谁先写、谁后读”。

信号量与信号

信号量(Semaphore)是一个计数器:sem_wait() 减一、减不动就阻塞,sem_post() 加一并唤醒等待者,用来控制进入临界区的数量或做事件计数,它本身不传业务数据。信号(Signal)是异步事件通知:SIGTERM 请求退出、SIGCHLD 报告子进程状态变化。信号能携带的信息极少,处理函数还受 async-signal-safe 限制,只适合”出事了”级别的通知,不适合传数据。

Socket

Socket 是最通用的一种:同一台机器用 Unix Domain Socket(地址族 AF_UNIX),支持双向字节流和数据报,还能借助 SCM_RIGHTS 把文件描述符传给对端;跨机器就换成 TCP/UDP 网络 Socket。它接口统一、天然支持请求-响应模型,但字节流语义意味着分包、粘包要应用自己处理。

七种方式横向对比

方式 速度 容量 同步语义 跨机器
匿名管道 中,两次拷贝 内核缓冲区,默认 64KB 读空阻塞、写满阻塞 否
命名管道 中,两次拷贝 内核缓冲区 同管道,靠路径寻址 否
消息队列 中,两次拷贝 受队列与单条消息上限约束 保留消息边界,可异步 否
共享内存 最快,数据零额外拷贝 创建时决定,可很大 无内置同步 否
信号量 极快,计数操作 不传数据 阻塞式计数同步 否
信号 极快 仅事件编号 异步打断,标准信号不排队 否
Socket 较慢,协议栈开销 流式不限,受缓冲区控制 连接管理,字节流/数据报 是

表中”速度”是定性对比,真实性能还受上下文切换、消息大小与锁竞争影响。

共享内存 + 信号量:为什么经典

这对组合恰好互补。共享内存的短板是没有同步语义:生产者还没把一条记录写完,消费者就可能读到半成品。信号量的短板是不能传数据,只有计数。两者拼起来——共享内存负责数据通路,信号量负责访问时序(一个信号量记”已写条目数”,一个记”剩余空位”,必要时再加互斥量保护读写指针)——就得到一个完整的高吞吐生产者-消费者通道。数据库共享缓冲区、音视频处理流水线里大量使用这个模式。

实践要点

  • 选型先看语义再看速度:要消息边界选消息队列,要双向与请求-响应选 Unix Socket,跨机器只有 Socket。
  • 共享内存区域里不要放进程内指针——不同进程映射的基址不同,应存偏移量或数组下标。
  • 谈性能不要只数拷贝次数,同步成本(锁、信号量、唤醒)常常才是瓶颈。
  • 信号处理器里只做置标志位这类最小操作,复杂逻辑交给主循环统一处理。

小结

  • 进程地址空间彼此隔离,IPC 要么让内核中转数据,要么让内核建立共享映射。
  • 管道/FIFO 是单向字节流;消息队列保留边界但适合小消息;Socket 通用且唯一能跨机器。
  • 共享内存最快但无同步,信号量管同步不传数据,两者组合是经典的高吞吐方案。
  • 选型按数据量、消息边界、通信范围与同步需求来定,而不是按名词熟悉度。