如有转载,请注明出处:Windeal专栏
首先简述下几个概念的关系:
我们通过信号集建立信号屏蔽字,使得信号发生阻塞,被阻塞的信号即未决信号。
信号集:
信号集:其实就是一系列的信号。用sigset_t set表示。
数据类型:sigset_t 类似于整型(位数可能超过整型,因而不能用整型表示)。
我们一般在sigprocmask()等函数中使用信号集,用于创建一系列进程要阻塞的信号,告诉内核不允许这些信号发生。
几个关于信号集的函数:
#include <signal.h> int sigemptyset(sigset_t *set); //清空信号集 int sigfillset(sigset_t *set); //填满信号集 int sigaddset(sigset_t *set,int signo); //添加一个信号 int sigdelset(sigset_t *set,int signo); //删除信号集中的一个信号 All four return: 0 if OK,−1 on error int sigismember(const sigset_t *set,int signo); Returns: 1 if true, 0 if false,−1 on error
信号集函数的实现
《APUE》中假设系统只有31种信号,且整型是32bit的,也就是说我们整型的每一位可以代表一个信号(注意其它系统的实现方法可能不是这样的,这里只是做一个思路)
实现:
sigemptyset 和 sigfillset用宏实现
#define sigemptyset(ptr) (*(ptr) = 0) #define sigfillset(ptr) (*(ptr) = ˜(sigset_t)0, 0)
sigaddset、sigdelset和sigismember用函数实现:
#include <signal.h> #include <errno.h> /* *<signal.h> usually defines NSIG to include signal number 0. */ #define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG) int sigaddset(sigset_t *set, int signo) { if (SIGBAD(signo)) { errno = EINVAL; return(-1); } *set |= 1 << (signo - 1); /* turn bit on */ return(0); } int sigdelset(sigset_t *set, int signo) { if (SIGBAD(signo)) { errno = EINVAL; return(-1); } *set &= ˜(1 << (signo - 1)); /* turn bit off */ return(0); } int sigismember(const sigset_t *set, int signo) { if (SIGBAD(signo)) { errno = EINVAL; return(-1); } return((*set & (1 << (signo - 1))) != 0); }
信号屏蔽字与sigprocmask
信号屏蔽字用信号集来表示,该信号集中的信号在进程中被屏蔽,我们经常用sigprocmask函数实现:
#include <signal.h> int sigprocmask(int how,const sigset_t *restrict set,sigset_t *restrict oset); Returns: 0 if OK,−1 on error
参数:
oset:如果非空,表示当前信号屏蔽字,就是在执行这个函数之前的信号屏蔽字,
set:如果非空,表示接下来要进行修改的信号屏蔽字,how表示修改方式:set参数的角色根据how而定。
how:取值如下:
SIG_BLOCK: 期望的信号屏蔽字是set和原信号屏蔽字的并集
SIG_UNBLOCK:期望的信号屏蔽字是set和原来信号屏蔽字的补集的交集,也就是原来的信号屏蔽字解除掉属于set的部分
SIG_SETMASK:直接用set替换掉当前信号屏蔽字
未决信号与sigpending
信号阻塞而不能递送时,该信号对于调用进程来说是未决的,
我们用sigpending获取这些未决信号:
#include <signal.h> int sigpending(sigset_t *set); Returns: 0 if OK,−1 on error
set用于保存未决信号。
使用sigpending只能返回未决的信号有哪些,而无从得知某个未决信号发生了几次(不支持排队)。
附上一个《APUE》上跟许多信号功能相关的例子:
$./a.out ˆ generate signal once (before5seconds areup) SIGQUIT pending after return fromsleep caught SIGQUIT in signal handler SIGQUIT unblocked after return fromsigprocmask ˆQuit(coredump) generate signal again $./a.out ˆˆˆˆˆˆˆˆˆˆ generate signal 10 times (before5seconds areup) SIGQUIT pending caught SIGQUIT signal is generated only once SIGQUIT unblocked ˆQuit(coredump) generate signal again
sigsuspend()
用于解除信号屏蔽字的函数(原子操作)。
#include <signal.h> int sigsuspend(const sigset_t *sigmask); Returns:−1witherrnoset toEINTR
sigsuspend()
用于解除信号屏蔽字的函数(原子操作)。
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
Returns:−1witherrnoset toEINTR