一、信号的三种表示:
1)信号递达(Delivery):实际执行信号的处理动作
2)信号未决(Pending):信号从产生到递达之间的状态
3)进程可以选择阻塞(Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才 执行递达的动作。
注:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后 可选的⼀种处理动作。
二、信号在内存中的表示图
每个信号都有两个标志位,表示阻塞和未决,handler表示处理信号的动作(默认、忽略和自定义)。
三、信号集
sigset_t称为信号集,用来表示信号的有效或无效状态,用0、1表示
(1)阻塞信号集:该信号是否被阻塞 ,阻塞信号集也叫做当前进程的信号屏蔽字
(2)未决信号集:当前信号是否处于未决状态。
信号集操作函数:
int sigemptyset(sigset_t *set);
初始化set所指向的信号集,使其中所有信号的对应bit清零,表⽰该信号集不包含 任何有效信号。
int sigfillset(sigset_t *set);
初始化set所指向的信号集,使其中所有信号的对应bit置1,表⽰ 该信号集的有效信号包括系统⽀持的所有信号。
int sigaddset(sigset_t *set, int signo);
添加有效信号
int sigdelset(sigset_t *set, int signo);
删除有效信号
int sigismember(const sigset_t *set, int signo);
sigismember是⼀个布尔函数,⽤于判断⼀个信号集的有效信号中是否包含某种 信号,若包含则返回1,不包含则返回0,出错返回-1。
sigprocmask函数用来读取或更改进程的阻塞信号集
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
成功返回0,出错为-1
若oset非空,则读取当前进程的阻塞信号集
若set非空,则更改当前进程的阻塞信号集,how用来指示如何修改
若两者都非空,则将原来的信号屏蔽字备份到oset中,然后根据set、how修改
how指示当前的信号屏蔽字如何修改,下面对how作以解释,以mask为例
如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。
sigpending用来读取当前信号的未决信号集
int sigpending(sigset_t *set);
成功返回0,出错返回-1
四,代码实现
(1)实现信号的屏蔽
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void showpending(sigset_t *pending)
{
int i = 0;
for( ; i <= 31; i++)
{
if(sigismember(pending,i)) //判断是否包含某个信号
printf("1");
else
printf("0");
}
printf("\n");
}
int main()
{
sigset_t blockSet,oblockSet,pending;
sigemptyset(&blockSet); //清空信号集
sigemptyset(&oblockSet);
sigaddset(&blockSet,2); //添加2号信号Ctrl+c
sigprocmask(SIG_SETMASK, &blockSet, &oblockSet); //阻塞2号信号
while(1)
{
sigpending(&pending); //读取未决信号集
showpending(&pending); //显示未决信号集
sleep(1);
}
}
(2)实现信号的屏蔽与解除并递达(单次)
结果如下:
(3)信号的屏蔽与解除并递达(多次实现)
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void handler(int sig)
{
printf("get a sig:%d\n",sig);
}
void showpending(sigset_t *pending)
{
int i = 0;
for( ; i <= 31; i++)
{
if(sigismember(pending,i))
printf("1");
else
printf("0");
}
printf("\n");
}
int main()
{
sigset_t blockSet,oblockSet,pending;
sigemptyset(&blockSet);
sigemptyset(&oblockSet);
sigaddset(&blockSet,2);
while(1) //添加while循环,使信号可以被屏蔽多次
{
signal(2,handler);
sigprocmask(SIG_SETMASK,&blockSet,&oblockSet);
int count=1;
while(1)
{
sigpending(&pending);
showpending(&pending);
sleep(1);
if(count++==10)
{
printf("recover proc block set\n");
sigprocmask(SIG_SETMASK,&oblockSet,NULL);
break; //跳出循环
}
}
}
}
结果如下: