GOOGLE ADS

Dienstag, 3. Mai 2022

Alle untergeordneten Prozesse ordnungsgemäß ernten und den Exit-Status erfassen

Ich möchte alle untergeordneten Prozesse abfangen, die von einem übergeordneten Prozess gegabelt wurden, und dann den Exit-Status des letzten untergeordneten Prozesses erfassen. Zu diesem Zweck habe ich sigsuspend() aufgerufen, um auf ein SIGCHLD-Signal zu warten. Wenn ich das SIGCHLD-Signal erhalte, ruft der Handler waitpid in einer Schleife auf, bis er anzeigt, dass keine Kinder mehr zu ernten sind. Der Exit-Status wird gesetzt, und der Main wird aus der Schleife ausbrechen und beendet.

Ich habe jedoch festgestellt, dass dies nicht korrekt ist, da nicht immer alle Kinder geerntet werden. Wie kann ich das beheben?

#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;
}


Lösung des Problems

Übertragen leicht modifizierter Kommentare in eine Antwort.

Die WNOHANGOption waitpid()bedeutet "sofort zurückkehren, wenn keine Kinder mehr übrig sind, ODER wenn Kinder übrig sind, aber noch laufen". Wenn Sie wirklich warten möchten, bis alle untergeordneten Elemente beendet sind, lassen Sie die WNOHANGOption entweder weg oder verwenden Sie stattdessen waitpid()einfach. wait()Beachten Sie, dass Aufgaben, die im Hintergrund gestartet wurden, möglicherweise für sehr lange Zeit nicht beendet werden, wenn überhaupt. Es hängt auch vom Kontext ab, ob „das letzte Kind, das stirbt" der richtige ist, um darüber zu berichten. Es ist möglich, sich Szenarien vorzustellen, in denen dies nicht angemessen ist.

Sie haben Recht, in diesem Fall meinte ich, dass "das letzte Kind, das stirbt", das letzte Kind ist, das gegabelt wurde. Kann ich dies beheben, indem ich eine einfache Bedingung hinzufüge, um zu prüfen, ob die zurückgegebene PID von Wait == die PID des letzten gegabelten Kindes ist?

Wenn Sie an dem letzten untergeordneten Element in der neuesten Pipeline interessiert sind (z. B. ls | grep … | sort … | wcund Sie auf warten möchten wc), dann kennen Sie die PID für wcund Sie können verwenden waitpid(wc_pid, &status, 0), um darauf zu warten, dass dieser Prozess ausdrücklich stirbt. Oder Sie können Ihre Schleife verwenden, um Körper zu sammeln, bis Sie entweder den Körper von finden wcoder „keine toten Prozesse mehr übrig" erhalten. An diesem Punkt können Sie sich entscheiden, speziell auf die PID zu warten wcoder (besser) use waitpid()without WNOHANG(oder use wait()) bis ein Prozess stirbt – und wieder können Sie entscheiden, ob dies der Fall war oder nicht, und wenn nicht, den Leichensammlungsprozess wcwiederholen WNOHANGSammle alle Zombies. Wiederholen Sie diesen Vorgang, bis Sie die Leiche von gefunden haben wc.

Außerdem haben Sie gesagt, dass Hintergrundaufgaben möglicherweise lange Zeit nicht beendet werden. Meinen Sie damit, dass waitpid(-1, &status, 0)alle Prozesse vollständig ausgesetzt werden, bis ein Kind bereit ist, geerntet zu werden?

waitpid(-1, &status, 0);lässt den Elternprozess unbegrenzt warten, bis ein Kindprozess stirbt, oder er kehrt zurück, weil es keine Kinder mehr gibt, auf die gewartet werden kann (was darauf hinweist, dass ein Haushaltsfehler aufgetreten ist; Kinder sollten nicht sterben, ohne dass die Eltern es wissen).

Beachten Sie, dass die Verwendung einer „Warten auf jedes Kind"-Schleife es vermeidet, Zombies in der Nähe zu lassen (Kinder, die gestorben sind, auf die jedoch nicht gewartet wurde). Dies ist im Allgemeinen eine gute Idee. Aber die Aufnahme, wenn das Kind, an dem Sie gerade interessiert sind, stirbt, stellt sicher, dass Ihre Hülle nicht herumhängt und wartet, wenn es nicht nötig war. Sie müssen also sowohl die PID als auch den Exit-Status der toten untergeordneten Prozesse erfassen.

Keine Kommentare:

Kommentar veröffentlichen

Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...