php信号处理

文章目录

  1. 1. pcntl
    1. 1.1. pcntl_signal
    2. 1.2. pcntl_alarm
    3. 1.3. pcntl_fork
    4. 1.4. pcntl_waitpid
    5. 1.5. pcntl_wexitstatus
    6. 1.6. SIGCHLD: 父进程不阻塞
    7. 1.7. pcntl_exec

pcntl

pcntl_signal

信号注册函数

pcntl_alarm

  • 指定秒数中断程序执行任务。
  • 每次执行只会有一个定时器生效,若之前计时器还没结束就定义新定时器,会替代之前定时器并返回之前定时器结束前秒数,若之前计时器已完成返回0
  • 参数设为0,会清空当前所有定时器,并不发起调用
  • 定时器会中断系统,即便是sleep执行中

<?php
declare(ticks = 1);

function signal_handler($signal) {
    print "Caught SIGALRM\n";
    echo pcntl_alarm(3).PHP_EOL;//再次调用
}

pcntl_signal(SIGALRM, "signal_handler", true);
echo pcntl_alarm(5).PHP_EOL;//只会调用一次

echo pcntl_alarm(3).PHP_EOL;//提示5,因为上一个计时器完成还剩5s

while(1) {
    //
}
?>

pcntl_fork

创建子进程

  • unix创建进程效率要比线程高,但需考虑进程数和内存等限制

<?php
$pid = pcntl_fork();

switch($pid) {
    case -1:
        print "Could not fork!\n";
        exit;
    case 0://子进程
        print "In child!\n";
        break;
    default://父进程,值代表子进程PID
        print "In parent!\n";
}
?>

pcntl_waitpid

等待或返回fork的子进程状态
挂起当前进程的执行直到参数pid指定的进程号的进程退出, 或接收到一个信号要求中断当前进程或调用一个信号处理函数。
如果pid指定的子进程在此函数调用时已经退出(俗称僵尸进程),此函数 将立刻返回。
pid可选值

  • 小于-1 等待任意进程组ID等于参数pid给定值的绝对值的进程。
  • -1 等待任意子进程;与pcntl_wait函数行为一致。
  • 0 等待任意与调用进程组ID相同的子进程。
  • 大于0 等待进程号等于参数pid值的子进程。

options

  • WNOHANG 如果没有子进程退出立刻返回。
  • WUNTRACED 子进程已经退出并且其状态未报告时返回。

其他方式去计算本函数的返回值

pcntl_wexitstatus

检查状态代码是否代表一个正常的退出。

  • 进程共享内容

<?php
for ($i = 1; $i <= 5; ++$i) {
    $pid = pcntl_fork();

    if (!$pid) {
        sleep(1);
        print "In child $i\n";
        exit($i);
    }
}
while (pcntl_waitpid(0, $status) != -1) {
    $status = pcntl_wexitstatus($status);
    echo "Child $status completed\n";
}
?>

SIGCHLD: 父进程不阻塞

SIGCHLD信号会在一个或多个子进程结束时向父进程通知
此时再加上pcntl_waitpid loop来让父进程及时回收全部结束的子进程


<?php
declare(ticks = 1);

pcntl_signal(SIGCHLD, "signal_handler");

function signal_handler($signal) {
    switch($signal) {
        case SIGCHLD:
            while (pcntl_waitpid(0, $status) != -1) {
                $status = pcntl_wexitstatus($status);
                echo "Child $status completed\n";
            }

            exit;
    }
}

for ($i = 1; $i <= 5; ++$i) {
    $pid = pcntl_fork();

    if (!$pid) {
        sleep(3);
        print "In child $i\n";
        exit($i);
    }
}

while(1) {
    //下面的代码会在父进程执行
    echo "parent processing here".PHP_EOL;
    sleep(1);
}
?>

pcntl_exec

调用程序执行,并取代自身


<?php
print "Before\n";
pcntl_exec("/usr/bin/uptime");
//下边不会输出
print "After\n"; 
?>
如有疑问,请文末留言交流或邮件:newbvirgil@gmail.com 本文链接 : https://newbmiao.github.io/2015/10/25/how-to-use-php-signal.html