Tenga en cuenta el siguiente fork()
/SIGCHLD
pseudocódigo.Evitar una condición de carrera de horquilla()/SIGCHLD
// 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);
}
}
En el ejemplo anterior, hay una condición de carrera. Es posible que "/* child stuff */
" finalice antes de que "/* parent stuff */
" comience, lo que puede dar como resultado que se agregue un pid de un niño a la lista de elementos secundarios después de salir y que nunca se elimine. Cuando llegue el momento de que la aplicación se cierre, el padre esperará sin parar para que el niño ya terminado termine.
Una solución que se me ocurre para contrarrestar esto es tener dos listas: started_children
y finished_children
. Agregaría a started_children
en el mismo lugar que estoy agregando al children
ahora. Pero en el controlador de señal, en lugar de eliminar de children
, me agregar a finished_children
. Cuando la aplicación se cierra, el padre simplemente puede esperar hasta que la diferencia entre started_children
y finished_children
sea cero.
Otra solución posible en la que puedo pensar es usar la memoria compartida, p. compartir la lista de hijos de los padres y dejar a los niños .add
y .remove
ellos mismos? Pero no sé mucho sobre esto.
EDITAR: Otra solución posible, que fue lo primero que me vino a la mente, es simplemente agregar un sleep(1)
al comienzo de /* child stuff */
pero me huele raro, por eso lo dejé fuera. Tampoco estoy seguro de que sea una solución al 100%.
Entonces, ¿cómo corregirías esta condición de carrera? Y si hay un patrón recomendado bien establecido para esto, ¡házmelo saber!
Gracias.
¿Es solo yo o el controlador de señales no es seguro? ¿Cómo podría children.remove() posiblemente implementarse para no explotar cuando un nuevo SIGCHLD lo interrumpe en el medio? –