【知识讲解】 Linux进程间通信之匿名管道 目录前言Part1. 为什么需要进程间通信Part2. Linux IPC两大分类Part3. 匿名管道基础Part3.1. 什么是匿名管道Part3.2. 管道通信原理Part3.3. pipe系统调用Part4. 匿名管道读写行为Part4.1. 四种典型读写场景Part4.2. 管道缓冲区大小Part4.3. 管道写入的原子性Part5. 基于管道实现简易进程池Part5.1. 整体模型Part5.2. 模块设计思路Part5.3. 进程创建之后常规操作示例Part6. 匿名管道知识点总结Part7. 结语前言Linux下对于进程间通信的了解是非常重要的接下来来跟随小编的视角来看看吧。lets go!!!!!!!!Part1. 为什么需要进程间通信进程之间地址空间相互隔离一个进程无法直接读写另一个进程内存。进程间通信IPC目的1. 数据传输进程之间互相传递数据2. 资源共享多个进程共享一份资源3. 事件通知一个进程向另外进程发送消息通知事件发生4. 进程控制一个进程管控另外进程的执行暂停、终止等IPC的本质让多个进程能够访问操作系统提供的公共资源不能由进程私自创造这份共享资源管道就是操作系统提供的经典IPC方式之一。Part2. Linux IPC两大分类1. 基于文件的管道通信匿名管道 pipe、命名管道 fifo2. System V 版本本机通信消息队列、共享内存、信号量Part3. 匿名管道基础Part3.1. 什么是匿名管道匿名管道是最经典、基于文件的IPC多用于父子进程之间通信。重点匿名管道没有文件名、没有文件路径是临时的内核缓冲区不属于磁盘上普通文件。生命周期随进程进程全部退出管道资源自动被内核回收。Part3.2. 管道通信原理当父进程调用pipe()创建管道之后会得到两个文件描述符。随后执行fork()创建子进程• fork()会复制父进程的file文件结构体父子进程同时指向同一个管道内核缓冲区• 父子进程都拥有管道的读端、写端文件描述符• 一般做法父、子各自关闭不需要的一端保留单向通道完成通信管道是内核维护的一块内存缓冲区不会写入磁盘速度快。Part3.3. pipe系统调用int pipe(int pipefd[2]);• 返回值成功返回0失败返回-1并设置errno• 参数pipefd是输出型参数调用完成后填充两个文件描述符◦ pipefd[0]管道读端从管道读取数据◦ pipefd[1]管道写端向管道写入数据记忆小技巧0读1写类似标准输入stdin0标准输出stdout1。Part4. 匿名管道读写行为管道自带同步互斥机制面向字节流属于半双工通信半双工同一时刻只能单向传输不能同时两边互相收发。如果需要双向通信必须创建两根管道。Part4.1. 四种典型读写场景1.写快读慢写端持续写入管道缓冲区被填满之后write()会阻塞休眠直到读端取走数据腾出空间。2.读慢写快关闭写端管道里面还有残留数据读端继续读完已有数据读完全部数据之后再次调用read不会阻塞read返回0代表读到文件末尾。3.读端已经全部关闭进程还尝试write写管道此时向管道写入会触发SIGPIPE信号进程默认直接终止。Part4.2. 管道缓冲区大小Ubuntu下匿名管道默认缓冲区大小为 64KB。缓冲区满写阻塞缓冲区空读阻塞。Part4.3. 管道写入的原子性管道写入具备原子性一次写入操作要么全部写完要么不写不会出现“写一半”。举例进程A连续写入aaaaa…进程B写入bbbb…不会出现ababab交错混乱数据是整块排队写入缓冲区。注意原子性保护有上限单次写入超过PIPE_BUF大小时不再保证原子。Part5. 基于管道实现简易进程池Part5.1. 整体模型父进程 → 管道 → 子进程父进程通过管道向子进程下发任务子进程读取任务执行对应的业务逻辑。目标尽量降低空闲尽可能保证所有子进程都处于工作状态充分利用多核。任务执行完毕之后进程池管理器还要负责回收子进程资源避免僵尸进程。Part5.2. 模块设计思路1.Channel封装一根管道保存管道读写文件描述符代表一条通信通道。2.ChannelManager管理全部Channel集合底层可用vector保存所有管道统一管理所有通信通道。3.进程池管理器记录子进程数量process_num批量调用pipe()批量创建管道批量fork()创建子进程。Part5.3. 进程创建之后常规操作示例// 父进程关闭不需要的端口管理任务分发 close(pipefd[1]); // 子进程读取管道任务执行业务work work(pipefd[0]); close(pipefd[0]);设计要点• 父进程负责下发任务• 子进程阻塞读取管道拿到任务之后执行任务• 任务管理模块进程池结束时统一回收子进程Part6. 匿名管道知识点总结1. 匿名管道适用场景亲缘进程父子、兄弟进程通信无名字生命周期随进程。2. pipefd[0]读pipefd[1]写半双工双向通信需要两条管道。3. 阻塞行为管道空read阻塞管道满write阻塞。4. 结束判断所有写端关闭 → read返回0代表通信结束。5. 危险场景读端全部关闭仍然write触发SIGPIPE信号进程被杀。6. 写入原子性单次小于PIPE_BUF保证写入不会交叉。7. 缓冲区Linux管道默认缓冲区64KB。8. 可以基于管道封装实现简易进程池父进程分发任务子进程消费任务。Part7. 结语这篇文章我们深入的知道了进程间通信的相关知识接下来小编还会带来更多Linux相关的知识敬请期待~最后祝大家可以春风得意马蹄疾一日看尽长安花最后的最后要是觉得本文还可以的话可以点点赞关注小编一波谢谢大家~