在 PHP 中,子进程将成为僵尸进程,除非父进程使用pcntl_wait()或pcntl_waitpid()等待它返回。一旦所有进程结束或被处理,僵尸将被销毁。如果不处理孩子并且孩子跑得比父母长,看起来父母也会变成僵尸。
来自pcntl_fork页面的示例:
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
或者像这样使用信号处理来防止在主线程上等待:
$processes = array(); // List of running processes
$signal_queue = array(); // List of signals for main thread read
// register signal handler
pcntl_signal(SIGCHLD, 'childSignalHandler');
// fork. Can loop around this for lots of children too.
switch ($pid = pcntl_fork()) {
case -1: // FAILED
break;
case 0: // CHILD
break;
default: // PARENT
// ID the process. Auto Increment or whatever unique thing you want
$processes[$pid] = $someID;
if(isset($signal_queue[$pid])){
childSignalHandler(SIGCHLD, $pid, $signal_queue[$pid]);
unset($signal_queue[$pid]);
}
break;
}
function childSignalHandler($signo, $pid=null, $status=null){
global $processes, $signal_queue;
// If no pid is provided, Let's wait to figure out which child process ended
if(!$pid){
$pid = pcntl_waitpid(-1, $status, WNOHANG);
}
// Get all exited children
while($pid > 0){
if($pid && isset($processes[$pid])){
// I don't care about exit status right now.
// $exitCode = pcntl_wexitstatus($status);
// if($exitCode != 0){
// echo "$pid exited with status ".$exitCode."\n";
// }
// Process is finished, so remove it from the list.
unset($processes[$pid]);
}
else if($pid){
// Job finished before the parent process could record it as launched.
// Store it to handle when the parent process is ready
$signal_queue[$pid] = $status;
}
$pid = pcntl_waitpid(-1, $status, WNOHANG);
}
return true;
}