A-A+

php 中的信号处理操作实例详解

2022年02月18日 我爱编程 暂无评论

本文实例讲述了php 中的信号处理操作,分享给大家供大家参考,具体如下:

首先我们需要了解几个函数

pcntl_signal   安装信号处理器,也就是当指定信号发生时,调用函数。

pcntl_alarm   指定秒数后向进程发送SIGALRM信号。

posix_getpid 返回当前进程id

posix_kill       给指定进程发送信号

一些常用的信号说明

SIGHUP

本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时,

通知同一session内的各个作业, 这时它们与控制终端不再关联。

SIGINT

程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出。

SIGQUIT

和SIGINT类似,但由QUIT字符(通常是Ctrl-/)来控制;进程在因收到SIGQUIT退出时会产生core文件,

在这个意义上类似于一个程序错误信号。

SIGKILL

用来立即结束程序的运行。本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。

SIGTERM

程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,

shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。

SIGUSR1

留给用户使用

SIGUSR2

留给用户使用

SIGALRM

时钟定时信号, 计算的是实际的时间或时钟时间。alarm函数使用该信号。

SIGCHLD

子进程结束时, 父进程会收到这个信号。

例1:

  1. <?php
  2. declare(ticks = 1);
  3. //信号处理函数
  4. function sig_func() {
  5.   echo "child exit \r\n";
  6. }
  7. //设置信号处理器
  8. pcntl_signal(SIGCHLD, 'sig_func');
  9. $pid = pcntl_fork();
  10. if($pid == -1) {
  11.   die('fork error');
  12. else if ($pid) {
  13.   pcntl_wait($status);
  14. else {
  15.   echo "child... \r\n";
  16.   exit;
  17. }

当子进程退出时,会向父进程发送SIGCHLD信号,我们通过设置信号处理器,成功的处理信号。

例2:

  1. <?php
  2. declare(ticks = 1);
  3. //信号处理函数
  4. function sig_func($signo) {
  5.   switch($signo) {
  6.     case SIGCHLD: {
  7.       echo "child SIGCHLD \r\n";
  8.       break;
  9.     }
  10.     case SIGTERM: {
  11.       echo "child SIGTERM \r\n";
  12.       break;
  13.     }
  14.     default:
  15.       //处理所有其他信号
  16.       break;
  17.   }
  18. }
  19. //设置信号处理器
  20. pcntl_signal(SIGCHLD, 'sig_func');
  21. //设置信号处理器
  22. pcntl_signal(SIGTERM, 'sig_func');
  23. $pid = pcntl_fork();
  24. if($pid == -1) {
  25.   die('fork error');
  26. else if ($pid) {
  27.   pcntl_wait($status);
  28. else {
  29.   sleep(3);
  30.   echo "child \r\n";
  31.   sleep(3);
  32.   posix_kill(getmypid(), SIGTERM);
  33.   exit;
  34. }

父进程等待子进程的退出,子进程等待3秒后输出child,再等待3秒后向自身发送结束程序信号。

例3:

  1. <?php
  2. declare(ticks = 1);
  3. //信号处理函数
  4. function sig_func($signo) {
  5.   switch($signo) {
  6.     case SIGCHLD: {
  7.       echo "child SIGCHLD \r\n";
  8.       break;
  9.     }
  10.     /*这里要把处理SIGTERM信号的代码注释掉
  11.     case SIGTERM: {
  12.       echo "child SIGTERM \r\n";
  13.       break;
  14.     }*/
  15.     default:
  16.       //处理所有其他信号
  17.       break;
  18.   }
  19. }
  20. //设置信号处理器
  21. pcntl_signal(SIGCHLD, 'sig_func');
  22. //设置信号处理器,也注释掉
  23. //不然当父进程发向子进程发送SIGTERM信号时,子进程不会退出,还会继续执行
  24. //我们的信号处理函数把SIGTERM给忽略了
  25. //pcntl_signal(SIGTERM, 'sig_func');
  26. $pid = pcntl_fork();
  27. if($pid == -1) {
  28.   die('fork error');
  29. else if ($pid) {
  30.   sleep(30);
  31.   posix_kill($pid, SIGTERM);
  32. else {
  33.   $cnt = 0;
  34.   for(;;) {
  35.     sleep(3);
  36.     echo $cnt'-';
  37.     ++$cnt;
  38.   }
  39.   exit;
  40. }

父进程在等待30秒后,向子进程发送SIGTERM结束程序信号。如果我们设置了SIGTERM信号的处理器,并且在自定义信号处理器中并没有杀死该进程,则该子进程会一直运行下去。

pcntl_signal()函数仅仅是注册信号和它的处理方法,真正接收到信号并调用其处理方法的是pcntl_signal_dispatch()函数。

例4:

  1. <?php
  2. //使用ticks需要PHP 4.3.0以上版本
  3. //declare(ticks = 1);
  4. function sig_func() {
  5.   echo "SIGALRM \r\n";
  6. }
  7. //设置信号处理器
  8. pcntl_signal(SIGALRM, 'sig_func');
  9. pcntl_alarm(3);

通过函数pcntl_alarm()3秒后给进程发送SIGALRM信号,但信号处理函数并未调用。

原因是我们注释了declare(ticks = 1);这段代码,而又没有调用pcntl_signal_dispatch()函数。

declare(ticks = 1);表示每执行一条低级指令,就检查一次信号,如果检测到注册的信号,就调用其信号处理器。但是这种处理方式效率很低,建议在代码循环中通过pcntl_signal_dispatch()来处理信号。

  1. <?php
  2. //使用ticks需要PHP 4.3.0以上版本
  3. //declare(ticks = 1);
  4. function sig_func() {
  5.   echo "SIGALRM \r\n";
  6. }
  7. //设置信号处理器
  8. pcntl_signal(SIGALRM, 'sig_func');
  9. pcntl_alarm(3);
  10. //因为3秒后pcntl_alarm函数才会给进程发送SIGALRM信号
  11. //所以我们通过sleep函数等待3秒后,调用pcntl_signal_dispatch()来处理信号
  12. sleep(3);
  13. pcntl_signal_dispatch();

pcntl_signal_dispatch()这个函数是PHP5.3以上才支持的,如果你的PHP版本大于5.3,建议使用这个方法调用信号处理器。

5.3以下的版本需要在注册信号之前加上:declare(ticks = 1);

给我留言

Copyright © 四季博客 保留所有权利.   Theme  Ality

用户登录