You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:36:58