信 概念
是一个软件中断,通知进程发生了某件事情,中断进程当前操作,让进程去处理这个事件。
信 有很多种:62种信 ,两大类型:可靠信 :34~64/非可靠信 :1~31.进程必须识别这些信 。
查看信 种类:kill -l
kill杀死进程的原理:向进程发送信 –通知事件,让进程自己退出
信 生命周期:信 的产生—>在进程中注册—>在进程中注销—>信 的处理
信 的产生
硬件产生:ctrl+c ctrl+| ctrl+z
软件产生:kill -signum pid kill(pid, signum) raise(signum) abort() alarm(nsec)
具体代码如下:
信 在进程中的注册
在进程pcb中做标记,标记进程收到了哪些信
未决(pending):是一种状态—表示信 从产生到处理之前所处的状态。
非可靠信 注册:判断pcb中的pending位图中相应信 是否已经注册(位图是否已经置1);若未注册,则位图修改为1,并向sigqueue链表中添加一个信 节点;若已经注册,则不作任何操作(事件丢失)。
可靠信 注册:不管信 是否已经注册,都会向链表中添加一个新的信 节点(事件不会丢失)
信 在进程中的注销
非可靠信 :节点只有一个,注销就是删除节点,位图置0.
可靠信 :节点可能有多个,注销就是删除一个节点,判断链表中是否还有相同信 的节点;若没有则将位图置0;否则位图不变仍然需要标记这个信 待处理。
信 的处理
信 的处理并不是立即被处理,而是选择一个合适的时机去处理信 。—->即进程的运行从内核态返回用户态的时候。
进程如何从用户态切换到内核态:发起系统调用、程序异常、中断。
程序运行的代码若是库函数或是用户自己写的函数,就说进程当前运行在用户态。
信 处理有多种方式:
- 默认处理方式:既定义好的处理方式
- 忽略处理方式:处理动作中什么都没做
- 自定义处理方式:用户自己确定信 如何处理—-自定义信 的处理函数替换原有的处理函数。
如何修改信 处理方式:
sighandler_t signal( int signum, sighandler_t handler);
signum:信 编 —–替换signum这个信 的处理函数
handler:函数指针–用户传入的处理函数
SIG_DFL:信 的默认处理动作
SIG_IGN:信 的忽略处理动作
typedef void (*sighandler_t)(int);
在此段代码中,我们使用sigaction将信 SIGINT的处理动作替换成了我们自定义的函数sigcb,并将原处理方式保存在old_act中,当接收到信 SIGINT时,会打印信 编 ,接下来我们将信 的处理方式又还原成默认处理方式,所以当我们第二次再给一个SIGINT信 的时候,程序就可以直接退出了,运行结果如下:
自定义信 处理方式的捕捉流程
内核如何实现信 的捕捉/strong>
如果信 的处理动作是用户自定义函数,在信 递达时就调用这个函数,这称为捕捉信 。由于信 处理函数的代码是在用户空间的,处理过程比较复杂,举例如下:用户程序注册了SIGQUIT这个信 的处理函数sigcb,当前正在执行main函数,这时发生中断或异常切换到内核态。在中断处理完毕后要返回用户态的main函数之前检查到有信 SIGQUIT递达。内核决定返回用户态之后不是恢复main函数的上下文继续执行,而是执行sigcb函数,sigcb和main函数使用不用的堆栈空间,他们之间不存在调用和被调用的关系,是两个独立的控制流程。sigcb函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。如果没有新的信 要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。
信 阻塞
阻止信 被递达——信 依然可以注册,只是暂时不处理。
注意:阻塞和忽略是不同的,只要信 被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
在pcb中还有一个集合—-阻塞信 集合—-标记哪些信 暂时不被处理。
在上图中,pending位图中标记了一个1 信 ,和一个2 信 ,2 信 被阻塞了,但1 没有被阻塞,成功递达并处理,而2 信 没能递达。
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,无法被阻塞,无法被自定义,无法被忽略。
可重入函数与不可重入函数
函数的重入:多个执行流程同时执行进入相同的函数。
函数的可重入与不可重入:
可重入:多个执行流程同时执行进入相同的函数,不会造成数据二义性以及代码逻辑混乱。
不可重入:多个执行流程同时执行进入相同的函数,有可能造成数据二义性以及代码逻辑混乱。
当用户设计一个函数或使用一个函数的时候,在多个执行流中,那么这时候就需要考虑函数是否可重入情况。
如果一个函数符合以下条件之一则是不可重入的:
- 调用了malloc或free,因为malloc也是用全局链表来管理堆的。
- 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
函数可重入与不可重入的关键点:
这个函数中是否对临界资源(全局数据)进行了非原子操作。
文章知识点与官方知识档案匹配,可进一步学习相关知识CS入门技能树Linux入门初识Linux24975 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!