# 8.5.4 阻塞和解除阻塞信号
Linux 提供阻塞信号的隐式和显式的机制:
- 隐式阻塞机制。 内核默认阻塞任何当前处理程序正在处理信号类型的待处理的信号。例如,图 8-31 中,假设程序捕获了信号 s,当前正在运行处理程序 S。如果发送给该进程另一个信号 s,那么直到处理程序 S 返回,s 会变成待处理而没有被接收。
- 显式阻塞机制。 应用程序可以使用
sigprocmask函数和它的辅助函数,明确地阻塞和解除阻塞选定的信号。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
返回: 如果成功则为 0,若出错则为 -1。
int sigismember(const sigset_t *set, int signum);
返回: 若 signum 是 set 的成员则为 1,如果不是则为 0,若出错则为 -1。
sigprocmask 函数改变当前阻塞的信号集合(8.5.1 节中描述的 blocked 位向量)。具体的行为依赖于 how 的值:
SIG_BLOCK:把set中的信号添加到 blocked 中(blocked = blocked | set)。SIG_UNBLOCK:从 blocked 中删除set中的信号(blocked = blocked & ~set)。SIG_SETMASK:blocked = set。
如果 oldset 非空,那么 blocked 位向量之前的值保存在 oldset 中。
使用下述函数对 set 信号集合进行操作:sigemptyset 初始化 set 为空集合。sigfillset 函数把每个信号都添加到 set 中。sigaddset 函数把 signum 添加到 set,sigdelset 从 set 中删除 signum,如果 signum 是 set 的成员,那么 sigismember 返回 1,否则返回 0。
例如,图 8-32 展示了如何用 sigprocmask 来临时阻塞接收 SIGINT 信号。
sigset_t mask, prev_mask;
Sigemptyset(&mask);
Sigaddset(&mask, SIGINT);
/* Block SIGINT and save previous blocked set */
Sigprocmask(SIG_BLOCK, &mask, &prev_mask);
...
/* Code region that will not be interrupted by SIGINT */
...
/* Restore previous blocked set, unblocking SIGINT */
Sigprocmask(SIG_SETMASK, &prev_mask, NULL);
图 8-32 临时阻塞接收一个信号