C语言父子进程通过管道与clang-format通信时read()挂起问题求解
问题根因
核心问题是父进程写完待格式化代码后,没有关闭fd2[1]管道写端:
- Linux管道的读端只有在所有关联的写端都被关闭时,才会返回EOF(read调用返回0)
- 你在父进程中调用
write(fd2[1], code, codeLen)写完代码后,始终没有关闭fd2[1],clang-format进程会认为还有后续数据要输入,一直阻塞在标准输入的读取逻辑,不会输出处理结果 - 父进程的
read(fd[0], ...)自然会一直等待子进程输出,出现永久挂起
修复方案
只需在父进程写完数据后,主动关闭fd2[1]即可通知子进程输入已经结束,修复后的完整代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> int main() { int fd[2]; int fd2[2]; pid_t childPid; pipe(fd); pipe(fd2); if ((childPid = fork()) == -1) { perror("fork"); exit(1); } if (childPid == 0) { dup2(fd[1], 1); close(fd[0]); dup2(fd2[0], 0); close(fd2[1]); execlp("clang-format", "clang-format", (char *)NULL); // 补充execlp执行失败的退出逻辑,避免子进程异常残留 perror("execlp"); exit(1); } else { close(fd[1]); close(fd2[0]); char code[] = "void\n cool\n(int num){return num +1;}\n"; size_t codeLen = strlen(code); write(fd2[1], code, codeLen); close(fd2[1]); // 新增这行,关闭输入管道写端 char buf[401]; ssize_t msgLen = read(fd[0], buf, 400); buf[msgLen] = '\0'; printf("message from child: %s :end of message.\n", buf); } }
调试思路
这类管道通信挂起问题可以用以下方法快速定位:
- 用
strace -f 可执行文件路径命令跟踪所有进程的系统调用,能直接看到父子进程分别阻塞在哪个系统调用上,本例中可以看到子进程阻塞在标准输入的read调用,父进程阻塞在管道的read调用,就能定位是输入结束信号没有传递给子进程 - 编写管道通信代码时遵循最佳实践:所有进程不需要用到的管道端点,在fork/dup操作后立刻关闭,避免残留未关闭的端点导致逻辑异常
内容的提问来源于stack exchange,提问作者Max888
相关产品推荐
相关产品推荐

