系统编程-信号

2020-12-16  本文已影响0人  aoshi

信号是事件发生时对进程的通知机制,有时又称为软件中断。一个进程可以向另一个进程发送信号,比如子进程结束时都会向父进程发送一个SIGCHLD(17号信号)来通知父进程,所以有时信号也被当作一种进程间通信的机制。

在linux系统下,通常我们使用 kill -9 XXPID来结束一个进程,其实这个命令的实质就是向某进程发送 SIGKILL(9号信号),对于在前台运行的程序我们通常用 Ctrl + c 快捷键来结束运行,该快捷键的实质是向当前进程发送 SIGINT (2号信号),而进程收到该信号的默认行为是结束运行。我们可以用命令 kill -l 来查看系统的信号列表:

image.png

其中1 ~ 31 号信号为标准信号或者传统信号,而大于31号信号为实时信号,这里我们主要介绍 标准信号。进程收到一个信号时,视信号的不同,有以下几种不同的行为:
1)忽略信号,进程就像没收到过信号一样,比如父进程收到子进程发送的 SIGCHLD 信号
2)结束进程, 比如进程收到 SIGINT (Ctrl + c) 信号
3)暂停运行
4)从之前的暂停状态恢复运行

PHP的pcntl扩展以及posix扩展为我们提供了若干操作信号的方法:

pcntl_signal_dispatch — 调用等待信号的处理器
pcntl_signal_get_handler — Get the current handler for specified signal
pcntl_signal — 安装一个信号处理器
pcntl_sigprocmask — 设置或检索阻塞信号
pcntl_sigtimedwait — 带超时机制的信号等待
pcntl_sigwaitinfo — 等待信号 
posix_kill — 向一个进程发送信号
pcntl_signal 方法可以让我们自定义进程对信号的处理动作,但是在linux系统中,SIGKILL(9号信号)和 SIGSTOP (19号信号)这两个信号是无法被我们自己捕获和处理的,SIGKILL总是会结束进程运行,SIGSTOP总是能暂停进程。
bool pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] )
 
signo
信号编号
 
handler
信号处理器可以是用户创建的函数或方法的名字,也可以是系统常量 SIG_IGN(译注:忽略信号处理程序)或SIG_DFL(默认信号处理程序)

在PHP中,有自己触发信号回调的机制

PCNTL现在使用了ticks作为信号处理的回调机制,ticks在速度上远远超过了之前的处理机制。 
这个变化与“用户ticks”遵循了相同的语义。您可以使用declare() 语句在程序中指定允许发生回调的位置。这使得我们对异步事件处理的开销最小化。
在编译PHP时 启用pcntl将始终承担这种开销,不论您的脚本中是否真正使用了pcntl。 PHP 4.3.0使用ticks作为信号处理回调机制,这比以前的机制快了很多。
这个变化与 "用户ticks" 遵循了相同的语义。您可以使用declare() 语句在程序中指定允许发生回调的位置。

demo

<?php
class pcntl{
    public function do_reap() {
        echo 'this is over with null' . PHP_EOL;
        exit('this is over');
    }

    /**
     * 测试捕获kill信号
     * */
    public function testKill() {

        //安装信号处理器 Ctrl + C
        //pcntl_signal(SIGINT, array(&$this,"cron_JIGUANG_push_ctrl_c"));
        //安装信号处理器 kill
        //pcntl_signal(15, array(&$this,"cron_JIGUANG_push_kill"));

        //安装信号处理器 Ctrl + C
        pcntl_signal(SIGINT, function(){
            echo "捕获到了 SIGINT 信号" . PHP_EOL;
        });                 //
        //安装信号处理器 kill
        pcntl_signal(15, array(&$this,"do_reap"));
        for($i = 0;$i<30;$i++) {
            echo $i . PHP_EOL;
            sleep(3);
            //调用等待信号的处理器   调用每个通过pcntl_signal() 安装的等待信号的处理器。
            pcntl_signal_dispatch();
        }
    }

    /**
     * 注册信号回调不存在方法时处理逻辑
     * */
    public function __call($name, $arguments) {
        $this->doKill($name);
    }


    /**
     * 添加信号处理程序
     * @param   string      $name       信号标识
     * */
    public function doKill($name) {
        //log
        CronKillLogModel::gi()->add(array('kill_signal'=>$name,'create_time'=>date('Y-m-d H:i:s')));
        exit('this is over');
    }
}
>

注意:

这个程序会再执行状态,当我们按下 Ctrl + c 时,就给程序发送了一个 SIGINT 信号,但由于我们自定义了信号处理,所以这时不会结束进程,而是执行信号接收回调函数。

上一篇下一篇

猜你喜欢

热点阅读