六十天Linux从0到项目搭建(第二十二天)(pipe、管道四种场景)
1 关于 pipe 系统调用的解析
int pipe(int pipefd[2])
是 Unix/Linux 系统中用于创建匿名管道的系统调用。以下是关于管道特点的详细解释:
输出型参数
-
pipefd[2]
是输出型参数,调用成功后:-
pipefd[0]
存放管道的读取端文件描述符 -
pipefd[1]
存放管道的写入端文件描述符
-
管道通信特点
-
单向通信:
-
管道本质上是半双工通信的一种特殊情况
-
虽然可以通过创建两个管道实现全双工通信,但单个管道本身是单向的
-
-
文件本质:
-
管道在内核中表现为一个特殊的文件
-
文件描述符的生命周期随进程结束而结束
-
管道的生命周期也随进程结束而终止
-
-
使用场景:
-
主要用于具有"血缘关系"的进程间通信(IPC)
-
常用于父子进程通信
-
因为是匿名管道,没有名字,只能通过继承文件描述符的方式共享
-
-
读写特性:
-
读写次数不需要严格匹配
-
写入和读取的次数没有强相关性
-
数据以字节流形式传输
-
-
同步机制:
-
管道具有内置的同步机制
-
当管道为空时,读取操作会阻塞
-
当管道满时,写入操作会阻塞
-
这种特性使得读写进程能够协调工作
-
补充说明
-
命名管道(FIFO)与匿名管道的区别在于它有文件系统中的名称,可用于无亲缘关系进程间通信
-
管道的缓冲区大小有限(通常为几KB),超出时会阻塞写入
-
所有写入端关闭后,读取会返回EOF(读取返回0)
-
所有读取端关闭后,写入会产生SIGPIPE信号
2.管道通信的四种典型场景分析
1. 读取完毕后的等待
-
场景:读取端已经读取完管道中的所有数据
-
行为:如果写入端没有新数据写入,读取操作会阻塞等待
-
原因:这是管道的内置同步机制,避免忙等待
-
解除阻塞条件:写入端写入新数据或关闭写入端
2. 管道写满的情况
-
场景:写入端将管道缓冲区写满(通常4KB-64KB不等,取决于系统)
-
行为:
-
继续写入操作会阻塞
-
直到读取端读取部分数据腾出空间
-
-
特殊情况:如果写入端设置为非阻塞模式,写满时会立即返回
EAGAIN
错误
3. 写端关闭后的读取
-
场景:写端关闭且管道数据已全部读取完毕
-
行为:
-
再次读取时
read()
会返回0 -
这表示到达了"文件结束"(EOF)
-
-
意义:这是进程间通信的正常终止信号
4. 读端关闭后的写入(危险场景)
-
场景:读端已关闭,但写端仍在尝试写入
-
行为:
-
操作系统认为这是无意义的操作
-
内核会向写入进程发送
SIGPIPE
信号(信号编号13) -
默认情况下该信号会终止进程
-
-
编程建议:
-
应该处理
SIGPIPE
信号或检查write()
的返回值 -
write()
会返回-1
且设置errno
为EPIPE
-
重要补充
-
这些行为保证了管道通信的健壮性和资源有效性
-
在实际编程中,应该考虑:
-
正确处理阻塞/非阻塞模式
-
检查所有系统调用的返回值
-
考虑使用
select()
/poll()
等多路复用机制 -
必要时处理
SIGPIPE
信号避免意外终止
-