23

Nagiosで設定できますchild_processes_fork_twice=<0/1>

ドキュメントには

このオプションは、Nagiosがホストとサービスのチェックを実行するときに子プロセスを2回fork()するかどうかを決定します。デフォルトでは、Nagios fork()は2回です。ただし、use_large_installation_tweaksオプションが有効になっている場合は、fork()が1回だけ実行されます。

私の知る限りfork()、新しい子プロセスが生成されます。なぜ私はそれを2回やりたいのですか?

4

5 に答える 5

75

では、まず最初に、ゾンビプロセスとは何ですか?

これは死んだプロセスですが、その親は他の作業を行うのに忙しかったため、子の終了ステータスを収集できませんでした。

場合によっては、子供は非常に長い間走り、親はそれだけ長く待つことができず、仕事を続けます(親は死なないが、残りのタスクを続けるが、子供を気にしないことに注意してください)。

このようにして、ゾンビプロセスが作成されます。


それでは、ビジネスに取り掛かりましょう。ここで2回フォークすることはどのように役立ちますか?

注意すべき重要なことは、孫が親プロセスが子に実行させたい作業を実行することです。

これで、最初にフォークが呼び出されたときに、最初の子が再びフォークして終了します。このように、親は子の終了ステータスを収集するために長時間待つ必要はありません(子の唯一の仕事は別の子を作成して終了することであるため)。したがって、最初の子はゾンビにはなりません。

孫はすでに親が亡くなっています。したがって、孫はプロセスによって採用され、initプロセスは常にすべての子プロセスの終了ステータスを収集します。そのため、親はそれほど長く待つ必要がなくなり、ゾンビプロセスは作成されません。


ゾンビプロセスを回避する方法は他にもあります。これは一般的な手法です。


お役に立てれば!

于 2013-05-20T17:42:15.653 に答える
24

Linuxでは、デーモンは通常、孫をフォークした後に中間プロセスを終了して2回フォークすることによって作成されます。これには、孫プロセスを孤立させる効果があります。その結果、OSが終了した後、クリーンアップするのはOSの責任になります。その理由は、通常はクリーンアップを担当する親も死亡したため、終了後も存続し、リソースを消費するゾンビプロセスと呼ばれるものに関係しています。

于 2012-06-07T13:22:48.920 に答える
5

また、ドキュメントから、

通常、Nagiosはホストとサービスのチェックを実行するときに2回fork()します。これは、(1)プラグインが正常に機能せず、セグメンテーションフォールトが発生しないようにするため、および(2)OSが孫プロセスの終了後にクリーンアップするようにするために行われます。

于 2012-06-07T13:20:41.577 に答える
4

Unixプログラミングに関するよくある質問§1.6.2:

1.6.2どうすればそれらの発生を防ぐことができますか?

終了するすべての子プロセスに対して、親プロセスがwait()(または waitpid()、など)を呼び出すようにする必要があります。wait3()または、一部のシステムでは、子の終了状態に関心がないことをシステムに指示できます。

もう1つのアプローチは、fork() 2回実行し、直接の子プロセスをすぐに終了させることです。これにより、孫プロセスが孤立するため、initプロセスがクリーンアップを担当します。これを行うコードについてはfork2()、例のセクションの関数を参照してください。

子の終了状態を無視するには、次のことを行う必要があります(システムのマンページをチェックして、これが機能するかどうかを確認してください)。

     struct sigaction sa;
     sa.sa_handler = SIG_IGN;
 #ifdef SA_NOCLDWAIT
     sa.sa_flags = SA_NOCLDWAIT;
 #else
     sa.sa_flags = 0;
 #endif
     sigemptyset(&sa.sa_mask);
     sigaction(SIGCHLD, &sa, NULL);

これが成功すると、wait()関数は機能しなくなります。それらのいずれかが呼び出された場合、それらはすべての子プロセスが終了するまで待機し、その後、で失敗を返しerrno == ECHILDます。

もう1つの手法は、SIGCHLDシグナルをキャッチし、シグナルハンドラーにwaitpid()またはを呼び出すことwait3()です。完全なプログラムについては、例のセクションを参照してください。

于 2012-06-07T13:22:39.840 に答える
2

このコードは、doubleforkメソッドを使用して、ゾンビプロセスのリスクなしに、孫プロセスをinitに採用できるようにする方法を示しています。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>

int main()
{
    pid_t p1 = fork();

    if (p1 != 0)
    {
        printf("p1 process id is %d", getpid());
        wait();
        system("ps");
    }
    else
    {
        pid_t p2 = fork();
        int pid = getpid();

        if (p2 != 0) 
        {
            printf("p2 process id is %d", pid);
        }
        else
        {
            printf("p3 process id is %d", pid);
        }

        exit(0);
    }
}

親はfork新しい子プロセスを実行し、waitそれを終了します。子はfork孫プロセスになり、その後exit(0)

この場合、孫はを除いて何もしませんがexit(0)、デーモンプロセスに実行させたいことは何でも実行させることができます。孫は長生きする可能性があり、initプロセスが完了すると、プロセスによって回収されます。

于 2014-05-29T16:21:38.700 に答える