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

xiaoxiao2021-02-28  2

阻塞信号

这里我们需要先了解几个基本概念 信号递达(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 *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 | setSIG_UNBLOCK:解除当前block中的信号,mask=mask & ~setSIG_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); } } }

运行结果:

转载请注明原文地址: https://www.6miu.com/read-250374.html

最新回复(0)