Was ist der Unterschied zwischen verschiedenen $ SIG {CHLD} -Werten?

7

Was ist der Unterschied zwischen diesen Einstellungen?

%Vor%

Laut "Advanced Programming in der UNIX-Umgebung, 2. Auflage", Abbildung 10.1 ist der Standardwert von SIGCHLD "ignore".

Wenn "ignorieren" "SIG_IGN" bedeutet, dann wäre kein Kind jemals ein Zombie, und das ist nicht der Fall.

Von dort wird es nicht viel klarer:

  

Wenn der Prozess seine Disposition speziell auf SIG_IGN setzt, untergeordnete Elemente   des aufrufenden Prozesses wird keine Zombie-Prozesse generieren. Beachten Sie, dass   Dies unterscheidet sich von seiner Standardaktion (SIG_DFL), die aus Abbildung   10.1 ist zu ignorieren. Stattdessen wird bei Beendigung der Status dieser untergeordneten Prozesse angezeigt   wird verworfen.

Es fällt mir schwer zu wissen, wie sich die verschiedenen Werte (oder nicht definierter Nichtwert) auswirken. Bisher bestand die Lösung darin, sich durch diese Wahlmöglichkeiten zu drehen, bis ich das gewünschte Verhalten erreicht habe, und ich würde lieber genau verstehen, wie jeder Wert das Verhalten des Signals definiert.

Das Verhalten: Ein untergeordneter Prozess ruft "System" auf oder verwendet Backticks, die ein anderes Kind erzeugen, und das Signal würde normalerweise vom falschen (Eltern-) Handler erfasst werden. Das Setzen eines lokalen Handlers kann funktionieren, aber ich verstehe nicht, welcher Wert am besten geeignet ist, wenn ich möchte, dass das Signal vom Enkelkind nichts unternimmt.

Könnte jemand bitte mich erleuchten?

UPDATE: Basierend auf Ikegamis Feedback habe ich einige spezifische Tests durchgeführt. Das Verhalten ist zumindest teilweise plattformspezifisch.

Betrachten Sie das folgende Fragment:

%Vor%

Perl 5.8.6 unter Solaris 10 zeigt "SIGNAL CHLD" -Nachrichten für die PID des Aufrufs system () an. Alles tun, sogar so trivial wie

  

lokal $ SIG {CHLD};

im Kind unterdrückt diese Nachrichten.

Bei jedem anderen Geschmack, den ich versucht habe, sieht der Schnitter das Kind nie.

    
Trueblood 05.12.2011, 17:34
quelle

4 Antworten

9

Siehe %SIG .

$SIG{CHLD} = 'IGNORE'; bewirkt, dass Ihr Prozess SIGCHLD-Signale ignoriert.

$SIG{CHLD} = 'DEFAULT'; bewirkt, dass Ihr Prozess SIGCHLD-Signale behandelt, als hätten Sie nicht mit $SIG{CHLD} oder einem gleichwertigen Element verfahren. Laut Kill (1) ignoriert ein Prozess auf meinem System SIGCHLD standardmäßig

$SIG{CHLD} = ''; und $SIG{CHLD} = undef; sind keine gültigen Werte.

Wie beim Ernten werden Kinder eines Elternteils, dessen SIGCHLD-Handler explizit auf IGNORE gesetzt ist, automatisch vom System geerntet.

%Vor%     
ikegami 05.12.2011, 18:17
quelle
12

Es gibt zwei Möglichkeiten, die Erstellung von Zombie-Prozessen zu vermeiden:

  1. explizit festgelegt $SIG{CHLD}='IGNORE'
  2. Ernten Sie die toten Kinder explizit mit den Aufrufen wait oder waitpid (dies könnte innerhalb eines SIGCHLD-Handlers geschehen, muss aber nicht sein)

Das Setzen von $SIG{CHLD}='IGNORE' fängt das SIGCHLD auf Betriebssystemebene ab und bereinigt den Kindprozess, ohne dass Sie sogar Ihr Perl-Programm signalisieren.

Jede andere Einstellung, einschließlich 'DEFAULT' , undef , "" , sub {} , 'some_function_name_that_doesnt_even_exist' , bewirkt, dass das Signal an Perl geliefert wird und das Kind nicht automatisch geerntet wird.

