常用停止信号的区别

2020/08/05 操作系统

在 Workerman 源码中看到这么一段代码,用于终止进程。

<?php

if (static::$_gracefulStop) {
    $sig = \SIGTERM;
} else {
    $sig = \SIGINT;
}
foreach ($worker_pid_array as $worker_pid) {
    \posix_kill($worker_pid, $sig);
    if(!static::$_gracefulStop){
        Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, \SIGKILL), false);
    }
}

以上代码使用了三种信号用于停止进程,分别是SIGTERMSIGINTSIGKILL。第一次看到循环中的两个posix_kill时不禁一愣,为什么要调用两次呢?难道是为了确保成功终止?那为什么不调用三次、四次呢?

在分析之前,再看一段代码。

<?php

pcntl_async_signals(true);

pcntl_signal(SIGKILL, "sig_handler", false);

function sig_handler($signo) {
    switch ($signo) {
        case SIGKILL:
            echo "kill\n";
            break;
    }
}

while (true) {}

以上代码执行会报错Fatal error: Error installing signal handler for 9SIGKILL的值就是9,错误的意思是SIGKILL安装处理器出错,也就是说SIGKILL是不受用户控制的,无论进程在干什么,都必须要终止。因此,SIGKILL很靠谱,但是不优雅,毕竟是强制终止的。同时,也可以判断SIGTERMSIGINT都是可以受用户控制的,至于SIGTERMSIGINT的区别不大,SIGINT在命令行上可以通过Ctrl+C发出;SIGTERMkill命令的默认信号。

<?php
// demo.php

pcntl_async_signals(true);

pcntl_signal(SIGINT, "sig_handler", false);
pcntl_signal(SIGTERM, "sig_handler", false);

function sig_handler($signo) {
    switch ($signo) {
        case SIGINT:
            echo "interrupt\n";
            break;
        case SIGTERM:
            echo "terminate\n";
            break;
    }
}

while (true) {}

执行以上程序,可以玩下以下命令加深一下对信号的印象,^表示Ctrl键。

$ php demo.php &
$ ps ajx | grep demo.php | grep -v grep | awk '{print $2}' | xargs kill
terminate
$ jobs
[1]+  Running                 php demo.php &
$ fg 1
php demo.php
^Cinterrupt
^Cinterrupt
^Cinterrupt
^Z
[1]+  Stopped                 php demo.php
$ ps ajx
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
   16   192   192    16 pts/0      206 T        0   1:35 php demo.php
$ kill -s SIGCONT 192
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
   16   192   192    16 pts/0      207 R        0   1:37 php demo.php

除了以上三个信号,还有两个跟停止相关的信号SIGQUITSIGSTOPSIGQUITSIGINTSIGTERM类似,SIGQUIT可以在命令行上通过Ctrl+\发出。SIGSTOP只是暂停进程,并不会终止,在接收到SIGSTOP之后,SIGTERMSIGINTSIGQUIT都会无效,但是SIGKILL仍然可以终止进程。

SIGSTOP之后,通过SIGCONT信号让进程继续运行。SIGSTOPSIGCONT这对命令挺好用的,可以用于定时器之类的情景下,暂停任务时,通过SIGSTOP来实现,SIGCONT则用于恢复任务。

Search

    Table of Contents