【问题标题】:Avoiding the production of zombie processes in C++避免在 C++ 中产生僵尸进程
【发布时间】:2012-10-15 12:10:59
【问题描述】:

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

我有一个 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 进程,并继续正常执行。最终生成了太多的僵尸,系统用完了 pid。

另外:

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

想法?

【问题讨论】:

  • 一个有效的解决方法是调用 signal(SIGCHLD, SIG_IGN);在 main 的顶部,但这并不理想。我想直接收割子进程。

标签: c++ concurrency fork zombie-process


【解决方案1】:

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

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

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

其中一种技术是杀死父进程,从而也杀死它的子进程,包括任何僵尸进程。作者指出,在操作系统重新启动之前,似乎有一些子进程保持为僵尸。

您没有提到用于将命令传达给子进程的机制。然而,一种选择可能是通过断开子进程与其父进程的连接来放松子进程,类似于终端进程的子进程可以与终端会话断开连接的方式。这样子进程将成为自己的进程,如果出现问题,可以退出而不会成为僵尸。

【讨论】:

  • 嗨,理查德,感谢您的想法。澄清一下,子进程最初并没有死。我提供的代码首先终止进程,然后尝试使用 waitpid 收集其退出状态。不知何故,似乎有可能在不退出子进程的情况下收集退出状态。
  • @JohnDoucette,嗯。所以我想知道在发送信号之后和在 pid 上等待之前进行一百毫秒的睡眠的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
相关资源
最近更新 更多