Warum zweimal fork() [duplicate]

Lesezeit: 6 Minuten

Benutzer-Avatar
DerMike

Nagios lässt mich konfigurieren child_processes_fork_twice=<0/1>.

Das Dokumentation sagt

Diese Option legt fest, ob Nagios untergeordnete Prozesse zweimal aufgabelt, wenn es Host- und Service-Prüfungen ausführt. Standardmäßig ist Nagios fork()s zweimal. Wenn jedoch die Option use_large_installation_tweaks aktiviert ist, wird sie nur einmal fork() verwenden.

Soweit ich weiss fork() erzeugt einen neuen untergeordneten Prozess. Warum sollte ich das zweimal machen wollen?

  • @larsmans Vielen Dank für diesen Link. Es war nicht auf meiner Liste, als ich die Frage zuerst recherchierte. Ich habe dort einfach viel gelernt und einige Upvotes abgegeben.

    – Der Mike

    7. Juni 2012 um 13:31 Uhr

Benutzer-Avatar
nj-ath

Also gut, also jetzt erst einmal: Was ist ein Zombie-Prozess?

Es ist ein Prozess, der tot ist, aber sein übergeordneter Prozess war mit anderen Arbeiten beschäftigt, daher konnte er den Exit-Status des untergeordneten Prozesses nicht erfassen.

In einigen Fällen läuft das Kind sehr lange, der Elternteil kann nicht so lange warten und wird mit seiner Arbeit fortfahren (beachten Sie, dass der Elternteil nicht stirbt, sondern seine verbleibenden Aufgaben fortsetzt, sich aber nicht um das Kind kümmert ).

Auf diese Weise entsteht ein Zombie-Prozess.

Kommen wir nun zur Sache. Wie hilft hier zweimal forking?

Es ist wichtig zu beachten, dass das Enkelkind die Arbeit erledigt, die der Elternprozess von seinem Kind erwartet.

Wenn nun zum ersten Mal ein Fork aufgerufen wird, gabelt das erste Kind einfach erneut und tritt aus. Auf diese Weise muss der Elternteil nicht lange warten, um den Exit-Status des Kinds zu sammeln (da die einzige Aufgabe des Kindes darin besteht, ein weiteres Kind zu erstellen und zu verlassen). Das erste Kind wird also kein Zombie.

Was das Enkelkind betrifft, so ist sein Elternteil bereits gestorben. Daher wird das Enkelkind von der adoptiert init Prozess, der immer den Exit-Status aller seiner untergeordneten Prozesse erfasst. Jetzt muss der Elternteil also nicht mehr lange warten, und es wird kein Zombie-Prozess erstellt.

Es gibt andere Möglichkeiten, einen Zombie-Prozess zu vermeiden; Dies ist nur eine gängige Technik.

Hoffe das hilft!

  • Ah. Beziehungen sind kompliziert. Und init ist eine gute alte Seele, um die Enkelkinder zu adoptieren.

    – CubicleSoft

    14. Mai 2016 um 14:27 Uhr

Unter Linux wird ein Daemon normalerweise durch zweimaliges Forken erstellt, wobei der Zwischenprozess nach dem Forken des Enkels beendet wird. Dies hat den Effekt, dass der Enkelprozess verwaist wird. Folglich liegt es in der Verantwortung des Betriebssystems, danach aufzuräumen, wenn es beendet wird. Der Grund sind sogenannte Zombie-Prozesse, die nach dem Verlassen weiterleben und Ressourcen verbrauchen, weil ihr Elternteil, der normalerweise für das Aufräumen zuständig wäre, ebenfalls gestorben ist.

  • Ich verstehe nicht, wie das besser ist, als nur einmal zu forken. Ich denke, der wahre Grund hat etwas mit Sitzungen und der Steuerung von Terminals zu tun, nicht mit dem Verwaisen, aber ich kann mich irren …

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. Juni 2012 um 15:09 Uhr

  • Der Hauptgrund ist, dass, wenn Sie Ihren Daemon in einer Anmeldesitzung starten, Double Fork dazu führen würde, dass der Daemon-Prozess init (PID 1) als übergeordnetes Element hat, und wenn Sie sich von der Sitzung abmelden, beendet SIGHUP den Prozess nicht. Es sollte nichts mit dem Zombie-Prozess zu tun haben, da die Hauptursache des Zombie-Prozesses normalerweise darin besteht, dass der übergeordnete Prozess nicht auf den beendeten untergeordneten Prozess “wait()” ist und das Betriebssystem den Rückgabewert des untergeordneten Prozesses wartend behält für seine Eltern zu bekommen. Also in Zombie Process, der Prozess ist bereits beendet, wird aber vom OS gehalten, also nicht wirklich tot, daher der Name Zombie.

    – Benutzer658991

    9. Juli 2019 um 17:21 Uhr

