示例代码
- github: https://github.com/lengjingzju/notes/tree/master/code/linux_ipc
- gitee: https://gitee.com/lengjingzju/notes/tree/master/code/linux_ipc
一、Linux IPC 概述
在 Linux 系统中,进程间通信(IPC,Inter-Process Communication) 是指在不同进程之间传递数据或信号的机制。由于每个进程拥有独立的虚拟地址空间,一个进程无法直接访问另一个进程的数据,因此需要借助操作系统提供的 IPC 工具来实现进程间的协作与同步。
IPC 不仅是操作系统课程的核心内容,更是实际开发中构建高性能、可扩展系统的基础技能。无论是构建多进程服务器、实现进程间任务协同,还是进行资源同步与数据共享,掌握 IPC 都是 Linux 后端开发工程师的必备能力。
二、IPC 工具分类
根据功能和用途,Linux IPC 工具可分为以下几类:
1. 通信工具
用于在进程之间传递数据。
数据传输
- 字节流式 :数据以无边界字节流形式传输
- PIPE(无名管道)
- FIFO(命名管道)
- TCP 套接字
- 消息式 :数据以有边界消息形式传输
- SYSV 消息队列
- POSIX 消息队列
- UDP 套接字
- 伪终端:模拟终端设备,用于进程间通信
共享内存
将一块内存区域映射到多个进程的地址空间,进程可直接读写该区域。
- SYSV 共享内存
- POSIX 共享内存
- 文件内存映射
- 匿名内存映射
2. 同步工具
用于协调进程或线程的执行顺序,防止竞争条件。
线程同步(同一进程内)
- mutex(互斥量)
- rwlock(读写锁)
- cond(条件变量)
- spin(自旋锁)
- barrier(屏障)
进程同步
- 文件锁
- 记录锁(fcntl)
- 文件锁(flock)
- 信号量
- SYSV 信号量
- POSIX 命名信号量
- POSIX 无名信号量
- 信号:常称为软中断,有中断号,用于通知进程事件发生
三、IPC 工具属性对比
下表总结了常用 IPC 工具的关键特性:
| 工具类型 | 名字空间 | 对象描述符 | 可访问性 | 持久性 |
|---|---|---|---|---|
| PIPE 无名管道 | 无名 | 文件描述符 | 相关进程 | 进程 |
| FIFO 命名管道 | 文件路径名 | 文件描述符 | 权限掩码 | 进程 |
| SYSV 消息队列 | IPC 键 key_t | IPC 标识符 int | 权限掩码 | 内核 |
| SYSV 信号量 | IPC 键 key_t | IPC 标识符 int | 权限掩码 | 内核 |
| SYSV 共享内存 | IPC 键 key_t | IPC 标识符 int | 权限掩码 | 内核 |
| POSIX 消息队列 | IPC 路径名 | mqd_t 描述符 | 权限掩码 | 内核 |
| POSIX 命名信号量 | IPC 路径名 | sem_t* 指针 | 权限掩码 | 内核 |
| POSIX 共享内存 | IPC 路径名 | 文件描述符 | 权限掩码 | 内核 |
| 文件内存映射 | 路径名 | 文件描述符 | 权限掩码 | 文件 |
| TCP 套接字 | IP+端口 | 文件描述符 | 任意进程 | 进程 |
| Unix 域套接字 | 路径名 | 文件描述符 | 权限掩码 | 进程 |
关键术语解释
- 相关进程 :同一进程通过
fork()创建的进程(父子进程或兄弟进程) - 权限掩码:通过文件系统权限控制访问
- 持久性 :
- 进程持久性:IPC 对象持续到最后一个使用它的进程关闭
- 内核持久性:IPC 对象持续到内核重启或显式删除
- 文件系统持久性:IPC 对象持续到显式删除,内核重启不影响
四、数据传输与共享内存机制
数据传输机制
- 写入过程:数据从进程缓冲区复制到内核缓冲区
- 读取过程:数据从内核缓冲区复制到进程缓冲区
- 特性 :
- 读取操作是破坏性的,数据被消耗后其他进程无法再次读取
- 默认情况下,空读/满写会阻塞进程
- 字节流无边界,可读取任意字节
- 消息有边界,一次读取一条完整消息
共享内存机制
- 直接内存访问:进程通过映射的虚拟地址直接读写共享内存
- 同步需求:需要额外同步机制(如信号量)保护共享数据
- 性能优势:避免了数据在内核和用户空间之间的复制,是最高效的 IPC 方式
- 内存映射类型 :
- 文件映射:基于文件内容初始化内存
- 匿名映射:分配新内存区域
五、IPC 选择策略
选择依据
-
通信模式
- 一对一 vs 一对多 vs 多对多
- 单向 vs 双向
-
性能要求
- 共享内存 > 消息队列 > 管道 > 套接字(本地通信)
-
平台兼容性
- POSIX IPC 标准化程度高,可移植性好
- System V IPC 历史悠久,广泛支持
-
开发复杂度
- 管道和 FIFO 简单易用
- 共享内存需要额外同步机制
-
持久性需求
- 是否需要跨进程生命周期的持久存储
典型应用场景
- 父子进程通信:PIPE
- 任意进程通信:FIFO、消息队列、共享内存
- 高性能数据共享:共享内存 + 信号量
- 网络通信:套接字
- 线程同步:互斥锁、条件变量
- 进程同步:信号量、文件锁
六、示例代码概览
在本次系列文章中,我们将以统一的示例模式演示各种 IPC 机制:父进程(或主线程)从终端读取数据,通过 IPC 机制传递给子进程(或子线程),子进程将数据输出到终端。输入 "q" 退出程序。
示例程序包括:
test_pipe.c- PIPE(无名管道)示例test_fifo.c- FIFO(命名管道)示例test_sysv_msg.c- SYSV 消息队列示例test_sysv_shm.c- SYSV 共享内存示例test_posix_mq.c- POSIX 消息队列示例test_posix_shm.c- POSIX 共享内存示例test_thread_cond.c- 线程条件变量示例test_thread_sem.c- 线程信号量示例test_signal_sender.c/test_signal_reciver.c- 信号通信示例
七、系列文章安排
本系列将分六篇文章深入讲解 Linux IPC:
- 总体介绍(本文):全面概述 Linux IPC 机制
- PIPE、FIFO 与信号:讲解最简单的进程间通信方式
- System V IPC:深入探讨消息队列、信号量和共享内存
- POSIX IPC:介绍现代、可移植的 IPC 机制
- 线程同步机制:讲解同一进程内的线程同步工具
- 结语与实战指南:回顾IPC,总结与展望
八、总结
Linux IPC 提供了丰富多样的进程间通信与同步机制,每种机制都有其适用场景和优缺点。选择合适的 IPC 机制需要综合考虑通信模式、性能需求、平台兼容性和开发复杂度等因素。
掌握 IPC 不仅是理解操作系统原理的关键,更是构建高性能、可靠分布式系统的基础。通过本系列文章,我们将从理论到实践,全面掌握 Linux IPC 的方方面面,为开发高效的多进程/多线程应用打下坚实基础。
在接下来的文章中,我们将从最简单的 PIPE 和 FIFO 开始,逐步深入各种 IPC 机制的内部原理和实际应用,敬请期待!
下一篇预告:我们将深入讲解 PIPE(无名管道)和 FIFO(命名管道),这是 Linux 中最基本、最常用的进程间通信方式,通过实际代码示例展示其工作原理和使用方法。