无名管道
2026/8/25大约 3 分钟
Linux 进程间通信:无名管道 Pipe
1. Pipe 是什么
Pipe(无名管道)是 Linux 最简单的 IPC 机制之一。
核心思想:
父进程
│
write()
↓
┌──────────────┐
│ Pipe │
│ 内核缓冲区 │
└──────────────┘
│
read()
↓
子进程特点:
- 半双工
- 字节流
- 通常用于有亲缘关系的进程
fork()后子进程继承父进程的文件描述符
核心 API:
pipe() // 创建管道
fork() // 创建子进程
read() // 读取
write() // 写入
close() // 关闭
waitpid() // 等待子进程2. 创建管道
int pipe_fd[2];
pipe(pipe_fd);成功后:
pipe_fd[0] → 读端
pipe_fd[1] → 写端因此:
write(pipe_fd[1], data, len);表示写入管道。
read(pipe_fd[0], buf, sizeof(buf));表示从管道读取。
3. 为什么要 fork()?
pid_t pid = fork();fork() 后产生父、子两个进程。
关键点:
子进程会继承父进程打开的文件描述符。
因此:
fork() 前:
父进程
├── pipe_fd[0] → Pipe读端
└── pipe_fd[1] → Pipe写端
fork() 后:
父进程 子进程
├── pipe_fd[0] ─────────┐ ┌── pipe_fd[0]
└── pipe_fd[1] ───────┐ │ │ └── pipe_fd[1]
↓ ↓
同一个 Pipe这就是父子进程能够通信的原因。
4. 父子进程分别关闭一端
如果设计成:
父进程 → 写
子进程 → 读那么:
父进程:
close(pipe_fd[0]);关闭读端,只保留:
pipe_fd[1] → 写子进程:
close(pipe_fd[1]);关闭写端,只保留:
pipe_fd[0] → 读最终:
父进程 子进程
pipe_fd[1] pipe_fd[0]
│ │
write() read()
│ │
└────────── Pipe ──────────────┘5. 父进程写数据
const char data[] = "Pipe Test Program!";
write(pipe_fd[1],
data,
strlen(data));数据流:
data
↓
write()
↓
Pipe6. 子进程读取
char buf[256] = {0};
read(pipe_fd[0],
buf,
sizeof(buf));数据流:
Pipe
↓
read()
↓
buf
↓
printf()所以完整过程:
父进程
│
│ write("Pipe Test Program!")
↓
┌─────────────────────┐
│ Pipe │
└─────────────────────┘
│
│ read()
↓
子进程 buf7. read() 为什么可以等待?
Pipe 默认是阻塞的。
如果:
Pipe 中没有数据此时:
read(pipe_fd[0], buf, sizeof(buf));可能阻塞。
直到:
父进程 write()
↓
Pipe 中出现数据
↓
子进程 read() 返回所以不需要依靠 sleep() 来保证通信顺序。
8. waitpid() 是干什么的?
父进程最后:
waitpid(pid, NULL, 0);它不是 Pipe 通信的一部分。
作用是:
父进程等待子进程执行结束。
所以这段程序实际上涉及两个知识点:
IPC:
pipe() + read() + write()
进程管理:
fork() + waitpid()9. Pipe 最核心的记忆点
pipe()
↓
得到两个 fd
↓
fork()
↓
子进程继承 fd
↓
父写、子读
↓
read/write 通信一句话:
Pipe 的核心是:
pipe()创建管道,fork()让子进程继承文件描述符,从而建立父子进程之间的通信通道。
完整实现
/** 父进程通过无名管道pipe向子进程发送一个字符串数据 **/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_DATA_LEN 256
#define DELAY_TIME 3
int main(){
pid_t pid;
int pipe_fd[2];
char buf[MAX_DATA_LEN];
const char data[] = "Pipe Test Program!";
int real_read,real_write;
memset(buf, 0, sizeof(buf));
if(pipe(pipe_fd) < 0){ //创建管道
perror("fail to pipe!\n");
exit(-1);
}
pid=fork();
if(pid== 0){ //创建一个子进程
close(pipe_fd[1]); //子进程中首先关闭写描述符
sleep(DELAY_TIME); //子进程暂停1秒以等待父进程关闭其读描述符
if( (real_read=read(pipe_fd[0], buf, MAX_DATA_LEN))>0 ){ //子进程从无名管道读取内容
printf("%d bytes read from the pipe: '%s'\n",real_read, buf);
}
close(pipe_fd[0]); //子进程关闭读描述符
exit(0);
}
else if(pid>0){
close(pipe_fd[0]); //父进程中首先关闭读描述符
if( (real_write=write(pipe_fd[1], data, strlen(data))) != -1 ){ //父进程向无名管道写入内容
printf("parent wrote %d bytes: '%s'\n", real_write, data);
}
close(pipe_fd[1]); //父进程关闭写描述符
waitpid(pid, NULL, 0); //父进程阻塞,等待子进程执行完毕
exit(0);
}
}
