信号
什么是信号?
-
信号的概念
- 是一个软件中断;通知进程发生了某件事情,中断进程当前操作,让进程去处理这件事情
-
信号的种类
-
操作系统中定义信号的种类:通过kill -l 查看信号种类;信号总共有62种
-
信号有两大类型:
- 可靠信号:1-31号信号
- 非可靠信号:34-64号信号
-
信号的生命周期
产生——>注册——>注销——>处理
-
信号的产生
- 硬件产生
ctrl+c ctrl+| ctrl+z
- 软件产生
kill -signum pid :向进程发送一个signum信号
-
信号的注册
- 未决:信号从产生到处理之前所处的状态
信号在进程中的注册:在进程pcb中做标记,标记哪些进程收到了信号
非可靠信号的注册:判断pcb中的pending位图中相应信号是否已经注册(位图是否已经置为1);若未注册则位图修改为1,向sigqueue链表中添加一个节点;若已经注册则不做任何修改(事件丢失)
可靠信号的注册:不管信号是否已经成功注册,都会向链表中添加一个新的信号节点(事件不会丢失)
我们在上面分别向进程发送2号非可靠信号和40号可靠信号;然后我们向进程发送了5次40号信号,看一下进程会收到几次40号信号
通过这个图我们看到进程收到了5次40号信号,说明可靠信号的注册:不管信号是否已经成功注册,都会向链表中添加一个新的信号节点(事件不会丢失)
然后我们看到我们也向进程发送了5次2号非可靠信号,结果进程只收到一次2号信号;说明非可靠信号在进程中注册的时候,如果已经注册过了就不会在继续注册(事件丢失) - 未决:信号从产生到处理之前所处的状态
-
信号的注销
非可靠信号:节点只有一个,注销就是删除节点,位图置0
可靠信号:节点可能有多个,注销就是删除一个节点;判断链表中是否还有其他相同信号的节点,若没有则位图置0;否则位图不变依然需要标记有这个信号待处理 -
信号的处理
信号的处理并不是立即被处理;而是选择一个合适的时机去处理信号
进程的运行从内核态返回用户态的时候:
内核态:系统的调用接口 用户态:库函数和我们自己写的程序
进程如何从内核态到用户态:发起系统调用,程序异常,中断
进程运行的代码若是库函数或者用户自己写的函数,就说进程当前运行在用户态
信号处理有多种方式:
默认处理方式——即定义好的处理方式
忽略处理方式——处理动作中什么都没做
自定义处理方式——用户自己确定信号如何处理——自定义信号的处理函数替换原有的处理函数
自定义处理方式信号的捕捉流程:
-
信号的阻塞:阻止信号被递达——信号依然可以注册,只是暂时不处理
递达:一个动作——信号的处理 在pcb中还有一个集合——阻塞信号集合——标记哪些信号暂时不被处理
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how:
SIG_BLOCK:向阻塞信号中加入set集合中的信号 block = mask | set
SIG_UNBLOCK :从阻塞信号中移除set集合中的信号 block = mask & (~set)
SIG_SETMASK:将set集合的信号设置为阻塞集合 block = set
oldset: 用于保存修改前,阻塞集合中的信号
在所有的信号中,9号信号SIGKILL和19号信号SIGSTOP,无法被阻塞,无法被自定义,无法被忽略
-