php进程间通信的另外一个手段就是通过 信号 来在进程间传递信息。信号是一种系统调用。通常我们用的kill命令就是发送某个信号给某个进程的。具体有哪些信号可以在liunx/mac中运行kill -l
查看。
一些php信号的意思如下:
SIGHUP | 终止进程 终端线路挂断 |
SIGINT | 终止进程 中断进程 |
SIGQUIT | 建立CORE文件终止进程,并且生成core文件 |
SIGILL | 建立CORE文件 非法指令 |
SIGTRAP | 建立CORE文件 跟踪自陷 |
SIGBUS | 建立CORE文件 总线错误 |
SIGSEGV | 建立CORE文件 段非法错误 |
SIGFPE | 建立CORE文件 浮点异常 |
SIGIOT | 建立CORE文件 执行I/O自陷 |
SIGKILL | 终止进程 杀死进程 |
SIGPIPE | 终止进程 向一个没有读进程的管道写数据 |
SIGALARM | 终止进程 计时器到时 |
SIGTERM | 终止进程 软件终止信号 |
SIGSTOP | 停止进程 非终端来的停止信号 |
SIGTSTP | 停止进程 终端来的停止信号 |
SIGCONT | 忽略信号 继续执行一个停止的进程 |
SIGURG | 忽略信号 I/O紧急信号 |
SIGIO | 忽略信号 描述符上可以进行I/O |
SIGCHLD | 忽略信号 当子进程停止或退出时通知父进程 |
SIGTTOU | 停止进程 后台进程写终端 |
SIGTTIN | 停止进程 后台进程读终端 |
SIGXGPU | 终止进程 CPU时限超时 |
SIGXFSZ | 终止进程 文件长度过长 |
SIGWINCH | 忽略信号 窗口大小发生变化 |
SIGPROF | 终止进程 统计分布图用计时器到时 |
SIGUSR1 | 终止进程 用户定义信号1 |
SIGUSR2 | 终止进程 用户定义信号2 |
SIGVTALRM | 终止进程 虚拟计时器到时 |
下面来看一个例子。启动3个子进程,运行,父进程等待5秒钟,向子进程发送sigint信号。子进程捕获信号,调用信号处理函数处理。
<?php
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
// 定义一个信号处理函数
function sighandler($signo) {
if( $signo == SIGINT ){
$pid = getmypid();
exit("{$pid} progress,oh no ,I'm killed!\n");
}
}
//PHP < 5.3 使用
//配合pcntl_signal使用,表示每执行一条低级指令,就检查一次信号,如果检测到注册的信号,就调用其信号处理器。
//declare(ticks=1);
pcntl_signal( SIGINT, 'sighandler'); //注册信号处理函数
$childList = [];
for( $i = 0; $i < 3; $i++ ){
$pid = pcntl_fork();
if( $pid == 0 ){
while( true ){
//PHP >= 5.3
//调用已安装的信号处理器
//必须在循环里调用,为了检测是否有新的信号等待dispatching。
pcntl_signal_dispatch();
echo "i am child " . getmypid() . " and i am running ! \n";
$sec = rand(1,2);
sleep($sec);
}
}else if( $pid == -1 ){
exit("fork fail!" . PHP_EOL);
}else{
$childList[$pid] = 1;
}
}
sleep(5);
foreach( $childList as $key=>$vo ){
posix_kill( $key, SIGINT ); //触发SIGINIT信号
}
sleep(2);
echo "($parentPid)parent is end " . PHP_EOL;
pcntl_signal_dispatch ( void )
调用每个等待信号通过pcntl_signal() 安装的处理器。说明一下:pcntl_signal()函数仅仅是注册信号和它的处理方法,真正接收到信号并调用其处理方法的是pcntl_signal_dispatch()函数必须在循环里调用,为了检测是否有新的信号等待dispatching。
pcntl_signal_dispatch()这个函数是PHP5.3以上才支持的,如果你的PHP版本大于5.3,建议使用这个方法调用信号处理器。5.3以下的版本需要在注册信号之前加一句:declare(ticks = 1);表示每执行一条低级指令,就检查一次信号,如果检测到注册的信号,就调用其信号处理器。