Récolter correctement tous les processus enfants et collecter le statut de sortie
Je souhaite capturer tous les processus enfants créés par un processus parent, puis collecter le statut de sortie du dernier enfant. À cette fin, j'ai appelé sigsuspend() pour attendre un signal SIGCHLD. Lorsque je reçois le signal SIGCHLD, le gestionnaire appellera waitpid dans une boucle jusqu'à ce qu'il indique qu'il ne reste plus d'enfants à récolter. L'état de sortie sera défini et le principal sortira de la boucle et se terminera.
Cependant, j'ai remarqué que ce n'est pas correct, car tous les enfants ne sont pas toujours moissonnés. Comment puis-je réparer cela?
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
volatile sig_atomic_t exit_stat;
// Signal Handler
void sigchld_handler(int sig) {
pid_t pid;
int status;
while(1) {
pid = waitpid(-1, &status, WNOHANG);
if(pid <= 0) {break;}
if(WIFEXITED(status)) {
printf("%s", "Exited correctly.");
}
else {
printf("%s", "Bad exit.");
}
}
exit_stat = status;
}
// Executing code.
int main() {
signal(SIGCHLD, sigchld_handler);
sigset_t mask_child;
sigset_t old_mask;
sigemptyset(&mask_child);
sigaddset(&mask_child, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask_child, &old_mask);
for(int i = 0; i < 5; i++) {
int child_pid = fork();
if(child_pid!= 0) {
//Perform execvp call.
char* argv[] = {"echo", "hi", NULL};
execvp(argv[0], argv);
}
}
while(!exit_stat) {
sigsuspend(&old_mask);
}
return 0;
}
Solution du problème
Transférer des commentaires légèrement modifiés dans une réponse.
L' WNOHANG
option à waitpid()
signifie "revenir immédiatement s'il n'y a plus d'enfants, OU s'il reste des enfants mais qu'ils courent toujours". Si vous voulez vraiment attendre que tous les enfants sortent, omettez l' WNOHANG
option waitpid()
ou utilisez simplement à la wait()
place. Notez que si des tâches ont été lancées en arrière-plan, elles peuvent ne pas se terminer pendant très longtemps, voire jamais. Cela dépend également du contexte si « le dernier enfant à mourir » est le bon sur lequel rapporter. Il est possible d'imaginer des scénarios où cela ne convient pas.
Vous avez raison, dans ce cas, je voulais dire que "le dernier enfant à mourir" est le dernier enfant qui a été bifurqué. Puis-je résoudre ce problème en ajoutant une condition simple pour vérifier si le pid renvoyé de wait == le pid du dernier enfant fourchu ?
Si vous êtes intéressé par le dernier enfant du pipeline le plus récent (par exemple ls | grep … | sort … | wc
, et que vous voulez attendre wc
), alors vous connaissez le PID de wc
, et vous pouvez utiliser waitpid(wc_pid, &status, 0)
pour attendre que ce processus meure spécifiquement. Ou vous pouvez utiliser votre boucle pour collecter des corps jusqu'à ce que vous trouviez le corps wc
ou que vous n'obteniez plus aucun processus mort. À ce stade, vous pouvez décider d'attendre spécifiquement le wc
PID, ou (mieux) utiliser waitpid()
sans WNOHANG
(ou utiliser wait()
) jusqu'à ce qu'un processus meure - et encore une fois, vous pouvez décider s'il l'était wc
ou non, et si ce n'est pas le cas, répétez le WNOHANG
processus de collecte de cadavres pour collecter tous les zombies. Répétez jusqu'à ce que vous trouviez le cadavre de wc
.
Et aussi, vous avez dit que les tâches en arrière-plan peuvent ne pas se terminer pendant longtemps. Par là, voulez-vous dire que waitpid(-1, &status, 0)
cela suspendra complètement tous les processus jusqu'à ce qu'un enfant soit prêt à être récolté ?
waitpid(-1, &status, 0);
fera attendre le processus parent indéfiniment jusqu'à ce qu'un processus enfant meure, ou il reviendra parce qu'il n'y a plus d'enfants à attendre (ce qui indique qu'il y a eu une erreur de gestion; les enfants ne doivent pas mourir sans que le parent le sache).
Notez que l'utilisation d'une boucle "attendre n'importe quel enfant" évite de laisser des zombies autour (des enfants qui sont morts mais qui n'ont pas été attendus). C'est généralement une bonne idée. Mais capturer quand l'enfant qui vous intéresse actuellement meurt garantit que votre coquille ne traîne pas en attente quand ce n'était pas nécessaire. Vous devez donc capturer à la fois le PID et l'état de sortie des processus enfants morts.
Commentaires
Enregistrer un commentaire