独立文件进程间管道通信故障排查求助
管道进程通信问题:P1发送的十六进制数据P2接收不到
问题描述
我在大型项目中需要实现两个进程通过管道通信:P1生成50到99的数字,转为十六进制后通过管道发送给P2,P2负责打印该数字。但目前仅能打印
P1 generated: xxx,P2完全没有输出,尝试多种方法都没解决,请求协助排查错误。
原代码片段
pipe1.c
#define WRITE 1 #define READ 0 int main() { int i; char hex[30]; int my_pipe[2]; pipe(my_pipe); int var; close(my_pipe[READ]); for(i=50;i<100;i++){ printf("P1 generated: %d\n",i); sprintf(hex, "%x", i); write(my_pipe[WRITE], &hex, sizeof(hex)); printf("P1 in hex %s\n",hex); sleep(3); } return 0; }
pipe2.c
#define WRITE 1 #define READ 0 int main() { char hex[30]; int my_pipe2[2]; pipe(my_pipe2); int var; close(my_pipe2[WRITE]); for(;;){ read(my_pipe2[READ], &hex, sizeof(hex)); printf("P2 received: %s",hex); sleep(3); } return 0; }
主启动代码
int main(int argc, char *argv[]) { //..... if (fork() == 0) { execlp("./pipe1", "./pipe1", NULL); } sleep(1); if (fork() == 0) { execlp("./pipe2", "./pipe2", NULL); } sleep(1); //.... }
问题根源分析
你遇到的核心问题是两个子进程使用的是完全独立的管道,根本没有建立起通信链路:
pipe1.c里自己创建了一个管道,往这个管道写数据;pipe2.c里也自己创建了另一个完全无关的管道,从这个空管道读数据;- 主进程创建的两个子进程完全不知道对方的存在,自然无法通信。
另外还有两个次要问题:
write和read里的&hex是多余的——hex作为数组名本身就是指向数组首元素的指针,不需要取地址;- P2的
printf没有加换行符\n,会导致输出被标准输出缓冲,即使收到数据也可能看不到。
修正后的完整解决方案
我们需要让主进程创建共享管道,然后将管道的文件描述符传递给两个子进程,这样它们才能使用同一个管道进行读写。
1. 修正主启动代码
主进程先创建管道,然后把管道的写端传给P1,读端传给P2:
#include <unistd.h> #include <stdio.h> #include <sys/wait.h> #include <stdlib.h> #define WRITE 1 #define READ 0 int main(int argc, char *argv[]) { int my_pipe[2]; // 创建管道,失败则报错 if (pipe(my_pipe) == -1) { perror("Failed to create pipe"); return 1; } // 启动P1:负责写数据 if (fork() == 0) { close(my_pipe[READ]); // P1不需要读端,关闭 char write_fd_str[10]; snprintf(write_fd_str, sizeof(write_fd_str), "%d", my_pipe[WRITE]); // 将管道写端fd作为参数传给pipe1 execlp("./pipe1", "./pipe1", write_fd_str, NULL); perror("Failed to start pipe1"); exit(1); } sleep(1); // 启动P2:负责读数据 if (fork() == 0) { close(my_pipe[WRITE]); // P2不需要写端,关闭 char read_fd_str[10]; snprintf(read_fd_str, sizeof(read_fd_str), "%d", my_pipe[READ]); // 将管道读端fd作为参数传给pipe2 execlp("./pipe2", "./pipe2", read_fd_str, NULL); perror("Failed to start pipe2"); exit(1); } // 主进程不再需要管道两端,关闭它们 close(my_pipe[READ]); close(my_pipe[WRITE]); // 等待两个子进程结束 wait(NULL); wait(NULL); return 0; }
2. 修正pipe1.c
接收主进程传递的管道写端fd,用这个fd写数据:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #define WRITE 1 #define READ 0 int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <pipe-write-fd>\n", argv[0]); return 1; } // 将命令行参数转为整数型文件描述符 int write_fd = atoi(argv[1]); int i; char hex[30]; for(i=50;i<100;i++){ printf("P1 generated: %d\n",i); sprintf(hex, "%x", i); // 直接用传入的fd写数据,hex不需要& write(write_fd, hex, sizeof(hex)); printf("P1 sent hex: %s\n", hex); sleep(3); } // 写完后关闭写端,通知P2没有数据了 close(write_fd); return 0; }
3. 修正pipe2.c
接收主进程传递的管道读端fd,用这个fd读数据,并处理管道关闭的情况:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #define WRITE 1 #define READ 0 int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <pipe-read-fd>\n", argv[0]); return 1; } // 将命令行参数转为整数型文件描述符 int read_fd = atoi(argv[1]); char hex[30]; while(1){ ssize_t bytes_read = read(read_fd, hex, sizeof(hex)); if (bytes_read <= 0) { // 管道写端已关闭(P1结束),退出循环 break; } // 添加\n确保输出立即刷新到终端 printf("P2 received: %s\n", hex); sleep(3); } // 关闭读端 close(read_fd); return 0; }
关键修正点说明
- 共享管道创建:管道由主进程创建,两个子进程继承或接收管道的fd,确保它们使用同一个通信通道;
- 关闭无用管道端:每个进程只保留自己需要的管道端,避免管道被意外保持打开导致的阻塞;
- 处理管道关闭:P2检测到
read返回<=0时,知道P1已经结束,退出循环,避免无限阻塞; - 修复输出缓冲:给P2的
printf添加\n,确保输出立即显示在终端。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

