创建两个管道时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
相关产品推荐
相关产品推荐

