PHP的pcntl扩展提供了信号处理的功能,利用它可以让PHP来接管信号的处理,在开发服务器端守护进程方面,信号处理至关重要。

函数原型

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

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

pcntl_signal的实现

  1.  
    <?php
  2.  
    //信号处理需要注册ticks才能生效,这里务必注意
  3.  
    //PHP5.4以上版本就不再依赖ticks了
  4.  
    declare(ticks = 1);
  5.  
    function sig_handler($signo){
  6.  
    switch ($signo) {
  7.  
    case SIGUSR1: echo "SIGUSR1\n"; break;
  8.  
    case SIGUSR2: echo "SIGUSR2\n"; break;
  9.  
    default: echo "unknow"; break;
  10.  
    }
  11.  
    }
  12.  
    //安装信号触发器器
  13.  
    pcntl_signal(SIGUSR1, "sig_handler");
  14.  
    pcntl_signal(SIGUSR2, "sig_handler");
  15.  
    //向当前进程发送SIGUSR1信号
  16.  
    posix_kill(posix_getpid(), SIGUSR1);
  17.  
    posix_kill(posix_getpid(), SIGUSR2);
  18.  
    ?>

执行此代码会在终端输出你想要的结果,其实官方的pcntl_signal性能极差,主要是PHP的函数无法直接注册到操作系统信号设置中,所以pcntl信号需要依赖tick机制来完成。 
pcntl_signal的实现原理是,触发信号后先将信号加入一个队列中。然后在PHP的ticks回调函数中不断检查是否有信号,如果有信号就执行PHP中指定的回调函数,如果没有则跳出函数。 
ticks=1表示每执行1行PHP代码就回调此函数。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。 
比较好的做法是去掉ticks,转而使用pcntl_signal_dispatch,在代码循环中自行处理信号。

pcntl_signal_dispatch的实现

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

实战:用信号来处理函数超时

    1.  
      <?php
    2.  
      function a(){
    3.  
      sleep(10);
    4.  
      echo "OK\n";
    5.  
      }
    6.  
      function b(){
    7.  
      echo "Stop\n";
    8.  
      }
    9.  
      function c(){
    10.  
      usleep(100000);
    11.  
      }
    12.  
      //信号处理代码
    13.  
      function sig(){
    14.  
      throw new Exception;
    15.  
      }
    16.  
      try{
    17.  
      pcntl_alarm(2); //设定超时后触发的信号
    18.  
      pcntl_signal(SIGALRM, "sig");
    19.  
      pcntl_signal_dispatch();
    20.  
      a();
    21.  
      pcntl_alarm(0);
    22.  
      }catch(Exception $e){
    23.  
      echo "timeout\n";
    24.  
      }
    25.  
      b();
    26.  
      a(); //等待十秒后完成
    27.  
      b();
posted on 2020-03-30 17:18  李留广  阅读(906)  评论(0编辑  收藏  举报