pcntl_signal 信号处理函数

安装一个信号处理器。

说明:

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

函数 pcntl_signal 为 signo 指定的信号安装一个新的信号处理器。

参数:

  1. signo

    信号编号。

  2. handler

    信号处理器可以是用户创建的函数或方法的名字,也可以是系统常量 SIG_IGN(译注:忽略信号处理程序)或SIG_DFL(默认信号处理程序).

    注意:

    注意当你使用一个对象方法的时候,该对象的引用计数回增加使得它在你改变为其他处理或脚本结束之前是持久存在的。

  3. restart_syscalls

    指定当信号到达时系统调用重启是否可用。(译注:经查资料,此参数意为系统调用被信号打断时,系统调用是否从 开始处重新开始,但根据http://bugs.php.net/bug.php?id=52121,此参数存在bug无效。

成功时返回 true, 或者在失败时返回 false。

中断系统调用

当进程正在执行系统调用的时候,接收到中断信号,那么这个系统调用就会被中断,比如说进程正在写文件,无法恢复。

如果能恢复我们称为:可重入函数,否则就是非可重入函数。

若一个程序或副程序可以“在任意时刻被中断然后操作系统调度执行另一段代码,这段代码又使用了该副程序不会出错”,则称其为可重入(reentrant 或 re-entrant)的。即当该副程序正在运作时,执行线程可以再次进入并执行它,仍然可得到符合设计时所预期的结果。与多线程并发执行的线程安全不同,可重入强调对单一线程执行时重新进入同一个子程序仍然是安全的。

——可重入

一般在中断信号处理函数,不要写太多的业务逻辑。

我们经常把中断信号用于通知。

中断信号动作

每个信号都有相应的动作(信号处理程序):

  1. 用户自定义的中断信号处理程序
  2. SIG_DEF 系统默认动作(结果一般都会让进程终止或是停止,终止+core)
  3. 忽略 SIG_IGN ignore

进程启动的时候,信号的动作默认是系统行为,如果编写对应处理程序,会覆盖掉默认动作,有些信号不可以覆盖,例如 SIGKILL、SIGSTOP。

信号处理程序的继承

当父进程创建一个子进程的时候,子进程是继承父进程的中断信号处理程序的。


function sigHandler($signo)
{
    fprintf(STDOUT, "pid = %d,我接收到一个信号:%d \n", posix_getpid(), $signo);
}

pcntl_signal(SIGINT, 'sigHandler');
pcntl_signal(SIGUSR2,SIG_IGN); // 忽略信号

// SIGKILL、SIGSTOP 信号是无法捕捉的,编写的信号处理程序不会执行
// pcntl_signal(SIGKILL, 'sigHandler');
// pcntl_signal(SIGSTOP, 'sigHandler');

$pid = pcntl_fork();

while (1) {

    pcntl_signal_dispatch();

    fprintf(STDOUT, "pid = %d, main process doing something ... \n", posix_getpid());

    sleep(1);

}

pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072,我接收到一个信号:2 
pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072, main process doing something ... 
pid = 2073, main process doing something ... 
pid = 2072, main process doing something ... 
pid = 2073,我接收到一个信号:2 
pid = 2073, main process doing something ...

子进程也可以重设信号处理程序。


function sigHandler($signo)
{
    fprintf(STDOUT, "pid = %d,我接收到一个信号:%d \n", posix_getpid(), $signo);
}

pcntl_signal(SIGINT, 'sigHandler');

$pid = pcntl_fork();

if (0 === $pid) {
    pcntl_signal(SIGINT, function ($signo)
    {
        fprintf(STDOUT, "pid = %d,我是子进程,我重设了信号处理程序:%d \n", posix_getpid(), $signo);
    });
}

while (1) {

    pcntl_signal_dispatch();

    fprintf(STDOUT, "pid = %d, main process doing something ... \n", posix_getpid());

    sleep(1);

}

...
pid = 2088, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2088, main process doing something ... 
pid = 2088,我接收到一个信号:2 
pid = 2088, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2088, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2088, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2088, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2088, main process doing something ... 
pid = 2089, main process doing something ... 
pid = 2089,我是子进程,我重设了信号处理程序:2 
...