Search code examples
phpparallel-processingpcntl

How do I use $status returned by pcntl_waitpid()?


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?


Solution

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