pipe 是 POSIX 標準提供的進程間通信(IPC)機制,創建一個單向數據管道,返回一對文件描述符:fd[0] 用於讀取,fd[1] 用於寫入。數據在內核緩衝區中流動,遵循先進先出(FIFO)原則。
#include <unistd.h>
int pipe(int pipefd[2]);
pipefd[0]、pipefd[1] 分別為讀/寫端描述符errno(如 EMFILE、ENFILE、EFAULT)SIGPIPE)PIPE_BUF(≥512 字節)以內寫入保證原子#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int fd[2];
if (pipe(fd) == -1) {
perror("pipe");
return 1;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return 1;
}
if (pid == 0) { // 子進程:寫入
close(fd[0]); // 關閉讀端
const char* msg = "Hello from child!";
write(fd[1], msg, strlen(msg) + 1); // 含結束符
close(fd[1]); // 關閉寫端,發送 EOF
return 0;
} else { // 父進程:讀取
close(fd[1]); // 關閉寫端
char buf[128];
ssize_t n = read(fd[0], buf, sizeof(buf));
if (n > 0) {
buf[n] = '\0';
printf("Parent received: %s\n", buf);
}
close(fd[0]);
wait(NULL); // 回收子進程
}
return 0;
}
每個進程只保留需要的描述符,務必關閉另一端。否則:
SIGPIPE,持續阻塞Linux 管道默認 64KB。寫入超過容量會阻塞,需配合 select/poll/epoll 或非阻塞模式(O_NONBLOCK)處理高併發場景。
讀端關閉後寫入會觸發 SIGPIPE 導致進程終止。常見處理:
signal(SIGPIPE, SIG_IGN); // 忽略信號,write 返回 EPIPE
// 或
int flags = fcntl(fd[1], F_GETFL);
fcntl(fd[1], F_SETFL, flags | O_NONBLOCK); // 非阻塞模式
需創建兩個管道:
int fd1[2], fd2[2];
pipe(fd1); // 父→子
pipe(fd2); // 子→父
父進程保留 fd1[1]、fd2[0];子進程保留 fd1[0]、fd2[1]。
| 特性 | pipe(無名管道) | mkfifo(命名管道) |
|---|---|---|
| 適用範圍 | 親緣進程 | 任意進程 |
| 創建方式 | pipe() | mkfifo() + open() |
| 持久性 | 進程結束消失 | 文件系統持久存在 |
| 打開阻塞 | 無 | 雙端打開前阻塞 |
pipe 是 Unix 哲學「一切皆文件」的經典體現,以簡潔的文件描述符抽象實現進程間數據流傳輸。掌握其阻塞語義、描述符管理、信號處理等細節,是進行系統級編程的基礎功力。實際項目中,常配合 fork、exec、dup2 實現 Shell 管道、進程重定向等高級功能。