Linux C语言下父进程正确获取子进程停止/继续/退出状态的方法
问题根因与修正方案
一、语法错误修正
现有代码存在笔误,会直接导致编译失败:
- 函数定义
int waiting4pid()(pid_t processID)多了一对空括号,正确应为int waiting4pid(pid_t processID) - 所有调用处的
waiting4pid()(processID)同样多了空括号,正确应为waiting4pid(processID)
二、异常原因分析
waitpid的返回值与传入的flags直接相关,原有waiting4pid的循环逻辑不符合获取子进程停止、继续、退出三类状态的需求:
- 不带
WNOHANG时的阻塞原因
原有while (waitpid(...) > 0)循环会在拿到一次状态后,立刻再次调用waitpid等待下一个状态事件。
第一次发送SIGSTOP后,waitpid会立刻返回子进程的停止状态,处理完成后循环进入下一次waitpid调用,此时没有新的状态事件,waitpid就会阻塞,直到后续发送SIGCONT才返回继续状态,表现为“子进程恢复运行时waitpid阻塞”。 - 带
WNOHANG时捕获不到停止状态的原因WNOHANG的作用是无状态事件时立刻返回0,不会等待。发送SIGSTOP后立刻调用waitpid(WNOHANG)时,子进程尚未完成停止状态切换,内核还未生成可获取的停止事件,waitpid直接返回0,while循环判断返回值不大于0直接退出,因此捕获不到停止状态。
三、阻塞模式正确实现
按照需求“每发送一个信号后,捕获对应状态即返回”的逻辑,修改waiting4pid函数,去掉多余的循环:
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdio.h> // 阻塞等待任意子进程状态事件,处理后立即返回 int waiting4pid(pid_t processID) { int currentState; pid_t waitRet = waitpid(processID, ¤tState, WUNTRACED | WCONTINUED); if (waitRet == -1) { perror("waitpid error"); return -1; } if(WIFCONTINUED(currentState)){ printf("\n currentState = continued!\n"); } if(WIFSIGNALED(currentState)){ printf("\n currentState = signaled!\n"); } if(WIFSTOPPED(currentState)){ printf("\n currentState = stopped!\n"); } return 0; } void sigTest() { pid_t processID; processID = fork(); if(processID ==0) { // 子进程逻辑 // tmp/loop 为25秒计数的测试程序 execlp("tmp/loop", "tmp/loop", NULL); // exec失败时直接退出,避免执行父进程逻辑 perror("execlp error"); _exit(1); }else{ // 父进程逻辑 sleep(2); printf("\n Stop!"); kill(processID, SIGSTOP); waiting4pid(processID); sleep(2); printf("\n Continue!"); kill(processID,SIGCONT); waiting4pid(processID); sleep(2); printf("\n Kill!"); kill(processID, SIGKILL); waiting4pid(processID); } } int main() { sigTest(); return 0; }
四、非阻塞模式(带WNOHANG)实现
若父进程需要在等待子进程状态的同时处理其他逻辑,可修改为轮询模式,持续检查直到拿到目标状态:
int waiting4pid(pid_t processID) { int currentState; while (1) { pid_t waitRet = waitpid(processID, ¤tState, WUNTRACED | WCONTINUED | WNOHANG); if (waitRet == -1) { perror("waitpid error"); return -1; } if (waitRet == 0) { // 暂时无状态事件,可在此插入其他处理逻辑,休眠避免CPU空转 usleep(10000); continue; } // 拿到状态事件,处理后返回 if(WIFCONTINUED(currentState)){ printf("\n currentState = continued!\n"); } if(WIFSIGNALED(currentState)){ printf("\n currentState = signaled!\n"); } if(WIFSTOPPED(currentState)){ printf("\n currentState = stopped!\n"); } return 0; } }
注意:轮询模式下每次无事件时增加10ms休眠,避免CPU被空转占满。
内容的提问来源于stack exchange,提问作者John Alway
相关产品推荐
相关产品推荐

