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

创建两个管道时C程序执行冻结,求问题原因及解决方法

父子进程双向通信管道冻结问题排查与修复

问题描述

尝试实现父子进程间双向通信,编写了如下C代码:

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>

int main(){
    printf("Program started.");
    int p1[2]; // CHILD => PARENT
    int p2[2]; // PARENT => CHILD

    if (pipe(p1) < 0) {return -1;}
    if (pipe(p2) < 0) {return -1;}

    int pid = fork();
    if (pid == -1) {return -2;}
    if (pid == 0)
    {//child process
        close(p1[0]);
        close(p2[1]);

        int x;
        if (read(p2[0], &x, sizeof(x)) == -1) {return 3;}
        printf("Recieved %d\n", x);
        x *= x;
        if (write(p1[1], &x, sizeof(x)) == -1) {return 4;}
        printf("Wrote %d\n", x);

        close(p1[1]);
        close(p2[0]);
    }
    else
    {//parent process
        close(p1[1]);
        close(p2[0]);

        int y = 7;
        if (write(p2[1], &y, sizeof(y) == -1)) {return 5;}
        if (read(p1[0], &y, sizeof(y)) == -1) {return 6;}
        printf("Result is %d\n", y);

        close(p1[0]);
        close(p2[1]);

        wait(NULL);
    }
    return 0; 
}

代码在Linux Ubuntu系统下gcc编译成功,但运行时出现冻结,甚至第一条printf语句都未执行。若注释掉任意一条管道创建语句,程序可正常运行(虽无法完成双向通信,但不会冻结)。

错误分析

  • write函数参数括号错误
    父进程中write的条件判断存在语法错误:

    if (write(p2[1], &y, sizeof(y) == -1)) {return 5;}
    

    这里sizeof(y) == -1被优先计算,由于sizeof(int)通常为4,4 == -1的结果为假(0),导致write的第三个参数实际是0——父进程尝试向管道写入0字节数据。此时子进程调用read(p2[0], &x, sizeof(x))会一直阻塞,因为它期望读取4字节但管道中无数据;同时父进程后续调用read(p1[0], &y, sizeof(y))也会阻塞,因为子进程未收到数据就不会向p1管道写入,最终导致父子进程互相阻塞,程序冻结。

  • printf缓冲问题
    第一条printf("Program started.");没有换行符\n,标准输出默认是行缓冲模式,在程序正常结束前不会刷新缓冲区,所以即使程序未冻结,这条信息也无法立即显示。

修正后的代码

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>

int main(){
    printf("Program started.\n"); // 添加换行符刷新缓冲区
    int p1[2]; // CHILD => PARENT
    int p2[2]; // PARENT => CHILD

    if (pipe(p1) < 0) {return -1;}
    if (pipe(p2) < 0) {return -1;}

    int pid = fork();
    if (pid == -1) {return -2;}
    if (pid == 0)
    {//child process
        close(p1[0]);
        close(p2[1]);

        int x;
        if (read(p2[0], &x, sizeof(x)) == -1) {return 3;}
        printf("Recieved %d\n", x);
        x *= x;
        if (write(p1[1], &x, sizeof(x)) == -1) {return 4;}
        printf("Wrote %d\n", x);

        close(p1[1]);
        close(p2[0]);
    }
    else
    {//parent process
        close(p1[1]);
        close(p2[0]);

        int y = 7;
        // 修正括号位置,正确判断write的返回值
        if (write(p2[1], &y, sizeof(y)) == -1) {return 5;}
        if (read(p1[0], &y, sizeof(y)) == -1) {return 6;}
        printf("Result is %d\n", y);

        close(p1[0]);
        close(p2[1]);

        wait(NULL);
    }
    return 0; 
}

运行结果

修正后程序运行会输出:

Program started.
Recieved 7
Wrote 49
Result is 49

内容的提问来源于stack exchange,提问作者kims9

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 19:05:22