信号的响应过程

13 篇文章 4 订阅

在这里插入图片描述

内核为每个线程都维护了 两个位图:mask和pending

信号屏蔽字 mask :用来表示当前信号的状态,mask初始值一般全部都是1
pending位图: 用来记录当前进程收到哪些信号,一般初始值全部都是0

在程序运行时间片耗尽时,被内核的中断机制打断时,程序保存当前的执行现场,进入到内核态的就绪队列等待就绪,当再次获取时间片时,从内核态回到用户态期间程序会将mask位图 按位与上 pending位图来判断是否接收到信号,当没有信号时,位图结果为0,表示没有收到信号,程序回到之前的执行现场继续执行。程序当收到信号时,对应的信号结果为1,程序执行对应的信号处理函数,此时对应的mask位和pending位均置为0,当执行完信号处理函数后,将对应的mask位置为1,如果时间片没有耗尽就回到用户态执行之前任务的位置,否则进入就绪队列等待调度。
 

程序从接收到信号 到 响应信号会有一个不可避免的延迟,只有程序从内核态 切换到 用户态的时候,才会比较 mask位图 和 pending位图,只有这个时候才能知道 是否收到了信号,收到了哪个信号,以及才会响应信号。

所以思考的问题:

1 信号从收到 到 响应 有一个不可避免的延迟
可以理解为,信号是 程序从 内核态 切换会 用户态的 路上响应的,并且只能在这个时间点响应。所以这个延迟就是 程序 必须重新要从内核态切换到用户态,即必须要有一个新的中断或者时间片耗尽,程序进入内核态 并且 等待调度后 切回 用户态 所需要的时间,所以如果程序收到信号后,一直没有中断打断他,或者时间片一直没有耗尽,即一直没有进入内核态,也就不能从 内核态 切换为 用户态,也就不能比较 两个位图,也就是不能发现信号。

一句话,信号 是程序 从内核态 回到 用户态的路上响应的。
 

2 如何忽略掉一个信号
从上面的信号响应过程可以知道,只要将 mask位图中的 对应信号位 永远置0 即可。这样 就算接收到 对应信号,两个位图比较后,结果也是0,即无信号。

3 标准信号为什么要丢失
程序在响应信号的时候,mask位图,和pending位图的对应信号位都会被置0,而此时如果再发来 一万次 SIGINT信号,那么结果也只是 pending位图的 SIGINT信号为 被反复置1 一万次,结果还是1。即 等程序执行完 信号响应 并重新切换回用户态,mask位图 SIGINT位被重新置1,并再次比较两个位图的时候,尽管接受了一万次SIGINT信号,但是也只知道 最后一次收到的信号。

4 标准信号的响应没有严格的顺序

5 不能从信号处理函数中随意的往外跳
可知,程序从内核态切换到用户态,发现 mask位图 和 pending位图的变化,于是扎内核 替换执行程序地址,去执行信号响应程序,并且将 mask信号屏蔽位置0,等执行完响应程序后 再次重新扎内核,重新将mask信号屏蔽位置1,即将信号屏蔽字 解除阻塞,这样以后才能正常接收信号,最后再回到用户态。如果 在信号响应程序中跳转态其他位置,那么会错过 将信号屏蔽字 解除阻塞的操作,那么以后就无法响应对应的信号了。
所以 setjmp() 和 longjmp() 在信号处理函数中要慎用,可以使用sigsetjmp()和siglongjmp();

上图以进程中为单线程举例,如果是多线程程序,每个线程都有两个位图,以进程为单位只有一个pending位图,当进程收到信号时,在被中断打断后,进入就绪队列等待就绪,当前被调度的线程在内核态回到用户态的途中去响应信号,先用mask位 & 进程的pending位,在用mask去 & 上自己线程的pending位。其他的过程和上面的类似。

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值