如何使用 C++ 在 Linux 环境下进行管道(pipe)系统调用
pipe() 系统调用
在 Linux 系统编程中,pipe() 是一个系统调用,用于创建一个匿名管道,实现同一进程或父子进程间的单向通信。管道有两个文件描述符:一个用于读取(读端),一个用于写入(写端)。
pipe() 函数原型
1 |
|
-
pipefd是一个包含两个整数的数组,用于存储管道的文件描述符
pipefd[0]:管道的读端,用于读取数据pipefd[1]:管道的写端,用于写入数据
-
返回值:成功返回 0,失败返回 -1 并设置
errno
使用步骤
-
创建管道:调用
pipe()函数 -
创建子进程:使用
fork()创建子进程(管道通常用于父子进程间通信) -
关闭不需要的端:
- 父进程关闭读端(
pipefd[0]),只写 - 子进程关闭写端(
pipefd[1]),只读(或根据需求调整,如父进程读、子进程写)
- 父进程关闭读端(
-
通信:通过
write()写入数据,read()读取数据 -
关闭管道:通信完成后关闭所有文件描述符
示例代码
1 |
|
代码说明
-
管道创建:
pipe(pipefd)成功后,pipefd[0]和pipefd[1]分别代表读端和写端 -
进程通信
- 父进程通过
write(pipefd[1], ...)向管道写入数据 - 子进程通过
read(pipefd[0], ...)从管道读取数据
- 父进程通过
-
关闭端的重要性
- 不使用的端必须关闭,否则可能导致
read()阻塞(等待数据) - 所有写端关闭后,
read()会返回 0(表示数据结束)
- 不使用的端必须关闭,否则可能导致
-
单向性:管道是单向的,数据只能从写端流向读端
核心原则:按需保留,及时关闭,全量清理
-
“先关闭,后通信” 的原则:进程创建后(如
fork()后),应立即关闭不需要的端,再进行读写操作。例如:- 父进程若负责写数据,应先关闭读端(
pipefd[0]),仅保留写端(pipefd[1]); - 子进程若负责读数据,应先关闭写端(
pipefd[1]),仅保留读端(pipefd[0])。避免因 “未及时关闭” 导致的意外数据交互(如子进程误写数据到本应关闭的写端)。
- 父进程若负责写数据,应先关闭读端(
-
写端关闭的 “触发信号” 作用:写端完成数据发送后,必须主动关闭写端,这是告知读端 “数据已发送完毕” 的唯一方式。读端通过
read()返回 0 感知 “所有写端已关闭”,从而正常退出读取逻辑。- 反例:若父进程写完数据后未关闭写端,子进程的
read()会一直阻塞(等待更多数据),导致子进程无法退出。
- 反例:若父进程写完数据后未关闭写端,子进程的
-
多进程协作时的 “全关闭” 检查:若多个进程共享同一管道的写端(如父进程和多个子进程都向管道写数据),必须确保所有写端都关闭后,读端才能收到 EOF(
read()返回 0)。- 需通过进程同步(如
waitpid)确保所有写进程都已关闭写端,避免读端提前退出或阻塞。
- 需通过进程同步(如