web-dev-qa-db-ja.com

なぜfork()を2回

Nagiosでは、_child_processes_fork_twice=<0/1>_を構成できます。

ドキュメント は言う

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

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

20
DerMike

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

21
sizzzzlerz

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

死んでいるのはプロセスですが、その親は他の作業でビジー状態だったため、子の終了ステータスを収集できませんでした。

場合によっては、子は非常に長い時間実行され、親はその時間を待つことができず、作業を続行します(親は死なないが、残りのタスクを続行するが、子供を気遣うこと)。

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


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

注意すべき重要なことは、孫が親プロセスが子供にしてほしいことをしているということです。

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

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


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


お役に立てれば!

63
nj-ath

documentation からも、

通常、Nagiosはホストとサービスのチェックを実行するときに2回fork()します。これは、(1)失敗してsegfaultするプラグインに対する高レベルの耐性を確保し、(2)OSが終了した孫プロセスのクリーンアップを処理するために行われます。

4
Alex Lockwood

nixプログラミングFAQ §1.6.2:

1.6.2それらの発生を防ぐにはどうすればよいですか?

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

別のアプローチはfork()twiceで、直接の子プロセスをすぐに終了させることです。これにより、孫プロセスが孤立するため、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()関数は機能しなくなります。それらのいずれかが呼び出された場合、それらはall子プロセスが終了するまで待機し、次に_errno == ECHILD_で失敗を返します。

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

4
user405725

このコードは、double forkメソッドを使用して、孫プロセスがゾンビプロセスのリスクなしに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プロセスによって回収されます。

0
Jain Anjan