IPC
IPC
进程间通信即 IPC,Inter-Process Communication,讨论的是不同进程之间如何交换数据。
进程是资源分配单位,通常拥有相互独立的地址空间。为了安全,一个进程不能直接读写另一个进程的地址空间。因此,进程通信必须由操作系统提供受控机制。
常见 IPC 方式主要有三类:共享存储、消息传递、管道通信。
共享存储
共享存储让多个进程把同一片物理内存映射到各自地址空间中。这样,进程 P 写入共享区的数据,进程 Q 可以从自己的地址空间中读到。
| 类型 | 做法 | 特点 |
|---|---|---|
| 基于数据结构的共享 | 共享区只能按系统规定的数据结构使用,例如固定大小数组 | 限制多,速度相对慢,属于低级通信方式 |
| 基于存储区的共享 | 操作系统划出共享存储区,数据格式和位置由通信进程决定 | 灵活、速度快,属于高级通信方式 |
共享存储速度快,但不自动保证访问顺序。多个进程同时读写同一共享区时,需要互斥和同步机制,否则会出现覆盖、读到半成品数据等问题。
共享存储的地址映射细节可联系 Memory-Mapped-Files-And-mmap。这里关注的是 IPC 语义:多个进程通过同一共享区交换数据。
消息传递
消息传递以格式化的消息为单位。进程不直接共享地址空间,而是通过操作系统提供的发送、接收原语交换消息。
一条消息通常包括:
| 部分 | 内容 |
|---|---|
| 消息头 | 发送进程 ID、接收进程 ID、消息长度、消息类型等控制信息 |
| 消息体 | 真正要传递的数据 |
消息传递有两种典型形式:
| 形式 | 发送目标 | 接收来源 | 特点 |
|---|---|---|---|
| 直接通信 | 直接指定接收进程 | 直接指定发送进程 | 发送方和接收方需要知道对方身份 |
| 间接通信 | 发送到信箱或消息队列 | 从信箱或消息队列接收 | 发送方和接收方通过中间对象解耦 |
直接通信可以理解为“点名道姓”:进程 P 把消息发给进程 Q,操作系统把消息挂入 Q 的消息队列,Q 再从队列中取走。
间接通信以信箱作为中间实体:多个进程可以向同一信箱发送消息,也可以从同一信箱接收消息。
管道通信
管道是一种特殊共享文件,也可以理解为内核维护的固定大小内存缓冲区。一个进程向管道写数据,另一个进程从管道读数据。
管道的关键规则:
| 规则 | 含义 |
|---|---|
| 半双工 | 同一时间段内通常只能单向传输;若要双向通信,需要两个管道 |
| 互斥访问 | 多个进程访问管道时,由操作系统保证必要的互斥 |
| 写满阻塞 | 管道满时,写进程阻塞,直到读进程取走数据 |
| 读空阻塞 | 管道空时,读进程阻塞,直到写进程写入数据 |
| 读出即消失 | 管道中的数据被读出后就不再保留 |
多个进程读取同一管道时可能发生混乱,因为数据被某个读进程取走后,其他读进程就读不到这部分数据。常见处理方式是限制为多个写进程、一个读进程;也可以由系统安排多个读进程轮流读取。
三种 IPC 对比
| 方式 | 数据放在哪里 | 交换方式 | 典型特点 |
|---|---|---|---|
| 共享存储 | 共享内存区 | 进程直接读写共享区 | 速度快,但必须额外处理同步互斥 |
| 消息传递 | 内核消息队列或信箱 | 通过发送/接收原语传递消息 | 结构清晰,适合受控通信 |
| 管道通信 | 内核管道缓冲区 | 一端写,一端读 | 适合流式数据,读出即消失 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Elian's blog page!