您的位置:首页 > 运维架构 > Linux

Linux日常——信号(2)之阻塞信号

2017-06-13 21:41 183 查看

阻塞信号

这里我们需要先了解几个基本概念

信号递达(Delivery) :实际执⾏行信号的处理动作

信号未决(Pending) :信号从产⽣生到递达之间的状态

阻塞:进程可以选择阻塞 (Block )某个信号。

被阻塞的信号产⽣生时将保持在未决状态,直到进程解除对此信号的阻塞, 才执⾏行递达的动作。

阻塞:在信号未决状态产生,此时没有对信号做出处理

忽略:在信号递达后进行,忽略也是对信号的一种处理方式(就是不做处理-_-)

每个进程的PCB块里都有3张表

block:位图,用于表示信号是否被阻塞(屏蔽)—————-阻塞

pending:位图,用于表示信号是否收到————————-未决

handler:函数指针数组,描述信号被如何处理(3种方式)——-递达

SIG_DFL:默认方式

SIG_ING:忽略方式



在上图的例⼦子中,

1. SIGHUP信号未阻塞也未产⽣生过,当它递达时执⾏行默认处理动作。

2. SIGINT信号产⽣生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在 没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

3. SIGQUIT信号未产⽣生过,⼀一旦产⽣生SIGQUIT信号将被阻塞,它的处理动作是⽤用户⾃自定义函数sighandler。

信号集sigset_t

这个类型可以表示每个信号的“有效”或“无效”状态,

在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞

( 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask))

在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。

产生:

Linux中规定::常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示 。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。

信号集操作函数

头文件:signal.c

int sigemptyset(sigset_t *set)

初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号

int sigfillset(sigset_t *set )

初始化set所指向的信号集,使其中所有信号的对应bit置位(全1),表示该信号集的有效信号包括系统⽀支持的所有信号

在使用sigset_t类型 的变量之前,一定要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态

int sigaddset(sigset_t *set ,int signo)

向信号集中添加某种有效信号

int sigdelset (sigset_t *
4000
set ,int signo)

向信号集中删除某种有效信号

以上四个函数都是成功返回0,出错返回-1

int sigismember(const sigset_t *set ,int signo )

布尔函数,用于判断一个信号集的有效信号中是否包含某种信号

包含则返回1,不包含则返回0, 出错返回-1

int sigprocmask(int how, const sigset_t *set, sigset_t *oset)

读取或更改进程的信号屏蔽字(阻塞信号集)

成功则为0,若出错则为-1

如果oset是⾮非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。

如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。

如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset⾥里,然后根据set和how参数更改信号屏蔽字。

简单来说:

oset可以用来记录修改前的block,方便执行完操作后恢复之前的block

set是修改后的新block表

how是要执行的操作(3种)

SIG_BLOCK:添加信号到当前的block,mask=mask | set

SIG_UNBLOCK:解除当前block中的信号,mask=mask & ~set

SIG_SRTMASK:设置当前block为set指向的值, mask=set

解释:

mask是当前block表。它在oset中做备份,而set是新的block表,set与mask做运算



以下是实现进程

在10秒内,block表屏蔽2号信号,此时间段内从键盘发送一个2号信号,pending表被设置,但信号却不会被递达,10秒结束后恢复到原来状态,信号被捕获(信号递达)

#include<stdio.h>
#include<signal.h>
void showpending(sigset_t *pending)
{
int i=1;
for(;i<=31;++i)
{
//判断i号信号是否存在于pending
if(sigismember(pending,i))
{
printf("1");

}
else{
printf("0");
}
}
printf("\n");

}
void handler(int sig)
{
printf("get a sig :%d\n",sig);
}
int main()
{
sigset_t blockset,oblockset,pending; //设置3张表,新的block表,旧block
//初始化两张表,全置0
sigemptyset(&blockset);
sigemptyset(&oblockset);
//向block中添加2号信号,---屏蔽2号
sigaddset(&blockset,2);

signal(2,handler);
//备份原来的block(oblockset是备份),向blockset中设置屏蔽2号信号
sigprocmask(SIG_SETMASK,&blockset,&oblockset);
int count=1;
while(1)
{
//获取pending
sigpending(&pending);
//打印pending
showpending(&pending);
sleep(1);
if((count++)==10)
{
printf("return old blockset\n");
//恢复为原来的pending
sigprocmask(SIG_SETMASK,&oblockset,NULL);
}
}
}


运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: