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

C语言多进程程序为何在wait(NULL)处阻塞?

问题:父进程卡在wait(NULL)无法获取子进程strace输出

我是一名C语言初学者,编写了一个多进程程序,希望让子进程调用strace,再通过管道将输出传递给父进程进行打印。但父进程似乎卡在了wait(NULL);处,我尝试注释掉wait(NULL);后,就能正常获取子进程的输出。我无法理解父进程为何一直处于等待状态,子进程难道还没退出吗?

以下是我的代码:

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

int main(int argc, char *argv[]) {
  int pipefd[2];
  pid_t pid;
  char *exec_argv[] = { "/bin/strace", "-T", "tree", "/bin", NULL};
  char *exec_envp[] = { "PATH=/bin", NULL };

  if (pipe(pipefd) == -1) {
    perror("pipe");
    exit(EXIT_FAILURE);
  }
  pid = fork();
  if (pid < 0) {
    perror("fork");
    exit(EXIT_FAILURE);
  } else if (pid == 0) { // child
    close(pipefd[0]);   /* close unused read end */
    close(STDOUT_FILENO);
    if (dup2(pipefd[1], STDERR_FILENO) == -1) {
      perror("dup2");
      exit(EXIT_FAILURE);
    }
    // invoke strace
    execve(exec_argv[0], exec_argv, exec_envp);
    perror(exec_argv[0]);
    exit(EXIT_FAILURE);
  } else {  // parent
    close(pipefd[1]);   /* close unused write end */
    if (dup2(pipefd[0], STDIN_FILENO) == -1) {
      perror("dup2");
      exit(EXIT_FAILURE);
    }
    printf("I'm parent!!!\n");
    wait(NULL);
    char *line = NULL;
    size_t len;
    while (getline(&line, &len, stdin) != -1) {
      printf("%s", line);
    }
    free(line);
  }
  return 0;
}

问题原因

这是管道读写阻塞导致的死锁:

  • 子进程通过dup2把stderr重定向到管道写端,strace的输出会持续往管道里写
  • 父进程先调用wait(NULL)等待子进程退出,但管道缓冲区有大小限制,当子进程把缓冲区写满后,会被阻塞,等待父进程读取管道数据
  • 此时父进程在等子进程退出,子进程在等父进程读管道,双方互相等待,形成死锁

解决方法

调整父进程的代码逻辑,先读取管道数据,再等待子进程退出:

else {  // parent
  close(pipefd[1]);   /* close unused write end */
  if (dup2(pipefd[0], STDIN_FILENO) == -1) {
    perror("dup2");
    exit(EXIT_FAILURE);
  }
  printf("I'm parent!!!\n");
  
  // 先读取管道数据,子进程写完后会自动退出
  char *line = NULL;
  size_t len;
  while (getline(&line, &len, stdin) != -1) {
    printf("%s", line);
  }
  free(line);
  
  wait(NULL);  // 此时子进程已退出,wait不会阻塞
}

补充说明

  • 管道的规则是:当所有读端关闭时,写端进程会收到SIGPIPE信号退出;当所有写端关闭时,读端的getline会返回-1(表示EOF)
  • 原来的逻辑中,父进程没读管道,子进程写满缓冲区后卡住,导致wait永远等不到子进程退出
  • 调整顺序后,父进程持续读取管道数据,子进程可以顺利写完输出并退出,wait就能正常获取子进程的退出状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:09:24