C语言fork多进程场景下获取已终止子进程exit status问题排查
问题根因
- 代码中的
pid变量在for循环fork结束后,只会保留最后一次fork生成的子进程PID,后续while循环里反复调用waitpid(pid, ...)只会等待这一个子进程,其余子进程都会变成僵尸进程无法被回收,也拿不到它们的退出状态 - 原逻辑没有对
waitpid返回的状态值做解析,直接根据调用是否失败来累加成功/失败计数,统计逻辑完全错误 waitpid第一个参数传-1的时候才会等待任意一个子进程退出,这才是符合需求的逻辑
修复后完整代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <errno.h> int main(int argc, char *argv[]) { pid_t pid; int i, stat, suc = 0, fail = 0; if (argc < 2){ printf("Usage: ./wordcount.exe [File_1] [File_2] [...] [File_n]\n"); exit(1); } for (i = 1; i < argc; i++){ if ((pid = fork()) == 0){ if (access(argv[i], F_OK) != 0){ fprintf(stderr, "Child process %ld for %s does not exist\n", (long)getpid(), argv[i]); return 1; } fprintf(stderr, "Child process %ld for %s: Number of words is: %d\n", (long)getpid(), argv[i], 0); exit(0); } } // 修复子进程等待与状态统计逻辑 while(1){ // 第一个参数传-1:等待任意子进程退出 pid = waitpid(-1, &stat, 0); if (pid == -1) { // 没有更多子进程需要等待时退出循环 if (errno == ECHILD) break; // 被信号中断则重试 else if (errno == EINTR) continue; else perror("waitpid error"); } // 解析子进程退出状态 if (WIFEXITED(stat)) { int exit_code = WEXITSTATUS(stat); printf("pid = %d\t exit status=%d\n", pid, exit_code); if (exit_code == 0) suc++; else if (exit_code == 1) fail++; } } printf("Parent process created %d processes to count %d words in %d files\n", (suc + fail), 0, (suc + fail)); printf("%d file(s) have been counted successfully!\n", suc); printf("%d file(s) did not exist.\n", fail); return 0; }
核心修改点说明
- 将
waitpid第一个参数改为-1,表示等待任意一个子进程终止,每次调用返回终止的子进程PID - 新增状态解析逻辑:用
WIFEXITED判断子进程是否正常退出,再用WEXITSTATUS获取子进程的返回值,根据返回值累加成功/失败计数 - 退出循环的条件改为
errno == ECHILD,表示当前没有剩余子进程需要等待,此时才终止循环
内容的提问来源于stack exchange,提问作者Cal3bK
相关产品推荐
相关产品推荐

