Bitte beachten Sie die folgenden fork()
/SIGCHLD
Pseudocode.Vermeiden einer Gabel()/SIGCHLD Race Condition
// main program excerpt
for (;;) {
if (is_time_to_make_babies) {
pid = fork();
if (pid == -1) {
/* fail */
} else if (pid == 0) {
/* child stuff */
print "child started"
exit
} else {
/* parent stuff */
print "parent forked new child ", pid
children.add(pid);
}
}
}
// SIGCHLD handler
sigchld_handler(signo) {
while ((pid = wait(status, WNOHANG)) > 0) {
print "parent caught SIGCHLD from ", pid
children.remove(pid);
}
}
Im obigen Beispiel gibt es eine Race-Condition. Es ist möglich, dass "/* child stuff */
" beendet wird, bevor "/* parent stuff */
" gestartet wird, was dazu führen kann, dass die pid eines Kindes zur Liste der Kinder hinzugefügt wird, nachdem es beendet wurde, und niemals entfernt wird. Wenn es an der Zeit ist, dass die App geschlossen wird, warten die Eltern endlos darauf, dass das bereits fertiggestellte Kind fertig ist.
Eine Lösung, die ich mir vorstellen kann, ist, zwei Listen zu haben: started_children
und finished_children
. Ich würde started_children
an derselben Stelle hinzufügen, die ich zu children
jetzt hinzufüge. Aber im Signal-Handler, anstatt children
zu entfernen, würde ich zu finished_children
hinzufügen. Wenn die App geschlossen wird, kann das übergeordnete Element einfach warten, bis der Unterschied zwischen started_children
und finished_children
gleich Null ist.
Eine andere mögliche Lösung, die ich mir vorstellen kann, ist Shared-Memory, z. teilen Sie die Liste der Eltern der Eltern und lassen Sie die Kinder .add
und .remove
sich selbst? Aber ich weiß nicht viel darüber.
EDIT: Eine andere mögliche Lösung, die das erste, was war in den Sinn kam, ist einfach eine sleep(1)
zu Beginn der /* child stuff */
hinzufügen, aber das riecht mir komisch vor, weshalb ich es weggelassen. Ich bin mir auch nicht einmal sicher, ob es eine 100% ige Lösung ist.
Also, wie würdest du diese Rasse-Bedingung korrigieren? Und wenn es dafür ein bewährtes Muster gibt, lassen Sie es mich wissen!
Danke.
Ist es nur ich oder ist das Signal Handler nicht asynch-sicher? Wie könnte children.remove() möglicherweise implementiert werden, um nicht zu explodieren, wenn ein neues SIGCHLD es in der Mitte unterbricht? –