为何pipe系统调用读写未阻塞?代码运行异常求解
问题分析:管道同步未生效的原因
你的代码核心问题在于使用read(fd, NULL, 0)和write(fd, NULL, 0)无法实现进程间的阻塞同步,这两个调用不会触发管道的阻塞逻辑,导致父子进程各自循环完全串行执行。
关键原因:0字节读写的行为特性
根据POSIX标准:
read(fd, buf, 0):无论管道是否有数据、写端是否关闭,都会立即返回0,不会阻塞。write(fd, buf, 0):无论管道是否满、读端是否关闭,都会立即返回0,不会阻塞。
所以你的代码里,父子进程的循环中,write和read调用都直接跳过,没有任何等待逻辑。父进程会一口气跑完10次循环,之后调度器才切换到子进程执行,最终出现全父进程输出后全子进程输出的结果。
修正方案:使用有效字节实现同步
要实现父子进程交替执行的预期效果,需要通过管道传递至少1字节的数据,利用管道的阻塞特性:
- 父进程写入1字节后,尝试读取子进程的管道数据(此时无数据,阻塞)
- 子进程读取到父进程的字节后,输出,再写入1字节唤醒父进程
- 循环往复
修正后的代码示例:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int ffd[2], sfd[2]; if (pipe(ffd) < 0) { perror("pipe"); exit(EXIT_FAILURE); } if (pipe(sfd) < 0) { perror("pipe"); exit(EXIT_FAILURE); } int n = 10, rc; char buf; // 用于传递1字节数据 rc = fork(); if (rc < 0) { perror("fork"); exit(EXIT_FAILURE); } if (rc == 0) { for (size_t i = 0; i < n; i++) { read(ffd[0], &buf, 1); // 等待父进程的信号 printf("child - %ld\n", i); write(sfd[1], &buf, 1); // 发送信号给父进程 } } else { for (size_t i = 0; i < n; i++) { printf("parent - %ld\n", i); write(ffd[1], &buf, 1); // 发送信号给子进程 read(sfd[0], &buf, 1); // 等待子进程的信号 } } // 关闭管道描述符(良好实践) close(ffd[0]); close(ffd[1]); close(sfd[0]); close(sfd[1]); return 0; }
额外说明
- 管道的阻塞逻辑是:当管道为空时,
read会阻塞直到有数据可读或所有写端关闭;当管道满时,write会阻塞直到有空间或所有读端关闭。 - 0字节读写属于特殊情况,仅用于检查文件描述符的有效性(比如是否可读写),不会触发任何阻塞。
内容的提问来源于stack exchange,提问作者askaquestion
相关产品推荐
相关产品推荐

