Dan Bernstein erklärt auf seiner Webseite über den Self-Pipe-Trick einen Race-Condition mit select()
und signalisiert, bietet einen Workaround an und schließt daraus
Das Richtige wäre natürlich,
fork()
einen Dateideskriptor zurückzugeben, keine Prozess-ID.
Was meint er damit select()
? Geht es darum, untergeordneten Prozessen die Möglichkeit zu geben , ihre Statusänderungen zu verarbeiten, anstatt einen Signalhandler zu verwenden, um über diese Statusänderungen informiert zu werden?
signals
file-descriptors
fork
Lassi
quelle
quelle
signalfd
so etwas gab?wait()
, gab es Dinge, die Sie nicht tun konnten, also hat jemand SIGCHLD erfunden, aber es war ein schlechter Job. Nach meiner Erfahrung, und jetzt, wo sie existieren, Beregnung schön, nicht blockierendwait3()
,wait4()
und / oderwaitpid()
Anrufe an wichtigen Stellen (vielleicht Ihre Hauptereignisschleife) ist eine weit überlegene Alternative.Antworten:
Das Problem ist dort in deiner Quelle beschrieben,
select()
sollte durch Signale wie unterbrochen werdenSIGCHLD
, aber in manchen Fällen klappt es nicht so gut. Die Problemumgehung besteht also darin, ein Signal in eine Pipe zu schreiben, die dann von überwacht wirdselect()
. Das Ansehen von Dateideskriptoren ist das Richtigeselect()
, damit das Problem umgangen wird.Die Problemumgehung verwandelt das Signalereignis im Wesentlichen in ein Dateideskriptorereignis. Wenn Sie
fork()
nur ein fd zurückgeben, ist die Problemumgehung nicht erforderlich, da dieses fd dann vermutlich direkt mit verwendet werden könnteselect()
.Also ja, Ihre Beschreibung im letzten Absatz scheint mir richtig zu sein.
Ein weiterer Grund dafür, dass ein fd (oder eine andere Art von Kernel-Handle) besser ist als eine einfache Prozess-ID-Nummer, besteht darin, dass PIDs nach dem Abbruch des Prozesses wiederverwendet werden können. Dies kann in einigen Fällen ein Problem sein, wenn Signale an Prozesse gesendet werden. Es ist möglicherweise nicht sicher, ob der Prozess der Prozess ist, von dem Sie glauben, dass er es ist, und nicht ein anderer, der dieselbe PID wiederverwendet. (Obwohl ich denke, dass dies kein Problem sein sollte, wenn Signale an einen untergeordneten Prozess gesendet werden, da der übergeordnete Prozess auf dem untergeordneten Prozess ausgeführt werden muss,
wait()
damit seine PID freigegeben wird.)quelle
wait()
.clone
, das die tatsächliche Systemaufruf ist , dass Gabel Invokes auf LInux. Das Flag, um dies zu aktivieren, heißtCLONE_PIDFD
- siehe zum Beispiel lwn.net/Articles/784831 .Es ist nur eine Überlegung im Sinne von "Es wäre großartig, wenn Unix anders gestaltet wäre als es ist".
Das Problem mit PIDs ist, dass sie in einem globalen Namespace leben, in dem sie für einen anderen Prozess wiederverwendet werden können. Es wäre schön, wenn
fork()
im übergeordneten Element eine Art Handle zurückgegeben würde, das garantiert immer auf den untergeordneten Prozess verweist könnte über Vererbung oder Unix-Sockets /SCM_RIGHTS
[1] an andere Prozesse übergeben werden .Siehe auch die Diskussion hier für einen kürzlichen Versuch, dies unter Linux zu "beheben", einschließlich des Hinzufügens eines Flags, durch
clone()
das ein pid-fd anstelle einer PID zurückgegeben wird.Aber selbst dann würde das die Notwendigkeit dieses Self-Pipe-Hacks [2] oder besserer Schnittstellen nicht beseitigen, da die Signale, die einen übergeordneten Prozess über den Zustand eines Kindes benachrichtigen, nicht die einzigen sind, die Sie in der Hauptschleife behandeln möchten des Programms. Leider sind Dinge wie
epoll(7) + signalfd(2)
Linux oderkqueue(2)
BSD nicht Standard - die einzige Standardschnittstelle (die auf älteren Systemen nicht unterstützt wird) ist die viel schlechterepselect(2)
.[1] Es
waitpid()
könnte wahrscheinlich auf neueren Systemen durch Verwendung von erreicht werden, dass verhindert wird, dass die PID bis zur Rückkehr des Systemaufrufs und der Verwendung des Rückgabewerts erneut durchlaufen wirdwaitid(.., WNOWAIT)
.[2] Ich würde DJ Bernstein nicht darauf hinweisen, dass er es erfunden hat (sorry für die Entschuldigung ;-)).
quelle
Bernstein gibt nicht viel Kontext für diese "Richtige" Bemerkung, aber ich werde eine Vermutung wagen: Wenn fork (2) eine PID zurückgibt, ist dies inkonsistent mit open (2), creat (2) usw., die Dateideskriptoren zurückgeben. Der Rest des Unix-Systems hätte die Prozessmanipulation mit einem Dateideskriptor durchführen können, der einen Prozess anstelle einer PID darstellt. Es gibt einen Systemaufruf signalfd (2) , der eine etwas bessere Interaktion zwischen Signalen und Dateideskriptoren ermöglicht und zeigt, dass ein Dateideskriptor, der einen Prozess darstellt, funktionieren könnte.
quelle
pidfd_open
Linux, siehe zum Beispiel lwn.net/Articles/789023