Signatur
Beschreibung
pcntl_waitpid() hält den aktuellen Prozess an, bis der durch $process_id angegebene Kind-Prozess beendet wird, oder gibt sofort zurück, falls der Kind-Prozess bereits beendet ist. Diese Funktion ist essenziell, um sogenannte Zombie-Prozesse zu vermeiden: Wenn ein Eltern-Prozess nicht auf seine Kinder wartet, bleiben deren Prozesseinträge im System erhalten, bis der Eltern-Prozess selbst endet.
Der Parameter $process_id steuert, auf welche Kinder gewartet wird: Ein Wert von -1 wartet auf beliebige Kinder (wie pcntl_wait()), ein positiver Wert wartet auf genau den Kind-Prozess mit dieser PID, 0 wartet auf ein Kind in derselben Prozessgruppe, und ein Wert kleiner als -1 wartet auf Kinder mit der Prozessgruppen-ID gleich dem Absolutwert.
Über den $flags-Parameter lässt sich das Verhalten anpassen: Mit WNOHANG kehrt die Funktion sofort zurück, wenn kein Kind beendet wurde (nicht-blockierendes Warten). WUNTRACED liefert auch Statusinformationen über gestoppte Kinder. Der zurückgegebene $status kann anschließend mit Funktionen wie pcntl_wexitstatus(), pcntl_wifexited() oder pcntl_wifsignaled() ausgewertet werden.
Die Funktion ist besonders in Daemon-Prozessen, Worker-Pools und parallelen Verarbeitungs-Szenarien nützlich, in denen mehrere Kind-Prozesse erzeugt und sauber überwacht werden müssen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $process_id Pflicht | int | PID des zu erwartenden Kind-Prozesses. -1 = beliebiger Kind-Prozess, 0 = Kinder in derselben Prozessgruppe, positiver Wert = exakte PID, negativer Wert < -1 = Kinder mit Prozessgruppen-ID gleich dem Absolutwert. |
|
| $status Pflicht | int | Wird per Referenz übergeben und enthält nach dem Aufruf den Statuscode des Kind-Prozesses. Kann mit pcntl_wifexited(), pcntl_wexitstatus(), pcntl_wifsignaled() usw. ausgewertet werden. |
|
| $flags | int | 0 | Steuerungsflags als Bitmask. WNOHANG: Sofortiger Rückgabe wenn kein Kind beendet wurde. WUNTRACED: Liefert auch Status von gestoppten Kindprozessen. |
| $resource_usage | array | [] | Wird per Referenz übergeben und enthält nach dem Aufruf Ressourcenverbrauch-Informationen des beendeten Kind-Prozesses (ab PHP 8.1 verfügbar). |
Rückgabewert
-1, oder 0 wenn WNOHANG gesetzt ist und kein Kind beendet wurde.Beispiele
Einfaches Warten auf einen Kind-Prozess
<?php
$pid = pcntl_fork();
if ($pid === -1) {
die('Fork fehlgeschlagen');
} elseif ($pid === 0) {
// Kind-Prozess
echo "Kind-Prozess läuft (PID: " . posix_getpid() . ")\n";
sleep(1);
exit(42); // Exit-Code 42
} else {
// Eltern-Prozess wartet auf das Kind
$childPid = pcntl_waitpid($pid, $status);
if (pcntl_wifexited($status)) {
$exitCode = pcntl_wexitstatus($status);
echo "Kind-Prozess (PID: $childPid) beendet mit Exit-Code: $exitCode\n";
}
}
Nicht-blockierendes Warten mit WNOHANG (Worker-Pool)
<?php
$workers = [];
// 3 Worker-Prozesse starten
for ($i = 0; $i < 3; $i++) {
$pid = pcntl_fork();
if ($pid === -1) {
die('Fork fehlgeschlagen');
} elseif ($pid === 0) {
// Kind-Prozess: Arbeit simulieren
sleep(rand(1, 3));
exit(0);
} else {
$workers[$pid] = true;
echo "Worker gestartet mit PID: $pid\n";
}
}
// Nicht-blockierend auf beendete Worker prüfen
while (!empty($workers)) {
foreach (array_keys($workers) as $workerPid) {
$result = pcntl_waitpid($workerPid, $status, WNOHANG);
if ($result > 0) {
echo "Worker $workerPid beendet.\n";
unset($workers[$workerPid]);
} elseif ($result === -1) {
echo "Fehler beim Warten auf Worker $workerPid\n";
unset($workers[$workerPid]);
}
}
usleep(100000); // 100ms warten vor nächster Prüfung
}
echo "Alle Worker beendet.\n";
// Wichtig · Fallstricke
Wichtig: pcntl_waitpid() steht nur auf Unix-ähnlichen Systemen (Linux, macOS) zur Verfügung und ist unter Windows nicht nutzbar. Die PHP-Erweiterung pcntl muss aktiviert sein.
Zombie-Prozesse: Wird diese Funktion (oder pcntl_wait()) nicht aufgerufen, bleiben beendete Kind-Prozesse als Zombie in der Prozesstabelle, bis der Eltern-Prozess endet. In langlebigen Daemon-Prozessen kann dies zur Erschöpfung der Prozessslots führen.
Signal-Handler: In Anwendungen mit Signal-Handling empfiehlt es sich, pcntl_waitpid() im SIGCHLD-Handler mit WNOHANG aufzurufen, um beendete Kinder asynchron aufzuräumen. Dabei sollte die Schleife so lange laufen, bis der Rückgabewert 0 oder -1 ist, um alle bereits beendeten Kinder zu erfassen.