I have a parent/worker arrangement going on. The parent keeps the worker PIDs in an array, constantly checking that they are still alive with the following loop:
// $workers is an array of PIDs
foreach ($workers as $workerID => $pid) {
// Check if this worker still exists as a process
pcntl_waitpid($pid, $status, WNOHANG|WUNTRACED);
// If the worker exited normally, stop tracking it
if (pcntl_wifexited($status)) {
$logger->info("Worker $workerID exited normally");
array_splice($workers, $workerID, 1);
}
// If it has a session ID, then it's still living
if (posix_getsid($pid))⋅
$living[] = $pid;
}
// $dead is the difference between workers we've started
// and those that are still running
$dead = array_diff($workers, $living);
The problem is that pcntl_waitpid()
is always setting $status
to 0, so the very first time this loop is run, the parent thinks that all of its children have exited normally, even though they are still running. Am I using pcntl_waitpid()
incorrectly, or expecting it to do something that it doesn't?
Simple, the child has not exited or stopped. You added the WNOHANG
flag, so it will always return immediately (It tells the function not to wait for an event). What you should do is check the return value of pcntl_waitpid
to see if anything of value was returned (assuming that you only want to run the contents of the loop if there's a status change):
foreach ($workers as $workerID => $pid) {
// Check if this worker still exists as a process
if (pcntl_waitpid($pid, $status, WNOHANG|WUNTRACED)) {
// If the worker exited normally, stop tracking it
if (pcntl_wifexited($status)) {
$logger->info("Worker $workerID exited normally");
array_splice($workers, $workerID, 1);
}
// If it has a session ID, then it's still living
if (posix_getsid($pid))⋅
$living[] = $pid;
}
}