Veuillez prendre en compte les éléments suivants fork()
/SIGCHLD
pseudo-code.Éviter une fourche()/Conditions de course 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);
}
}
Dans l'exemple ci-dessus, il existe une condition de concurrence. Il est possible que "/* child stuff */
" se termine avant "/* parent stuff */
", ce qui peut entraîner l'ajout du PID d'un enfant à la liste des enfants après sa fermeture et ne jamais être supprimé. Lorsque le moment est venu de fermer l'application, le parent attendra indéfiniment que l'enfant déjà terminé finisse.
Une solution que je peux penser pour contrer cela est d'avoir deux listes: started_children
et finished_children
. Je voudrais ajouter à started_children
dans le même endroit que j'ajoute à children
maintenant. Mais dans le gestionnaire de signal, au lieu de supprimer de children
je ajouter à finished_children
. Lorsque l'application se ferme, le parent peut simplement attendre que la différence entre started_children
et finished_children
soit nulle.
Une autre solution possible que je peux penser est l'utilisation de la mémoire partagée, par ex. partager la liste des enfants du parent et laisser les enfants .add
et .remove
eux-mêmes? Mais je ne sais pas trop à ce sujet.
EDIT: Une autre solution possible, qui était la première chose qui me vient à l'esprit, est d'ajouter simplement un sleep(1)
au début de /* child stuff */
mais ça me fait drôle, c'est pourquoi je l'ai omis. Je ne suis même pas sûr que ce soit une solution à 100%.
Alors, comment corrigeriez-vous cette condition de course? Et s'il y a un modèle recommandé bien établi pour cela, s'il vous plaît faites le moi savoir!
Merci.
Est-ce que c'est juste moi ou ce gestionnaire de signal n'est-il pas sécurisé? Comment child.remove() pourrait-il être implémenté pour ne pas exploser quand un nouveau SIGCHLD l'interrompt au milieu? –