Indem Sie den Prozess selbst mit wait und waitpid ernten, können Sie zusätzliche Informationen wie den Exit-Status des Kindprozesses und (mehr oder weniger) die Reihenfolge erhalten, in der die Kindprozesse abgeschlossen sind. Wenn $SIG{CHLD} auf 'IGNORE' festgelegt ist, geben wait und waitpid immer -1 zurück und legen nicht $? fest.

Der SIGCHLD , falls vorhanden, wird immer an den Prozess übergeben, der den Kindprozess hervorgebracht hat, also glaube ich nicht, dass Sie richtig sagen, dass ein SIGCHLD von einem Enkelprozess (aus einem system -Aufruf) stammt in einem Kindprozess) wird im Elternprozess gefangen. Vermutlich ist es so, dass Ihr untergeordneter Prozess den Signalhandler von seinem übergeordneten Prozess erbt.

system und Backticks erzeugen (bei den meisten Systemen) nach Abschluss einen SIGCHLD und setzen den $? -Wert mit dem Exit-Status des Befehls. Aber Perl wird diese Unterprozesse selbst ernten, und Sie werden nicht in der Lage sein, die Prozess-ID eines system - oder backticks-Aufrufs mit wait oder waitpid zu erfassen.

    
mob 05.12.2011 18:09
quelle
2

Es gibt zwei verschiedene Bedeutungen für "ignorieren", und sie treten an zwei verschiedenen Bewertungspunkten auf.

Die erste Verwendung betrifft, ob das Signal überhaupt geliefert wird. Wenn ein Kind Exits verarbeitet, wird es normalerweise vom Betriebssystem gehalten und ein CHLD-Signal wird an sein Elternteil gesendet. Wenn $ SIG {CHLD} auf 'IGNORE' gesetzt wird, wird dem System mitgeteilt, dass es kein Signal erzeugen soll und das Kind den Prozess nur beenden lassen soll. Der Elternteil hat keine Möglichkeit, Informationen über den Kindprozess zu erhalten, und es entstehen keine Zombies.

Aber wenn $ SIG {CHLD} etwas anderes als 'IGNORE' ist, bedeutet dies, das Signal an den Elternprozess zu liefern, an welchem ​​Punkt entweder ein benutzerdefinierter Signalhandler oder ein Standardsignalhandler vorhanden ist, und der Standardhandler wird dies tun variieren auf verschiedenen Systemen oder sogar Versionen des gleichen Betriebssystems. Die Manpage book und signal (7) spricht darüber, was standardmäßig passiert, wenn ein Signal an den übergeordneten Prozess übergeben wird (d. H. Der Handler ist nicht auf "IGNORE" eingestellt). So ist die zweite Verwendung von ignore verwandt mit der Aktion für ein geliefertes Signal . Zum Beispiel führt SIGINT dazu, dass Ihr Prozess beendet wird, und SIGSTOP wird Ihren Prozess "anhalten" lassen, obwohl benutzerdefinierte Signalhandler diese Standardaktionen ändern.

Beim SIGCHLD-Signal wird es standardmäßig "ignoriert", aber in dies bedeutet es nur, dass der (übergeordnete) Prozess normal weiterläuft, während der untergeordnete Prozess wartet (dh keine Beendigung oder Abbruch des Elternprozesses). Sie können später darauf warten (), um seine Informationen zu erhalten und einen Zombie zu vermeiden.

    
simpleuser 19.06.2015 01:54
quelle
1
  

$ SIG {CHLD} = 'IGNORE'

Dies wird an das Betriebssystem als SIG_IGN übergeben, was gemäß den Betriebssystemdokumenten dazu führt, dass die untergeordneten Prozesse mit Zombies enden (oder ihren Ausgangscode an den übergeordneten Code melden).

  

$ SIG {CHLD} = 'STANDARD'
  $ SIG {CHLD} = ''
  $ SIG {CHLD} = undef

Diese sind auf Betriebssystemebene gleich (sie rufen signal () mit SIG_DFL auf). Einige Perl-Pakete, insbesondere AnyEvent :: child, funktionieren jedoch nicht, wenn $ SIG {CHLD} auf 'DEFAULT' gesetzt ist.

    
Steven Schoch 04.04.2016 22:11
quelle