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;