【无标题】无名管道
无名管道(Unnamed Pipe,也称为匿名管道)是 Unix/Linux 系统中最基础的进程间通信(IPC)机制之一,用于在有亲缘(亲缘)关系的进程(如父子进程、兄弟进程)之间进行单向问数据传输。
无名管道的核心特点
- 无标识:不像命名管道(FIFO)有文件系统中的路径标识,无名管道仅存在于内存中,进程通过文件描述符访问。
- 半双工:数据只能单向流动,如需双向通信需创建两个无名管道。
- 亲缘关系限制:仅能在父子进程、兄弟进程等有共同祖先的进程间使用(通过 fork 继承管道的文件描述符)。
- 面向字节流:数据按字节顺序传输,没有消息边界(类似 TCP 流)。
- 阻塞特性:
- 读端:管道为空时,读操作会阻塞,直到有数据写入。
- 写端:管道满时,写操作会阻塞,直到数据被读取。
- 若写端关闭,读端会读到
0
(表示数据结束);若读端关闭,写操作会触发SIGPIPE
信号(默认终止进程)。
无名管道的创建与使用
通过 pipe()
系统调用创建无名管道,函数原型:
#include <unistd.h>
int pipe(int pipefd[2]);
- 参数
pipefd
是一个长度为 2 的数组,用于存储管道的两个文件描述符:pipefd[0]
:读端(接收数据)pipefd[1]
:写端(发送数据)
- 返回值:成功返回
0
,失败返回-1
并设置errno
。
使用流程(父子进程通信示例)
- 父进程调用
pipe()
创建管道。 - 父进程调用
fork()
创建子进程,子进程会继承管道的两个文件描述符。 - 关闭不需要的端(如父进程关闭读端,子进程关闭写端,实现父→子通信)。
- 通过
write()
写入数据,read()
读取数据。 - 通信结束后关闭管道描述符。
示例代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main() {int pipefd[2];char buf[1024];// 1. 创建无名管道if (pipe(pipefd) == -1) {perror("pipe failed");return 1;}// 2. 创建子进程pid_t pid = fork();if (pid == -1) {perror("fork failed");return 1;}if (pid == 0) { // 子进程:读数据close(pipefd[1]); // 关闭子进程的写端(不需要)// 读取管道数据ssize_t n = read(pipefd[0], buf, sizeof(buf));if (n > 0) {printf("子进程收到:%.*s\n", (int)n, buf);}close(pipefd[0]); // 关闭读端return 0;} else { // 父进程:写数据close(pipefd[0]); // 关闭父进程的读端(不需要)// 向管道写入数据const char *msg = "Hello from parent!";write(pipefd[1], msg, strlen(msg));close(pipefd[1]); // 关闭写端(触发子进程读端返回0)return 0;}
}
无名管道的应用场景
- 父子进程间的简单数据传递(如父进程向子进程传递配置参数)。
- shell 中的管道命令(如
ls | grep "txt"
,通过无名管道连接ls
和grep
进程)。 - 进程间的简单协同(如子进程完成任务后向父进程发送通知)。
与命名管道(FIFO)的核心区别
特性 | 无名管道(Pipe) | 命名管道(FIFO) |
---|---|---|
标识方式 | 仅通过文件描述符,无文件路径 | 有文件系统路径(如 /tmp/myfifo ) |
适用进程 | 仅限亲缘关系进程 | 任意进程(通过路径访问) |
生命周期 | 随进程退出而销毁 | 存在于文件系统,需手动删除 |
总结:无名管道是一种轻量级的 IPC 机制,适用于亲缘进程间的简单单向通信,其设计简单、效率较高,但受限于亲缘关系和半双工特性,无法满足复杂通信场景。