目录
[一、无名管道(Unnamed Pipe / pipe)半双工](#一、无名管道(Unnamed Pipe / pipe)半双工)
[1. 概念](#1. 概念)
[2. 创建方式](#2. 创建方式)
[3. 使用流程(重点)](#3. 使用流程(重点))
[4. 读写规则](#4. 读写规则)
[4.1 读端行为](#4.1 读端行为)
[4.2 写端行为](#4.2 写端行为)
[5. 管道关闭规则(非常重要)](#5. 管道关闭规则(非常重要))
[5.1 关闭写端](#5.1 关闭写端)
[5.2 关闭读端](#5.2 关闭读端)
[二、有名管道(Named Pipe / FIFO)半双工](#二、有名管道(Named Pipe / FIFO)半双工)
[1. 概念](#1. 概念)
[2. 创建方式](#2. 创建方式)
[3. 读写规则(和 pipe 类似)](#3. 读写规则(和 pipe 类似))
[5.1 读端](#5.1 读端)
[5.2 写端](#5.2 写端)
一、无名管道(Unnamed Pipe / pipe)半双工
1. 概念
无名管道是一种内核提供的临时通信缓冲区(队列) ,用于有亲缘关系的进程通信(父子进程)。
特点:
- 只能用于有关系的进程(父子/兄弟)
- 没有文件名
- 生命周期随进程结束而消失
2. 创建方式
cpp
int pipe(int pipefd[2]);
参数说明:
-
pipefd[0]:读端(read end) -
pipefd[1]本质:
内核创建一个环形队列/缓冲区:
写端 → [ 内核缓冲区(队列) ] → 读端3. 使用流程(重点)
-
先 pipe,再 fork
原因:fork 后子进程会继承父进程的 fd,从而共享同一个管道缓冲区
4. 读写规则
4.1 读端行为
情况1:管道无数据
read() → 阻塞(进入等待态)
情况2:管道有数据
read() → 立即返回,返回值 = 实际读取字节数
4.2 写端行为
情况1:正常写
write() → 写入缓冲区
情况2:读端关闭
write() → 触发 SIGPIPE 信号
进程默认退出(崩溃)
5. 管道关闭规则(非常重要)
5.1 关闭写端
如果:
- 写端全部关闭
- 读端仍在读
那么:read() → 返回 0 含义: 表示"文件结束 EOF"
5.2 关闭读端
如果:
- 读端关闭
- 写端还在写
那么:write() → 进程被 SIGPIPE 杀死
进程通信本质关系
pipe 是单向通信 :写进程 → 管道 → 读进程,如果需要双向通信:必须用 两个 pipe
二、有名管道(Named Pipe / FIFO)半双工
1. 概念
有名管道是: 有文件名的管道
本质仍然是:
- 内核缓冲区(队列)
- 但通过文件路径访问
2. 创建方式
方法1:命令创建
int pipe(int pipefd2);
参数说明:
pipefd[0]:读端(read end)pipefd[1]:写端(write end)
本质:内核创建一个环形队列/缓冲区:写端 → 内核缓冲区(队列) → 读端
方法2:系统调用
cpp
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
//示例 mkfifo("myfifo", 0664);
打开方式
open("myfifo", O_RDONLY);
open("myfifo", O_WRONLY);
3. 读写规则(和 pipe 类似)
5.1 读端
- 没数据 → 阻塞
- 有数据 → 返回
5.2 写端
- 无读者 → 阻塞或失败(取决于模式)
- 有读者 → 正常写入
三、有名管道和无名管道特点对比
| 项目 | 无名管道 | 有名管道 |
|---|---|---|
| 是否有名字 | 没有 | 有文件名 |
| 使用范围 | 父子进程 | 任意进程 |
| 生命周期 | 随进程 | 文件存在即存在 |
| 通信方式 | 内存队列 | 文件路径访问 |
| 创建方式 | pipe() | mkfifo() |