Auch von der Dokumentation,

Normalerweise wird Nagios zweimal fork() verwenden, wenn es Host- und Service-Prüfungen ausführt. Dies geschieht, um (1) ein hohes Maß an Widerstand gegen Plugins sicherzustellen, die schief gehen und einen Segfault verursachen, und (2) das Betriebssystem mit der Bereinigung des Enkelprozesses zu befassen, sobald es beendet wird.

FAQ zur Unix-Programmierung §1.6.2:

1.6.2 Wie kann ich verhindern, dass sie auftreten?

Sie müssen sicherstellen, dass Ihr übergeordneter Prozess aufruft wait() (oder
waitpid(), wait3()usw.) für jeden untergeordneten Prozess, der beendet wird; oder auf einigen Systemen können Sie das System anweisen, dass Sie an untergeordneten Ausgangszuständen nicht interessiert sind.

Ein anderer Ansatz ist fork() zweimal, und lassen Sie den unmittelbar untergeordneten Prozess sofort beenden. Dadurch wird der Enkelprozess verwaist, sodass der Init-Prozess für die Bereinigung verantwortlich ist. Code dafür finden Sie unter der Funktion fork2() im Beispielbereich.

Um untergeordnete Exit-Zustände zu ignorieren, müssen Sie Folgendes tun (überprüfen Sie die Manpages Ihres Systems, um zu sehen, ob dies funktioniert):

     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);

Wenn dies erfolgreich ist, dann die wait() Funktionen werden am Arbeiten gehindert; Wenn einer von ihnen gerufen wird, warten sie bis alle Untergeordnete Prozesse wurden beendet, geben dann einen Fehler mit zurück errno == ECHILD.

Die andere Technik besteht darin, das SIGCHLD-Signal abzufangen und den Signal-Handler aufrufen zu lassen waitpid() oder wait3(). Ein vollständiges Programm finden Sie im Beispielabschnitt.

Benutzer-Avatar
Jain Anjan

Dieser Code demonstriert die Verwendung von double fork Methode, um zu ermöglichen, dass der Enkelprozess von init übernommen wird, ohne das Risiko von Zombieprozessen.

#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);
    }
}

Die Eltern werden fork den neuen untergeordneten Prozess, und dann wait damit es fertig ist. Das Kind wird fork ein Enkelprozess, und dann exit(0).

In diesem Fall tut das Enkelkind nichts außer exit(0), kann aber dazu gebracht werden, alles zu tun, was der Daemon-Prozess tun soll. Das Enkelkind kann lange leben und wird von der zurückgefordert init Vorgang, wenn er abgeschlossen ist.

  • Eine Erklärung wäre nett.

    – Scott Solmer

    29. Mai 2014 um 16:43 Uhr


  • Op fragt eigentlich, warum das Programm so geschrieben ist, wie Sie es geschrieben haben

    – nj-ath

    18. September 2014 um 15:45 Uhr

  • @MichaelGaskill danke für die Bearbeitung. Ich werde meinen Kommentar entfernen.

    – Kiste Kiste Kiste Kiste

    24. Juni 2016 um 11:01 Uhr

  • Eine Erklärung wäre nett.

    – Scott Solmer

    29. Mai 2014 um 16:43 Uhr


  • Op fragt eigentlich, warum das Programm so geschrieben ist, wie Sie es geschrieben haben

    – nj-ath

    18. September 2014 um 15:45 Uhr

  • @MichaelGaskill danke für die Bearbeitung. Ich werde meinen Kommentar entfernen.

    – Kiste Kiste Kiste Kiste

    24. Juni 2016 um 11:01 Uhr

1345120cookie-checkWarum zweimal fork() [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy