中断处理过程示意图

信号集

信号集是指信号的集合。

主程序可以选择阻塞某些信号,被阻塞的信号集称为阻塞信号集。

当进程阻塞了某个信号(通过 pcntl_sigpromask 来设置信号屏蔽字),如果在运行期间接收到了阻塞的信号时,这个信号的处理程序不会被执行,这个信号会放在被挂起的信号集里(信号未决集)。

sigpending

PHP 没有实现这个函数。

examine pending signals.

sigpending() returns the set of signals that are pending for delivery to the calling thread (i.e., the signals which have been raised while blocked).

The mask of pending signals is returned in set.

pcntl_sigpromask

pcntl_sigpromask 设置或检索阻塞信号,用来增加,删除或设置阻塞信号,具体行为 依赖于参数how。

pcntl_sigprocmask(int $how, array $set, array &$oldset = ?): bool

参数:

how:

设置 pcntl_sigprocmask()函数的行为。 可选值:

  • SIG_BLOCK: 把信号加入到当前阻塞信号中。
  • SIG_UNBLOCK: 从当前阻塞信号中移出信号。
  • SIG_SETMASK: 用给定的信号列表替换当前阻塞信号列表。

set:

信号列表。

oldset:

是一个输出参数,用来返回之前的阻塞信号列表数组。

返回值:

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

示例:

<?php

pcntl_signal(SIGINT, function($signo){

    fprintf(STDOUT, "pid=%d 接收到了信号:%d\n", getmypid(), $signo);
});

// 设置进程的信号屏蔽字|信号阻塞集
$sigset = [SIGINT, SIGUSR1];
pcntl_sigprocmask(SIG_BLOCK, $sigset);

$i = 10;
while ($i--){

    pcntl_signal_dispatch();
    fprintf(STDOUT, "pid=%d do something...\n", getmypid());

    sleep(1);

    if ($i == 5){

        fprintf(STDOUT, "时间到,准备解除阻塞...\n");
        //解除信号屏蔽
        //$oldset 会返回之前阻塞的信号集|信号屏蔽字
        pcntl_sigprocmask(SIG_UNBLOCK, [SIGINT,SIGUSR1], $oldset);

        print_r($oldset);

    }
}

$ php demo13.php 
pid=2673 do something...
^C^Cpid=2673 do something...
# 按 ctrl + c  信号被屏蔽阻塞
^C^C^C^C^Cpid=2673 do something...
^C^C^Cpid=2673 do something...
pid=2673 do something...
时间到,准备解除阻塞...
Array
(
    [0] => 2
    [1] => 10
)
pid=2673 接收到了信号:2
pid=2673 do something...
^Cpid=2673 接收到了信号:2
# 解除阻塞后,按 ctrl + c 接收到信号并处理
pid=2673 do something...
^Cpid=2673 接收到了信号:2
pid=2673 do something...
^Cpid=2673 接收到了信号:2
pid=2673 do something...
^Cpid=2673 接收到了信号:2
pid=2673 do something...