进程间通信(IPC)- 管道专题学习笔记

进程间通信(IPC)- 管道专题学习笔记 一、今日学习总览补充知识点计数信号量核心学习进程间通信IPCIPC 分类框架梳理重点攻克管道无名管道 pipe 有名管道 fifo二、进程间通信IPC整体分类IPCinterprocess communicate是不同进程之间交换数据 / 信号的方式核心分为三大类类别具体方式核心特点古老的通信方式无名管道、有名管道、信号简单、基础部分有局限性如管道半双工IPC 对象通信消息队列、共享内存、信号量集效率高专为进程间通信设计Socket 通信基于网络 / 本地套接字跨主机 / 跨进程通用功能强大三、管道核心知识点重点1. 管道通用特性半双工通信数据只能单向流动双向通信需创建两个管道基于文件描述符读端fd [0]、写端fd [1]遵循 “先入先出”内核级缓冲区数据传输通过内核缓冲区不落地磁盘随进程 / 文件描述符关闭释放无名管道随进程退出销毁有名管道需手动卸载2. 管道读写四大关键场景场景触发条件行为表现写阻塞管道满 读端存在超过64k写进程阻塞直到有读进程取走数据读阻塞管道空 写端存在读进程阻塞直到有写进程写入数据管道破裂SIGPIPE写端写入时读端已全部关闭内核向写进程发送 SIGPIPE 信号默认导致进程终止read 返回 0管道空 写端已全部关闭读进程 read 返回 0表示无数据且不会再写入3. 无名管道pipe1核心特性仅限亲缘进程间通信父子 / 兄弟进程无文件名仅存在于内核中进程退出后自动销毁创建后返回两个文件描述符fd [0]读、fd [1]写2使用步骤 核心函数步骤函数 / 操作关键说明1. 创建管道int pipe(int fd[2]);成功返回 0失败返回 - 1fd [0] 读、fd [1] 写2. 创建子进程pid_t fork();子进程继承父进程的管道文件描述符3. 关闭无用端close(fd[0]/fd[1]);单向通信时父 / 子进程关闭不需要的端如父写子读父关 fd [0]子关 fd [1]4. 读写管道write(fd[1], buf, len);/read(fd[0], buf, len);write写入字节数read读取实际字节数0 表示写端关闭5. 关闭管道close(fd[0]/fd[1]);通信完成后关闭剩余文件描述符3实战示例父进程读照片传给子进程#include stdio.h #include unistd.h #include fcntl.h #include sys/wait.h #define BUF_SIZE 1024 int main() { int fd[2]; char buf[BUF_SIZE]; int fd_photo; ssize_t read_len, write_len; // 1. 创建无名管道 if (pipe(fd) -1) { perror(pipe error); return -1; } // 2. 创建子进程 pid_t pid fork(); if (pid -1) { perror(fork error); return -1; } if (pid 0) { // 子进程读管道数据 close(fd[1]); // 关闭写端 // 接收并保存照片 int fd_copy open(copy_photo.jpg, O_WRONLY | O_CREAT | O_TRUNC, 0644); while ((read_len read(fd[0], buf, BUF_SIZE)) 0) { write(fd_copy, buf, read_len); } close(fd[0]); close(fd_copy); return 0; } else { // 父进程读照片并写入管道 close(fd[0]); // 关闭读端 fd_photo open(test.jpg, O_RDONLY); if (fd_photo -1) { perror(open photo error); return -1; } // 读取照片并写入管道 while ((read_len read(fd_photo, buf, BUF_SIZE)) 0) { write_len write(fd[1], buf, read_len); if (write_len ! read_len) { perror(write pipe error); break; } } close(fd[1]); close(fd_photo); wait(NULL); // 等待子进程完成 } return 0; }4.注意事项1.管道的数据存储结构队列先进先出FIFO管道的本质是内核中的环形缓冲区数据严格按照写入顺序排列2.数据的生命周期读走即消失不会保留管道是流式、一次性的通信机制当调用read时数据会从管道缓冲区被剪切出来复制到用户态的buf里原缓冲区中的这段数据会被删除同一个数据只能被读取一次读完就从管道里消失了无法重复出现。3.管道缓冲区是有限大小的通常是4KB或64KB由系统决定。4. 有名管道fifo1核心特性支持非亲缘进程间通信任意进程只要知道管道名有文件路径如/tmp/myfifo存在于文件系统中内容在内存操作逻辑与无名管道一致仅创建 / 打开方式不同2使用步骤 核心函数步骤函数 / 操作关键说明1. 创建 fifo 文件int mkfifo(const char *path, mode_t mode);成功返回 0失败返回 - 1mode 为文件权限如 06442. 打开管道int open(const char *path, O_RDONLY/O_WRONLY);读端 / 写端需分别打开未配对时会阻塞除非 O_NONBLOCK3. 读写管道read()/write()与无名管道用法完全一致4. 关闭管道close(fd);关闭文件描述符5. 卸载 fifounlink(const char *path);删除文件系统中的 fifo 文件3注意事项创建 fifo 后必须同时有读端和写端打开否则单独打开会阻塞除非加 O_NONBLOCKfifo 文件仅为 “标识”数据仍存于内核缓冲区不落地多个进程写 fifo 时需保证写入数据不超过 PIPE_BUF原子写入避免数据错乱四、今日学习总结核心重点管道是 IPC 中最基础的通信方式无名管道适用于亲缘进程有名管道突破亲缘限制二者读写逻辑一致核心关注 “读写端存在性” 导致的阻塞 / 破裂场景。关键函数pipe创建无名管道、mkfifo创建有名管道、read/write管道读写、close/unlink管道关闭 / 卸载。核心易错点管道破裂SIGPIPE、读写端未正确关闭导致的阻塞、有名管道未配对打开的阻塞问题。五、后续学习建议结合示例代码实操验证 “读 / 写阻塞、管道破裂” 等场景的实际表现。对比无名管道和有名管道的适用场景总结二者的异同点。预习下一个 IPC 知识点如消息队列 / 共享内存对比管道的优缺点。