HOWTO · C
Verwendung der waitpid-Funktion in C
Dieser Artikel führt in die Verwendung der waitpid-Funktion in C ein
Auf dieser Seite
Verwenden Sie waitpid, wenn ein Elternprozess den Status eines bestimmten Kindprozesses oder eines beliebigen passenden Kindprozesses erfassen muss. Die Argumente bestimmen, welcher Kindprozess ausgewählt wird und welche Zustandsänderungen gemeldet werden. Den zurückgegebenen Status müssen Sie mit den Makros aus <sys/wait.h> auswerten; behandeln Sie ihn nicht direkt als Exit-Code.
Mit waitpid auf einen bestimmten Kindprozess warten
Ein Prozess kann mit fork einen Kindprozess erstellen. Dieser läuft ab der Stelle des Aufrufs weiter, während der Elternprozess die Prozess-ID des Kindes erhält. Der Elternprozess sollte ein beendetes Kind mit einem Aufruf aus der wait-Funktionsfamilie einsammeln. So wird dessen Beendigungsstatus verfügbar und der Prozess kann bereinigt werden.
Der Aufruf hat die Form waitpid(pid, &status, options). Eine positive pid wählt diesen Kindprozess aus. -1 wählt ein beliebiges Kind aus, dessen Zustand zu den Optionen passt; diese Auswahl verwendet auch wait. 0 wählt Kinder aus der Prozessgruppe des aufrufenden Prozesses aus. Ein Wert kleiner als -1 wählt Kinder aus der Prozessgruppe aus, deren ID dem Absolutwert von pid entspricht. waitpid eignet sich also, um ein Kind gezielt auszuwählen, ist aber nicht die einzige Schnittstelle der wait-Funktionsfamilie, mit der auf Kinder gewartet werden kann.
Das zweite Argument zeigt auf eine Ganzzahl, in der der Kernel einen codierten Status ablegt, wenn ein Kindzustand gemeldet wird. Übergeben Sie einen gültigen Zeiger, wenn Sie diesen Status benötigen. Das dritte Argument ist eine Bitmaske mit Optionen. Bei 0 wartet der Aufruf auf die Beendigung eines ausgewählten Kindes. Wenn keine passende Zustandsänderung vorliegt, blockiert er.
Festlegen, welche Ereignisse von Kindprozessen gemeldet werden
WNOHANG macht den Aufruf nicht blockierend: Wenn für kein ausgewähltes Kind eine meldbare Zustandsänderung vorliegt, gibt waitpid sofort 0 zurück. So kann der Elternprozess andere Aufgaben erledigen und später erneut prüfen. Ein positiver Rückgabewert ist die Prozess-ID des Kindes, dessen Status gespeichert wurde. WUNTRACED meldet zusätzlich ein angehaltenes Kind, dessen Anhalten noch nicht gemeldet wurde. WCONTINUED meldet ein Kind, das nach einer Unterbrechung weiterläuft. Diese Optionen legen fest, welche Zustandsänderungen einen Aufruf erfüllen können; ein einzelner Aufruf überwacht nicht alle zukünftigen Übergänge. Kombinieren Sie Flags mit dem bitweisen OR-Operator, zum Beispiel WUNTRACED | WCONTINUED.
Den von waitpid zurückgegebenen Status auswerten
Die Status-Ganzzahl ist codiert und muss mit den jeweils passenden Makros geprüft werden. WIFEXITED(status) erkennt eine normale Beendigung; anschließend liefert WEXITSTATUS(status) den Exit-Code. WIFSIGNALED(status) erkennt eine durch ein Signal verursachte Beendigung, und WTERMSIG(status) gibt dieses Signal an. Wenn angehaltene Kinder angefordert werden, erkennen WIFSTOPPED(status) und WSTOPSIG(status) den Stopp. Sofern verfügbar und angefordert, erkennt WIFCONTINUED(status) ein weiterlaufendes Kind. WCOREDUMP ist nur auf manchen Systemen verfügbar. Code, der dieses Makro verwendet, sollte seine Verfügbarkeit mit einer Präprozessordirektive prüfen. Diese Makros sind in <sys/wait.h> deklariert.
Rufen Sie WEXITSTATUS nur auf, wenn WIFEXITED wahr ist, und WTERMSIG nur, wenn WIFSIGNALED wahr ist. Die Ganzzahl ist nicht selbst der Exit-Code des Kindes. Mit den Makros müssen Sie sich nicht auf ein implementationsspezifisches Bitlayout verlassen.
Rückgabewerte und Fehler behandeln
Ein waitpid-Ergebnis größer als null gibt an, von welchem Kind der Status erfasst wurde. Das Ergebnis 0 bedeutet, dass kein passender Status vorliegt; dieser Wert tritt bei Verwendung von WNOHANG auf. -1 signalisiert einen Fehler. Prüfen Sie errno, um die Ursache zu ermitteln. ECHILD bedeutet beispielsweise, dass kein Kind zur Auswahl passt; EINTR bedeutet, dass ein abgefangenes Signal den Wartevorgang unterbrochen hat. Soll das Programm nach EINTR weiter warten, wiederholen Sie den Aufruf. Andernfalls behandeln Sie die Unterbrechung entsprechend der Signalrichtlinie der Anwendung. Ohne WNOHANG kann ein Aufruf außerdem unbegrenzt blockieren, wenn das ausgewählte Kind weiterläuft und keine angeforderte Zustandsänderung eintritt.
Ein vollständiges Beispiel mit einem Kindprozess ausführen
Dieses POSIX-Beispiel erstellt ein Kind, wartet gezielt auf dessen Beendigung, wiederholt den Aufruf bei einer Signalunterbrechung und gibt den ausgewerteten Exit-Status aus. Es verwendet fork und waitpid und benötigt weder ein separates Programm noch interaktive Eingaben. Der Code ist für eine POSIX-Umgebung mit C-Compiler vorgesehen und wird nicht als portables ISO-C-Beispiel dargestellt. Die bereitgestellten Ausführungsdaten dokumentieren einen erfolgreichen Lauf mit Exit-Code 0 und der unten gezeigten Ausgabe.
Führen Sie dieses Beispiel aus:
Der Code und die angezeigten Bezeichnungen oder Ausgaben in diesem Abschnitt bleiben auf Englisch.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
pid_t child = fork();
if (child == -1) {
perror("fork");
return EXIT_FAILURE;
}
if (child == 0) {
_exit(7);
}
int status;
pid_t result;
do {
result = waitpid(child, &status, 0);
} while (result == -1 && errno == EINTR);
if (result == -1) {
perror("waitpid");
return EXIT_FAILURE;
}
if (WIFEXITED(status)) {
printf("child exit status: %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("child terminated by signal: %d\n", WTERMSIG(status));
}
return EXIT_SUCCESS;
}
child exit status: 7