Gibt es eine UNIX-Variante, bei der ein untergeordneter Prozess mit seinem übergeordneten Prozess abstirbt?

41

Ich habe das Verhalten des Linux-Kernels schon seit einiger Zeit untersucht, und mir war immer klar, dass:

Wenn ein Prozess stirbt, werden alle seine Kinder an den initProzess (PID 1) zurückgegeben, bis sie schließlich sterben.

Kürzlich hat mir jedoch jemand mit viel mehr Erfahrung als ich mit dem Kernel gesagt, dass:

Wenn ein Prozess beendet wird, sterben auch alle seine untergeordneten Elemente (es sei denn, Sie verwenden, NOHUPin welchem ​​Fall sie zurückkehren init).

Auch wenn ich das nicht glaube, habe ich dennoch ein einfaches Programm geschrieben, um sicherzugehen. Ich weiß, dass ich mich sleepbei Tests nicht auf time ( ) verlassen sollte , da alles von der Prozessplanung abhängt, aber für diesen einfachen Fall denke ich, dass das ausreichend ist.

int main(void){
    printf("Father process spawned (%d).\n", getpid());
    sleep(5);

    if(fork() == 0){
        printf("Child process spawned (%d => %d).\n", getppid(), getpid());
        sleep(15);
        printf("Child process exiting (%d => %d).\n", getppid(), getpid());
        exit(0);
    }

    sleep(5);
    printf(stdout, "Father process exiting (%d).\n", getpid());
    return EXIT_SUCCESS;
}

Hier ist die Ausgabe des Programms mit dem zugehörigen psErgebnis bei jedem printfGespräch:

$ ./test &
Father process spawned (435).

$ ps -ef | grep test
myuser    435    392   tty1    ./test

Child process spawned (435 => 436).

$ ps -ef | grep test
myuser    435    392   tty1    ./test
myuser    436    435   tty1    ./test

Father process exiting (435).

$ ps -ef | grep test
myuser    436    1     tty1    ./test

Child process exiting (436).

Nun, wie Sie sehen können, verhält sich dies so, wie ich es erwartet hätte. Der Waisenprozess (436) wird an init(1) zurückgegeben, bis er stirbt.

Gibt es jedoch ein UNIX-basiertes System, auf dem dieses Verhalten nicht standardmäßig angewendet wird? Gibt es ein System, bei dem der Tod eines Prozesses sofort den Tod aller seiner Kinder auslöst?

John WH Smith
quelle

Antworten:

68

Wenn ein Prozess beendet wird, sterben auch alle seine untergeordneten Elemente (es sei denn, Sie verwenden NOHUP. In diesem Fall kehren sie zu init zurück).

Das ist falsch. Total falsch. Die Person, die das sagt, war entweder falsch oder hat eine bestimmte Situation mit dem allgemeinen Fall verwechselt.

Es gibt zwei Möglichkeiten, wie der Tod eines Prozesses indirekt den Tod seiner Kinder verursachen kann. Sie hängen damit zusammen, was passiert, wenn ein Terminal geschlossen wird. Wenn ein Terminal verschwindet (historisch , weil die serielle Leitung aufgrund eines Modems hangup geschnitten, heutzutage in der Regel , weil der Benutzer des Terminal - Emulator - Fenster geschlossen), ein SIGHUP - Signal gesendet wird, um den Steuerprozess in diesem Terminal läuft - in der Regel der erst Shell gestartet in diesem Terminal. Muscheln reagieren normalerweise darauf, indem sie beendet werden. Vor dem Beenden senden für die interaktive Verwendung bestimmte Shells HUP an jeden Job, den sie gestartet haben.

Das Starten eines Jobs von einer Shell aus nohupunterbricht diese zweite Quelle von HUP-Signalen, da der Job das Signal dann ignoriert und nicht angewiesen wird, zu sterben, wenn das Terminal verschwindet. Weitere Möglichkeiten, die Weitergabe von HUP-Signalen von der Shell an die Jobs zu disownunterbrechen, sind die Verwendung des integrierten Shell- Jobs (der Job wird aus der Jobliste der Shell entfernt) und das Double-Forking (die Shell startet ein untergeordnetes Objekt , das ein untergeordnetes Objekt startet) von selbst und geht sofort; die Muschel hat keine Kenntnis von ihrem Enkelkind).

Wiederum sterben die Jobs, die im Terminal gestartet wurden, nicht, weil ihr übergeordneter Prozess (die Shell) stirbt, sondern weil ihr übergeordneter Prozess entscheidet, sie zu töten, wenn ihm gesagt wird, dass er sie töten soll. Und die anfängliche Shell im Terminal stirbt nicht, weil ihr übergeordneter Prozess stirbt, sondern weil ihr Terminal verschwindet (was zufällig sein kann oder nicht, weil das Terminal von einem Terminalemulator bereitgestellt wird, der der übergeordnete Prozess der Shell ist).

Gilles 'SO - hör auf böse zu sein'
quelle
1
Es gibt einen dritten Weg, etwas mit Kontrollgruppen. Ich weiß nur, dass systemd es verwendet, um saubere Kills durchzusetzen.
o11c
5
@JanHudec Ich denke, du bist verwirrend nohupmit disown. disownist eine integrierte Shell, die einen laufenden Job aus der Jobtabelle entfernt (unter Verwendung eines Arguments wie %1), und der wichtigste nützliche Nebeneffekt ist, dass die Shell kein SIGHUP an den Unterprozess sendet. nohupist ein externes Dienstprogramm, das SIGHUP ignoriert (und nur wenige andere Aktionen ausführt) und dann den über die Befehlszeile übergebenen Befehl startet.
Gilles 'SO- hör auf böse zu sein'
@Gilles: Nein, das war ich nicht, aber wenn ich mir strace anschaue nohup, wird das Signal ignoriert, bevor es execder Befehl ist.
Jan Hudec
Vielen Dank für Ihre Antwort! Ich mochte besonders den kleinen historischen Hintergrund über Modem-Aufhängevorgänge. Ich begann mir Sorgen zu machen, dass ich den Kernel die ganze Zeit missverstanden hatte ...
John WH Smith
3
Es sollte auch beachtet werden, dass ein Programm beendet wird, wenn es SIGHUP empfängt, da der Standard-Signal-Handler für SIGHUP das Beenden ist. Jedes Programm kann jedoch einen eigenen SIGHUP-Handler implementieren, der dazu führen kann, dass es nicht beendet wird, wenn die übergeordnete Shell SIGHUP sendet.
Slebetman
12

Wenn ein Prozess beendet wird, sterben auch alle seine untergeordneten Elemente (es sei denn, Sie verwenden NOHUP. In diesem Fall kehren sie zu init zurück).

Dies ist korrekt, wenn der Prozess ein Sitzungsleiter ist. Wenn ein Sitzungsleiter stirbt, wird ein SIGHUP an alle Mitglieder dieser Sitzung gesendet. In der Praxis bedeutet das seine Kinder und ihre Nachkommen.

Ein Prozess macht sich selbst zum Sitzungsleiter, indem er aufruft setsid. Muscheln verwenden dies.

Dennis
quelle
Ich habe gerade einen Test durchgeführt, konnte das von Ihnen beschriebene Verhalten jedoch nicht reproduzieren. Ich habe einen Prozess erzeugt, ihm eine neue Sitzung gegeben ( fork, übergeordneten Prozess setsidbeenden) und ein anderes Kind in diese neue Sitzung eingegabelt. Als jedoch der übergeordnete Prozess (neuer Sitzungsleiter) starb, erhielt das Kind keine SEHENSWÜRDIGKEIT und wurde angefügt, initbis es schließlich beendet wurde.
John WH Smith
Von der setpgid(2)Manpage: Wenn eine Sitzung ein steuerndes Terminal hat und das CLOCAL-Flag für dieses Terminal nicht gesetzt ist und ein Terminal-Hangup auftritt, wird dem Sitzungsleiter ein SIGHUP gesendet. Wenn der Sitzungsleiter abreist, wird auch ein SIGHUP-Signal an jeden Prozess in der Vordergrundprozessgruppe des steuernden Terminals gesendet.
Ninjalj
1
@ninjalj Dann schätze ich, dass diese Antwort nur dann gültig ist, wenn der Sitzungsleiter auch der Steuerungsprozess eines Terminals ist. Ein Standard-Sitzungsleiter, unabhängig von einem Terminal, wird seine Kinder nicht töten. Ist es richtig?
John WH Smith
-1

Was über den Plakaten steht, ist, dass die Kinder nicht sterben, die Eltern sie töten (oder ihnen ein Signal senden, bei dem sie terminieren). Sie können also das haben, wonach Sie fragen, wenn Sie den Elternteil so programmieren, dass er (1) alle seine Kinder aufzeichnet und (2) ein Signal an alle seine Kinder sendet.

Dies ist, was die Shell tut, und es sollte sein, was Ihr übergeordneter Prozess tut. Möglicherweise muss das HUP-Signal im übergeordneten Element abgefangen werden, damit Sie noch genügend Kontrolle haben, um die Kinder zu töten.

Marco
quelle
Viele Ursachen können die Eltern sterben lassen. Es gibt keine Möglichkeit, das Überleben der Kinder zu verhindern, wenn die Eltern beispielsweise SIEGELT sind.
Emil Jeřábek unterstützt Monica
-1

Ich vermisse ein bisschen in den Antworten, die etwas mit sterbenden Eltern zu tun haben: Wenn ein Prozess auf eine Pipe schreibt, für die es keinen Lesevorgang mehr gibt, erhält er eine SIGPIPE. Die Standardaktion für SIGPIPE ist die Beendigung.

Dies kann tatsächlich zum Absterben von Prozessen führen. Tatsächlich ist dies die Standardmethode, mit der das Programm yesstirbt.

Wenn ich ausführe

(yes;echo $? >&2)|head -10

Auf meinem System lautet die Antwort

y
y
y
y
y
y
y
y
y
y
141

und 141 ist in der Tat 128 + SIGPIPE:

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers

von man 7 signal.

user86542
quelle
2
Aber der Prozess, der aus der Pipe liest, muss nicht unbedingt (oder sogar normalerweise) der übergeordnete Prozess sein. Das ist also wirklich ein ganz anderer Fall als in der Frage.
Barmar