pcntl之pcntl_signal_dispatch

张锋 3年前 访问:977 评论:0 关注:0

函数原型

bool pcntl_signal(int $signo ,callback $handler [,bool $restart_syscalls=true])

第一个参数是信号ID
第二个参数是信号发生时回调的PHP函数。
第三个参数是是否restart,是否重新注册此信号。这个参数如果为false,那此信号只注册处理一次。

pcntl_signal的实现

<?php
//信号处理需要注册ticks才能生效
//PHP5.4以上版本就不再依赖ticks了 **
declare(ticks = 1);
function sig_handler($signo){
    switch ($signo) {
        case SIGUSR1: echo "SIGUSR1\n"; break;
        case SIGUSR2: echo "SIGUSR2\n"; break;
        default:      echo "unknow";    break;
    }
}
//安装信号触发器器
pcntl_signal(SIGUSR1, "sig_handler");
pcntl_signal(SIGUSR2, "sig_handler");
//向当前进程发送SIGUSR1信号
posix_kill(posix_getpid(), SIGUSR1);
posix_kill(posix_getpid(), SIGUSR2);
?>

执行此代码会在终端输出想要的结果,官方的pcntl_signal性能极差,主要是PHP的函数无法直接注册到操作系统信号设置中,所以pcntl信号需要依赖tick机制来完成。

pcntl_signal的实现原理是,触发信号后先将信号加入一个队列中。然后在PHP的ticks回调函数中不断检查是否有信号,如果有信号就执行PHP中指定的回调函数,如果没有则跳出函数。

ticks=1表示每执行1行PHP代码就回调此函数。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。

比较好的做法是去掉ticks,转而使用pcntl_signal_dispatch,在代码循环中自行处理信号。

pcntl_signal_dispatch的实现

<?php
// 定义一个处理器,接收到SIGINT信号后只输出一行信息
function signalHandler($signo) {
    switch ($signo) {
        case SIGUSR1: echo "SIGUSR1\n"; break;
        case SIGUSR2: echo "SIGUSR2\n"; break;
        default:      echo "unknow";    break;
    }
}
//安装信号触发器器
pcntl_signal(SIGINT, 'signalHandler');
while (true) {
    sleep(1);
    posix_kill(posix_getpid(), SIGUSR1);
    pcntl_signal_dispatch(); //接收到信号时,调用注册的signalHandler()
}

用信号来处理函数超时

<?php
function a(){
    sleep(10);
    echo "OK\n";
}
function b(){
    echo "Stop\n";
}
function c(){
    usleep(100000);
}
//信号处理代码
function sig(){
    throw new Exception;
}
try{
    pcntl_alarm(2); //设定超时后触发的信号
    pcntl_signal(SIGALRM, "sig");
    pcntl_signal_dispatch();
    a();
    pcntl_alarm(0);
}catch(Exception $e){
    echo "timeout\n";
}
b();
a(); //等待十秒后完成
b();
评论

还没有人评论 ~

❤❤❤❤❤❤
心情
此图名叫《暗淡蓝点》
1990年2月14日,由旅行者1号拍摄,
蓝色的点就是地球
或许你看不清,因为地球在宇宙中太小了。