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

如何用fork、wait、waitpid让父进程等待所有层级子进程执行完毕?

解决方法:用wait/waitpid等待子进程,确保进程状态可被ps捕获

问题根源

你的子进程因为执行逻辑太简单(无耗时操作),在父进程调用system("ps")前就已退出,导致ps无法捕获;同时未调用wait/waitpid的话,退出的子进程会变成僵尸进程(如当前输出里的[a]),无法正常显示为运行状态。

核心思路

  1. 让子进程保持运行直到父进程执行ps:给子进程添加sleep()等延时操作,避免提前退出。
  2. 每个父进程(包括中间进程)等待自己的直接子进程:顶层父进程等待自己创建的中间进程、另一个子进程;中间进程等待自己的子进程,避免出现孤儿进程或僵尸进程。
  3. 顶层父进程在所有子进程运行时执行ps,之后再等待所有子进程完成(满足你看到完整进程列表的需求)。

方法1:用wait()等待所有直接子进程

wait()会阻塞当前进程,直到任意一个直接子进程退出,返回该子进程的PID。需要针对每个子进程单独调用,或循环调用直到所有子进程被回收。

示例代码

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

int main() {
    pid_t pid_mid, pid_child;

    // 创建中间进程
    pid_mid = fork();
    if (pid_mid == 0) {
        // 中间进程创建自己的子进程
        pid_t pid_grand = fork();
        if (pid_grand == 0) {
            // 中间进程的子进程:保持运行2秒,让父进程ps能捕获到
            printf("中间进程的子进程 PID: %d,PPID: %d\n", getpid(), getppid());
            sleep(2);
            exit(0);
        } else if (pid_grand > 0) {
            // 中间进程:等待自己的子进程完成
            wait(NULL);
            printf("中间进程 %d 已等待子进程完成\n", getpid());
            sleep(1);
            exit(0);
        } else {
            perror("创建中间进程的子进程失败");
            exit(1);
        }
    } else if (pid_mid > 0) {
        // 顶层父进程:创建另一个子进程
        pid_child = fork();
        if (pid_child == 0) {
            printf("另一个子进程 PID: %d,PPID: %d\n", getpid(), getppid());
            sleep(2);
            exit(0);
        } else if (pid_child > 0) {
            // 执行ps命令,此时所有子进程都在运行
            printf("\n=== 当前进程状态 ===\n");
            system("ps -f --ppid 306,%d,%d", getpid(), pid_mid); // 替换306为你的实际父进程PID
            // 等待所有直接子进程完成
            int status;
            waitpid(pid_mid, &status, 0); // 等待中间进程
            waitpid(pid_child, &status, 0); // 等待另一个子进程
            printf("\n所有子进程已完成\n");
        } else {
            perror("创建另一个子进程失败");
            exit(1);
        }
    } else {
        perror("创建中间进程失败");
        exit(1);
    }

    return 0;
}

方法2:用waitpid()灵活等待所有子进程

waitpid()可以指定等待特定PID的子进程,或用-1等待任意子进程,适合不确定子进程数量的场景。

示例代码(循环等待所有子进程)

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

int main() {
    int child_num = 0;
    pid_t pid;

    // 创建中间进程
    pid = fork();
    if (pid == 0) {
        // 中间进程创建子进程
        pid_t grand_pid = fork();
        if (grand_pid == 0) {
            printf("孙子进程 PID: %d,PPID: %d\n", getpid(), getppid());
            sleep(2);
            exit(0);
        } else if (grand_pid > 0) {
            waitpid(grand_pid, NULL, 0); // 中间进程等待自己的子进程
            printf("中间进程 %d 已等待孙子进程完成\n", getpid());
            sleep(1);
            exit(0);
        }
        perror("创建孙子进程失败");
        exit(1);
    } else if (pid > 0) {
        child_num++;
    } else {
        perror("创建中间进程失败");
        exit(1);
    }

    // 创建另一个子进程
    pid = fork();
    if (pid == 0) {
        printf("另一个子进程 PID: %d,PPID: %d\n", getpid(), getppid());
        sleep(2);
        exit(0);
    } else if (pid > 0) {
        child_num++;
    } else {
        perror("创建另一个子进程失败");
        exit(1);
    }

    // 执行ps查看进程状态
    printf("\n=== 进程状态 ===\n");
    system("ps -f --ppid 306,%d", getpid()); // 替换306为你的实际父进程PID

    // 循环等待所有直接子进程完成
    printf("\n等待所有子进程结束...\n");
    while (child_num > 0) {
        pid_t finished_pid = waitpid(-1, NULL, 0);
        if (finished_pid > 0) {
            printf("子进程 %d 已完成\n", finished_pid);
            child_num--;
        }
    }

    printf("所有子进程处理完毕\n");
    return 0;
}

关键说明

  1. 子进程延时:添加sleep()是为了让父进程的ps命令能捕获到运行中的子进程,否则子进程会瞬间退出,ps只能看到僵尸进程或完全看不到。
  2. 层级等待:中间进程必须等待自己的子进程,否则孙子进程会变成孤儿进程,被系统init/systemd进程收养,顶层父进程无法通过wait捕获它。
  3. wait与waitpid的区别:
    • wait():阻塞等待任意一个直接子进程退出,无法指定PID。
    • waitpid():可以指定等待某个PID的子进程,或用-1等待任意子进程,还能通过WNOHANG选项实现非阻塞等待(不阻塞父进程,轮询子进程状态)。

内容的提问来源于stack exchange,提问作者Anuj Shah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:45:33