2

非常に奇妙なバグです。おそらく誰かが私が見逃しているものを見るでしょう。

bash シェルからフォークしてコマンドを渡す C++ プログラムがあります。

定期的に、コマンドに意味のないものが含まれ、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 をシェルに送信し、次に本質的にスピンロックに座って、結果のプロセスを取得しようとします。最終的には成功し、新しい bash プロセスが init_bash() で開始されます。

少なくとも、そうあるべきです。代わりに、子プロセスの終了ステータスは収集されず、ゾンビ プロセスとして存在し続けます。それにもかかわらず、親ループを終了し、bash プロセスを再起動することに成功し、通常の実行を続行します。最終的に、生成されるゾンビが多すぎて、システムは pid を使い果たします。

さらに:

  • fork は、init_bash 内のプログラム内の 1 か所だけで呼び出されます。
  • チェックは、プログラムの開始時と上記の関数の呼び出し後に 1 回を除いて、init_bash が呼び出されるのを防ぎます。

考え?

4

1 に答える 1

1

私が読んだ記事によると、ゾンビプロセスの理由は、子プロセスが終了するが、親が子プロセスの終了を収集することはないということです。

この記事では、コマンドラインからゾンビプロセスを強制終了するいくつかの方法を紹介します。1つの手法は、SIGKILL以外の他のシグナル(たとえばSIGTERM)を使用することです。

この記事には、SIGKILLを使用すべきではないことを示唆する回答があります。

テクニックの1つは、親を殺し、それによってゾンビを含む子プロセスも殺すことです。著者は、OSが再起動されるまでゾンビとして残る子プロセスがあるように見えることを示しています。

コマンドを子プロセスに伝達するために使用されるメカニズムについては言及していません。ただし、1つのオプションは、ターミナルプロセスの子をターミナルセッションから切断するのと同じように、子プロセスを親から切断することによって子プロセスを緩めることです。そうすれば、子供は独自のプロセスになり、問題がある場合はゾンビになることなく終了する可能性があります。

于 2012-10-15T12:29:04.420 に答える