避免在C ++中生成僵尸进程

时间:2012-10-15 12:10:59

标签: c++ concurrency fork zombie-process

非常奇怪的错误,也许有人会看到我失踪的东西。

我有一个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。

此外:

  • 在程序中的一个地方调用fork,在init_bash中。
  • 检查阻止init_bash被调用,除非在程序启动时和调用上面的函数之后。

思考?

1 个答案:

答案 0 :(得分:1)

我读过的文章表明,僵尸进程的原因是子进程执行退出但父进程从不收集子进程。

本文提供several ways to kill a zombie process from the command line。一种技术是使用除SIGKILL之外的其他信号,例如SIGTERM。

不应使用此article has an answer which suggests SIGKILL

其中一种技术是杀死父母,从而杀死其子进程,包括任何僵尸。作者指出,在重新启动操作系统之前,似乎只有子进程仍然是僵尸。

您没有提到用于将命令传递给子进程的机制。但是,一个选项可能是通过将子进程与其父进程断开来使子进程松散,类似于终端进程的子进程可以从终端进程断开的方式。这样孩子就会成为自己的过程,如果出现问题,可能会退出而不会变成僵尸。