【Linux】信 相关知识点整理

信 概念

是一个软件中断通知进程发生了某件事情,中断进程当前操作,让进程去处理这个事件。

信 有很多种: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进行处理,非常感谢!

上一篇 2019年5月21日
下一篇 2019年5月21日

相关推荐