PHP CLI模式下PCNTL扩展实现多进程服务的例子

作者:袖梨 2022-06-24


PHP可通过PCNTL扩展实现进程控制,如进程创建,信号处理,进程中断判断等。但只能在CLI模式下操作。
PCNTL的信号机制是基于 ticks 机制实现的。因此在使用信号相关函数时需要在前面添加declare(ticks = n) 语法结构。
pcntl_alarm ( int $seconds )指定秒数后向进程发送一个 SIGALRM 信号
pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls ])给指定信号$signo设置回调函数
declare(ticks = 1);
 
function signal_handler($signal) {
    print "Caught SIGALRMn";
    pcntl_alarm(3);
}
 
pcntl_signal(SIGALRM, "signal_handler", true);
pcntl_alarm(3);
 
for(;;) {
}

pcntl_exec ( string $path [, array $args [, array $envs ]] )执行指定命令,执行完即结束,后面将不会执行
$dir = '/root/';
$cmd = 'ls';
$option = '-l';
$pathtobin = '/bin/ls';
 
$arg = array($cmd, $option, $dir);
pcntl_exec($pathtobin, $arg);
 
echo 'will not exec here';

pcntl_fork ( void )为当前进程fork子进程
此时,父进程执行过程中,得到的fork返回值为子进程号(>0),失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误;
父进程的阻塞同时会阻塞子进程。但是父进程的结束不影响子进程的运行;
子进程会从执行pcntl_fork()的那条语句开始执行(包括此函数),但是此时它返回的是零(代表这是一个子进程)。在子进程的代码块中最好有exit语句,即执行完子进程后立即就结束。
int pcntl_wait ( int &$status [, int $options = 0 ] ) 等待或返回fork的子进程状态
说明子进程调用结束后,并没有完全销毁,而是变成了僵尸进程,不占内存,仅存在进程列表。此时需要调用父进程调用wait来等待子进程结束。如果父进程在子进程前退出了,那么init进程将会对僵尸进程进行管理,它还是可以被清除的。第二个参数可设置阻塞方式:
1. WUNTRACED 阻塞方式调用的,函数返回值为子进程的pid,如果没有子进程返回值为-1;
2. WNOHANG 非阻塞方式调用,函数还可以在有子进程在运行但没有结束的子进程时返回0。
$pid  =  pcntl_fork ();
//父进程和子进程都会执行下面代码
if ( $pid  == -1 ) {
    //错误处理:创建子进程失败时返回-1.
    die( 'could not fork' );
} else if ( $pid ) {
    //父进程会得到子进程号,所以这里是父进程执行的逻辑
    pcntl_wait ($status, WUNTRACED);  //等待子进程中断,防止子进程成为僵尸进程。
    echo "ok".PHP_EOL;
} else if ($pid == 0){
    //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
    echo "子进程运行" . getmypid() .PHP_EOL;
    sleep(5);
    exit;
}
 
echo "父进程运行" . getmypid() .PHP_EOL;

相关文章

精彩推荐