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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:15:04