C语言中如何不阻塞父进程即可获取子进程的运行状态
问题原因
你的代码出现该问题有两个核心原因:
waitpid带WNOHANG参数的调用时机错误:你在fork完成后立刻调用了waitpid(p,&status,WNOHANG),此时子进程大概率还没被系统调度执行、更没有完成退出。WNOHANG的逻辑是如果检测到目标子进程仍在运行,会立刻返回0,不会修改传入的status变量,也不会阻塞父进程后续执行。你后续sleep的5秒期间子进程已经退出,但你没有再次调用waitpid获取状态,所以status始终是初始的垃圾值。- 局部变量
status未初始化:你定义int status;时没有给初始值,它的初始值是栈内存里的随机垃圾值,也会干扰你的判断。
实现非阻塞查询子进程状态的方案
首先你要明确waitpid带WNOHANG时的返回值含义,不要仅靠status判断状态:
- 返回值 > 0:目标子进程已经退出,返回值就是退出的子进程PID,此时status会被正常填充,可以用
WIFEXITED、WEXITSTATUS等宏解析子进程的退出状态 - 返回值 == 0:目标子进程仍在运行,此时status不会被修改
- 返回值 < 0:调用出错,一般是目标子进程不存在等场景
你需要在父进程处理其他任务的间隙,重复调用带WNOHANG的waitpid,直到返回值大于0或者小于0,就能实现非阻塞的状态查询。
修正后的示例代码
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> int main(){ int status = 0; // 初始化变量避免垃圾值干扰 pid_t p = fork(); if(p == 0){ printf("子进程运行中\n"); sleep(2); // 模拟子进程的耗时任务 printf("子进程运行结束,准备退出\n"); exit(0); } else if(p > 0){ printf("父进程运行中,开始处理其他任务\n"); pid_t wait_ret; int task_count = 0; // 父进程循环处理自有任务,间隙检查子进程状态 while(1){ // 非阻塞查询子进程状态 wait_ret = waitpid(p, &status, WNOHANG); if(wait_ret > 0){ printf("检测到子进程已退出,退出状态码:%d\n", WEXITSTATUS(status)); break; } else if(wait_ret < 0){ perror("waitpid调用出错"); break; } // 子进程还在运行,父进程继续处理自有任务 printf("父进程正在处理第%d轮任务,子进程仍在运行\n", ++task_count); sleep(1); // 模拟父进程的任务耗时 } exit(0); } return 0; }
代码说明
- 父进程每处理一轮自有任务,就调用一次
waitpid检查子进程状态,全程不会阻塞父进程的正常任务执行 - 通过
wait_ret的返回值判断子进程状态,比直接读取status更可靠 - 用
WEXITSTATUS宏解析status可以拿到子进程exit()传入的正确退出码,避免读取到status的原始编码值(里面包含了信号、退出状态等多段信息,不能直接打印)
内容的提问来源于stack exchange,提问作者n_prime
相关产品推荐
相关产品推荐

