非常奇怪的错误,也许有人会看到我失踪的东西。
我有一个C ++程序,它会伪造一个bash shell,然后将命令传递给它。
这些命令会定期包含废话,bash进程会挂起。我使用semtimedwait检测到这一点,然后像这样运行一个小函数:
if (kill(*bash_pid, SIGKILL)) {
cerr << "Error sending SIGKILL to the bash process!" << endl;
exit(1);
} else {
// collect exit status
long counter = 0;
do {
pid = waitpid(*bash_pid, &status, WNOHANG);
if (pid == 0) { // status not available yet
sleep(1);
}
if(counter++ > 5){
cerr << "ERROR: Bash child process ignored SIGKILL >5 sec!" << endl;
}
} while (pid != *bash_pid && pid != -1);
if(pid == -1){
cerr << "Failed to clean up zombie bash process!" << endl;
exit(1);
}
// re-initialized bash process
*bash_pid = init_bash();
}
假设我正确理解了waitpid的工作原理,这应该首先将SIGKILL发送到shell,然后基本上坐在一个螺旋锁中,试图获得最终的进程。最终,它成功,然后使用init_bash()启动新的bash过程。
至少,那是应该发生的事情。相反,永远不会收集子进程的退出状态,并且它继续作为僵尸进程存在。尽管如此,父 退出循环并设法重启bash进程,并继续正常执行。最终生成了太多的僵尸,并且系统耗尽了pids。
此外:
思考?
答案 0 :(得分:1)
我读过的文章表明,僵尸进程的原因是子进程执行退出但父进程从不收集子进程。
本文提供several ways to kill a zombie process from the command line。一种技术是使用除SIGKILL之外的其他信号,例如SIGTERM。
不应使用此article has an answer which suggests SIGKILL。
其中一种技术是杀死父母,从而杀死其子进程,包括任何僵尸。作者指出,在重新启动操作系统之前,似乎只有子进程仍然是僵尸。
您没有提到用于将命令传递给子进程的机制。但是,一个选项可能是通过将子进程与其父进程断开来使子进程松散,类似于终端进程的子进程可以从终端进程断开的方式。这样孩子就会成为自己的过程,如果出现问题,可能会退出而不会变成僵尸。