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

一、今日学习总览

  1. 补充知识点:计数信号量
  2. 核心学习:进程间通信(IPC)
    • IPC 分类框架梳理
    • 重点攻克:管道(无名管道 pipe + 有名管道 fifo)

二、进程间通信(IPC)整体分类

IPC(interprocess communicate) 是不同进程之间交换数据 / 信号的方式,核心分为三大类:

类别 具体方式 核心特点
古老的通信方式 无名管道、有名管道、信号 简单、基础,部分有局限性(如管道半双工
IPC 对象通信 消息队列、共享内存、信号量集 效率高,专为进程间通信设计
Socket 通信 基于网络 / 本地套接字 跨主机 / 跨进程通用,功能强大

三、管道核心知识点(重点)

1. 管道通用特性

  • 半双工通信:数据只能单向流动,双向通信需创建两个管道
  • 基于文件描述符:读端(fd [0])、写端(fd [1]),遵循 "先入先出"

内核级缓冲区:数据传输通过内核缓冲区,不落地磁盘

  • 随进程 / 文件描述符关闭释放:无名管道随进程退出销毁,有名管道需手动卸载

2. 管道读写四大关键场景

场景 触发条件 行为表现
写阻塞 管道满 + 读端存在 超过64k,写进程阻塞,直到有读进程取走数据
读阻塞 管道空 + 写端存在 读进程阻塞,直到有写进程写入数据
管道破裂(SIGPIPE) 写端写入时,读端已全部关闭 内核向写进程发送 SIGPIPE 信号,默认导致进程终止
read 返回 0 管道空 + 写端已全部关闭 读进程 read 返回 0,表示无数据且不会再写入

3. 无名管道(pipe)

(1)核心特性
  • 仅限亲缘进程间通信(父子 / 兄弟进程)
  • 无文件名,仅存在于内核中,进程退出后自动销毁
  • 创建后返回两个文件描述符:fd [0](读)、fd [1](写)
(2)使用步骤 + 核心函数
步骤 函数 / 操作 关键说明
1. 创建管道 int pipe(int fd[2]); 成功返回 0,失败返回 - 1;fd [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)实战示例:父进程读照片传给子进程
cs 复制代码
#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. 有名管道(fifo)

(1)核心特性
  • 支持非亲缘进程间通信(任意进程,只要知道管道名)
  • 有文件路径(如 /tmp/myfifo),存在于文件系统中,内容在内存
  • 操作逻辑与无名管道一致,仅创建 / 打开方式不同
(2)使用步骤 + 核心函数
步骤 函数 / 操作 关键说明
1. 创建 fifo 文件 int mkfifo(const char *path, mode_t mode); 成功返回 0,失败返回 - 1;mode 为文件权限(如 0644)
2. 打开管道 int open(const char *path, O_RDONLY/O_WRONLY); 读端 / 写端需分别打开,未配对时会阻塞(除非 O_NONBLOCK)
3. 读写管道 read()/write() 与无名管道用法完全一致
4. 关闭管道 close(fd); 关闭文件描述符
5. 卸载 fifo unlink(const char *path); 删除文件系统中的 fifo 文件
(3)注意事项
  • 创建 fifo 后,必须同时有读端和写端打开,否则单独打开会阻塞(除非加 O_NONBLOCK)
  • fifo 文件仅为 "标识",数据仍存于内核缓冲区,不落地
  • 多个进程写 fifo 时,需保证写入数据不超过 PIPE_BUF(原子写入),避免数据错乱

四、今日学习总结

  1. 核心重点 :管道是 IPC 中最基础的通信方式,无名管道适用于亲缘进程,有名管道突破亲缘限制,二者读写逻辑一致,核心关注 "读写端存在性" 导致的阻塞 / 破裂场景。
  2. 关键函数:pipe(创建无名管道)、mkfifo(创建有名管道)、read/write(管道读写)、close/unlink(管道关闭 / 卸载)。
  3. 核心易错点:管道破裂(SIGPIPE)、读写端未正确关闭导致的阻塞、有名管道未配对打开的阻塞问题。

五、后续学习建议

  1. 结合示例代码实操,验证 "读 / 写阻塞、管道破裂" 等场景的实际表现。
  2. 对比无名管道和有名管道的适用场景,总结二者的异同点。
  3. 预习下一个 IPC 知识点(如消息队列 / 共享内存),对比管道的优缺点。
相关推荐
顶点多余4 天前
进程:计算机世界的执行单元
linux·运维·服务器·进程
_OP_CHEN5 天前
【Linux系统编程】(四十五)线程池基础:日志系统设计与策略模式的优雅落地
linux·操作系统·线程池·进程·策略模式·c/c++·日志系统
_OP_CHEN5 天前
【Linux系统编程】(四十七)线程安全与线程锁深度解析:从概念到实战,避坑指南全掌握
linux·操作系统·线程池·进程·线程安全·c/c++·线程锁
♛识尔如昼♛5 天前
操作系统(4)第二章- 进程通信
操作系统·进程·ipc
_OP_CHEN6 天前
【Linux系统编程】(四十六)线程池原理与实现:从固定线程池到线程安全单例模式
linux·单例模式·操作系统·线程池·进程·线程安全·c/c++
青桔柠薯片19 天前
Linux软件编程:线程和进程间通信
linux·开发语言·线程·进程
’长谷深风‘19 天前
进程间通信
c语言·进程·进程间通信·软件编程
_OP_CHEN19 天前
【Linux系统编程】(四十)线程控制终极指南:从资源共享到实战操控,带你吃透线程全生命周期
linux·运维·操作系统·线程·进程·c/c++·线程控制
’长谷深风‘20 天前
线程函数接口和属性
c语言·开发语言·线程·进程·软件编程