c - 使用 waitpid 和 WNOHANG 区分进程状态
问题描述
在构建 shell 程序时,我面临识别进程状态的问题。waitpid
我面临的问题的描述是我有一个子进程列表,我正在尝试使用and找出它们的状态WNOHANG
。我希望区分 3 种状态TERMINATED
:RUNNING
和SUSPENDED
。(在下面的代码中定义)我希望将进程状态更改为上述三个之一,但是现在这个函数使正在运行的进程状态为terminated
,并且这个函数也不能识别挂起的进程。我想知道我做错了什么以及应该如何updateProcessList
编写函数来实现它?
#define TERMINATED -1
#define RUNNING 1
#define SUSPENDED 0
typedef struct process{
cmdLine* cmd; /* the parsed command line*/
pid_t pid; /* the process id that is running the command*/
int status; /* status of the process: RUNNING/SUSPENDED/TERMINATED */
struct process *next; /* next process in chain */
} process;
void updateProcessList(process **process_list) {
process *p = *process_list;
int code = 0, status = 0,pidd = 0;
while (p) {
pidd = p->pid;
code = waitpid(pidd, &status, WNOHANG);
if (code == -1) { /* child terminated*/
p->status = TERMINATED;
} else if(WIFEXITED(status)){
p->status = TERMINATED;
}else if(WIFSTOPPED(status)){
p->status = SUSPENDED;
}
p = p->next;
}
}
解决方案
RETURN VALUE waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state, then 0 is returned. On error, -1 is returned.
您应该检查0
... 的返回值并修复其余检查。
code = waitpid(ppid, &status, WNOHANG | WUNTRACED | WCONTINUED);
if (code == -1) {
// Handle error somehow...
// This doesn't necessarily mean that the child was terminated!
// See manual page section "ERRORS".
if (errno == ECHILD) {
// Child was already terminated by something else.
p->status = TERMINATED;
} else {
perror("waitpid failed");
}
} else if (code == 0) {
// Child still in previous state.
// Do nothing.
} else if (WIFEXITED(status)) {
// Child exited.
p->status = TERMINATED;
} else if (WIFSIGNALED(status)) {
// Child killed by a signal.
p->status = TERMINATED;
} else if (WIFSTOPPED(status)) {
// Child stopped.
p->status = SUSPENDED;
} else if (WIFCONTINUED(status)) {
// This branch seems unnecessary, you should already know this
// since you are the one that should kill(pid, SIGCONT) to make the
// children continue.
p->status = RUNNING;
} else {
// This should never happen!
abort();
}
另外,请注意:
- 我在标志中添加
WUNTRACED
和:除非您使用标志跟踪孩子,否则不会发生,除非使用标志否则不会发生。WCONTINUED
WIFSTOPPED()
ptrace()
WUNTRACED
WIFCONTINUED()
WCONTINUED
code
andppid
变量应该是,而pid_t
不是int
(该ppid
变量似乎也不需要)。
在任何情况下,请考虑为SIGCHLD
那里添加信号处理程序并更新子状态。您的程序将为SIGCHLD
每个终止/停止/恢复的孩子收到一个。它更简单也更快(不需要连续调用waitpid()
每个子进程)。
推荐阅读
- c# - 使用 dotnet core 2.2 读取 wkt、kml 和 shapefile
- terraform - Terraform“用于应用服务的名称“xxx”需要全局唯一且不可用”
- c# - 我的随机化脚本的 Unity 2D 问题
- matlab - 创建与日期对应的字符串
- apache-spark - 如何计算满足最后一个条件的天数?
- css - Bootstrap 4 - 谷歌地图不显示
- javascript - 从选择中使用 Ajax 更新表
- python - 除了大写之外,还有其他函数可以帮助将字符串的所有字符变为大写吗?
- css - 由 GitHub Pages 托管时看不到背景图片
- php - 这是使用 php 7 断言的类不变性的有效示例吗?