信号屏蔽字是指一个进程中当前阻塞而不能够递送给该进程的信号集。
信号集则是一个能表示多个信号的集合的一种数据类型,为sigset_t。
与信号集设置相关的函数有如下几个:
#include <signal.h>
/*
* 下列四个函数成功返回0,出错返回-1
*/
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
/*
* 下面函数若真返回1,若假返回0,出错返回-1
*/
int sigismember(const sigset_t *set, int signo);
要注意的是,所有应用程序在使用信号集前,要对信号集调用sigemptyset或sigfillset一次。这是因为C编译器把未赋初值的外部和静态变量都初始化为0,而这是否与给定的信号集实现对应却并不清楚。
设置信号屏蔽字则要调用下面函数:
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
how取值有下列三个:
SIG_BLOCK :set中包含的是希望阻塞的附加信号
SIG_UNBLOCK:set中包含的是希望解除阻塞的信号
SIG_SETMASK:set中包含的是现有屏蔽字的代替值
若oset是非空指针,则返回进程的当前信号屏蔽字。
若set为空,则进程信号屏蔽字不变,how值无意义。
另外,注意一点,不可以阻塞SIGKILL和SIGSTOP信号。
要想处理关于信号屏蔽字的问题,还需要一个函数,就是sigpending,原型如下:
#include <signal.h>
int sigpending(sigset_t *set);
此函数通过set返回当前正在阻塞的信号的信号集。
下面通过一个实例理解一下这几个函数的用法:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void sig_quit(int);
static void err_quit(const char *str)
{
perror(str);
exit(-1);
}
int main(void)
{
sigset_t newmask, oldmask, pendmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR)
err_quit("can't catch SIGQUIT");
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_quit("SIG_BLOCK error");
sleep(5);
if (sigpending(&pendmask) < 0)
err_quit("sigpending error");
if (sigismember(&pendmask, SIGQUIT))
printf("\nSIGQUIT pending\n");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_quit("SIG_SETMASK error");
printf("SIGQUIT unblocked\n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT\n");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
err_quit("can't reset SIGQUIT");
}
在ubuntu12.04下运行结果如下
[unix]$ ./a.out
^\^\^\^\^\^\^\^\^\^\
SIGQUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\退出 (核心已转储)
上面十个信号只有一个输出是因为SIGQUIT是不可靠信号,系统没有对其进行排队。