c-使用SIGCHLD处理僵尸



在我的程序中,我正在监听传入的SIGCHLD信号以避免僵尸。

代码:

void myhandler(int signo)
{   
printf("test");
int status;
pid_t pid;
while((pid = waitpid(-1, &status, WNOHANG)) > 0)
++count;
}
int main(int argc, char const *argv[])
{
struct sigaction sigchld_action;
memset(&sigchld_action,0,sizeof(sigchld_action));
sigchld_action.sa_handler = &myhandler;
sigaction(SIGCHLD,&sigchld_action,NULL);
if(fork() == 0){
exit(0);
}
if(fork()==0){
exit(0);
}
if(fork()==0){
exit(0);
}

while(wait(NULL) > 0)
++count;
return 0;
}

问题是,分叉子级的数量和printf("test"(的输出数量有时不匹配。分叉子级的数量大于数字printf("test"(。

这个代码段保证不会有僵尸吗?如果是这样,它如何实现这一点?它没有打印正确的"测试"编号。是waitpid((在这段时间内多次清除死去的孩子吗?

当这个信号处理程序调用时,会发生什么情况,同时另一个孩子可能会死亡。默认情况下,信号将被阻止。(当处理程序正在运行时,另一个孩子可能会死亡(。waitpid是否清除在信号处理程序运行时发送信号的进程?

此外,计数器也不相等。(静态volatile int(或者我尝试了原子整数。

发生了两件不同的事情:

  1. printf不是异步信号安全的,所以不应该从信号处理程序调用它。将其替换为write
  2. 在信号处理程序中,您只将count递增一次。如果你想知道有多少进程死亡,你需要在while循环中增加它

试试这个代码:

void handler(int signo)
{   
int status;
pid_t pid;
while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
write(1, "test", 4); /* technically this may result in a partial write and you should loop it, but in practice I think this'll be fine for this example */
++count;
}
}

使用该代码,您可能不会有僵尸,并且具有正确数量的tests和正确的count值。然而,还有一个竞争条件:如果在对waitpid的最后一次调用和信号处理程序结束之间,另一个子进程死亡,那么将不会接收到SIGCHLD,因此它将成为僵尸,直到它之后的那个进程也死亡。这种边缘情况的解决方案要复杂得多,并且取决于应用程序其余部分的结构。

最新更新