0


[Linux] 信号(singal)详解(一)

标题:[Linux] 信号(singal)详解

@水墨不写bug

(图片来源于网络)

正文开始:

一、认识信号

1、认识信号

  1. 信号,联系生活,比如你看到钟表知道现在的时间,于是提醒自己这会儿要要干啥了;再比如,在过马路时,看到信号灯是红色,你会停下来等待,直到信号灯变绿。这都是信号的例子,其实**信号简而言之,就是一种简易的信息传递方式。**

2、信号特点

  1. 随时可能产生,信号的产生是没有预告的,与你的生活是异步的。
  2. 你能识别信号(可以想想一下,如果不能识别信号,生活会变得怎么样),并且知道得到这个信号之后该怎么做。
  3. 当你收到信号的时候,你可能正在做更加重要的事(比如在期末考),这时需要把信号保存起来,暂不处理。
  1. **转到OS层面:**
  1. 在进程中,信号可能随时产生,(这意味着OS需要不停的检测信号是否产生),信号的产生和进程异步。
  2. 进程能够识别信号,并且知道得到这个信号之后该怎么做(处理信号)。
  3. 进程可能正在做更加重要的事情,于是可能会把信号暂不处理。

综上,OS需要组织信号,并且需要在合适的时候处理信号。

3、基本概念

  1. ** 信号是LINUX OS 提供的一种,向指定进程发送特定信息的方式。目的是让进程做识别和处理。**

二、信号的产生(5种方式)

  1. **1.通过kill指令,向特定的进程发送信号。**
  1. 首先可以通过 **kill -l **查看所有的信号类型:

  1. 对于不同种类的信号,OS会有不同的处理方式(后文将会有详细解释)
  1. ** 2.键盘可以产生信号。**

ctrl + c :SIGINT(2号信号)

ctrl + \ = | : SIGQUIT(3号信号)

(见上图)

  1. **3.系统调用可以产生信号。**

int kill(pid_t id,int sig);——kill命令的底层

**void abort(void); ——产生 SIGABRT; **

  1. ** 4.软件条件可以产生信号。**

比如:

  1. 管道read fd关闭,write fd还在写入,OS发送SIGPIPE 13号信号)来杀死write进程。
  2. alarm系统调用可以产生信号:![](https://i-blog.csdnimg.cn/direct/ebd2beb2120042bebc1bc520226440f5.png)
  1. **5.异常可以产生信号。**
  1. 对于非法访问操作,被OS检测到,OS会发送信号。

OS为什么可以检测到信号?

  1. 以发生除0错误为例,当发生除0时,CPU内部的eflag(寄存器)的溢出标记位被置1,表明本次运算的结果发生溢出,计算结果不可信。
  2. CPU是硬件,OS要管理硬件,于是OS会检测到CPU的这个标记位的错误信息,并通过发送信号的方式,终止发生错误的进程。
  3. **总结:OS通过检测硬件的标记位信息,来判断是否发生了错误。**

三、信号的保存

  1. 信号的保存和处理其实是密切联系的。信号的保存通过三张表实现的——**block位图、pending位图、handler函数指针表。**

** 概念引入:**

  1. ** 信号递达:**实际执行信号的过程称为信号的递达(Delivery)。
  2. ** 信号未决:**信号从产生到递达之间状态称为信号未决(pending)。
  3. ** 信号阻塞:**进程可以阻塞某一信号,意味着这个信号一旦产生,永远不递达,一直是未决状态,直到主动解除阻塞为止,才执行递达的动作。

注意:

** 信号的阻塞与其是否未决无关。**

** 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。**


通过查看kill -l:

发现:

  1. **普通信号一共31个**。如果用一个位图来存储,需要31bit位,于是Linux OS提供了一个专门的数据类型用作位图:**sigset_t 。**

  1. 本章开头所说的**2张位图和一张函数指针表**实际就是存储在进程的**task_struct**中的:

  1. 每个信号都有两个标志位分别表示**阻塞(block)**和**未决(pending)**,和**函数指针表(handler)**表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志(设置为1),直到信号递达才清除该标志(设置为0)。
  1. 在上图的例子中:
  • ** SIGHUP**信号未阻塞也未产生过;当它递达时执行默认处理动作。
    1. **SIGINT**信号产生过,但正在被阻塞,所以暂时不能递达;虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有可能会对SIGINT进行自定义处理,进而解除阻塞之后可能会产生意想不到的结果。
    1. ** SIGQUIT**信号未产生过;SIGQUIT产生之后,一旦产生SIGQUIT信号将被解除阻塞,它的处理动作是用户自定义函数sighandler

到这里,我们可以总结:

  1. **两张位图和一张函数指针数组,可以实现让进程识别信号!! **

实验:检测信号的保存

  1. ** 注意:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。如何验证(常规信号在递达之前产生多次只记一次)呢?**
  2. 通过下面的这一份实验测试,可以验证。但是你可能会对实验中使用的关于信号的函数接口有疑惑,鉴于此,我会在注释中尽可能详细注明;**并在后续的文章内容中详细讲解系统的信号部分的接口的使用。 **
  1. #include <signal.h>
  2. #include <unistd.h>
  3. #include <iostream>
  4. using std::cout;
  5. using std::endl;
  6. bool loop = true;
  7. void Print(sigset_t &pending)
  8. {
  9. for (int sig = 31; sig > 0; sig--) // 没有0号信号,信号的范围1——31,两闭
  10. {
  11. if (sigismember(&pending, sig))
  12. {
  13. cout << 1;
  14. }
  15. else
  16. {
  17. cout << 0;
  18. }
  19. }
  20. cout << endl;
  21. }
  22. /*一旦检测到3号信号,会走这里的处理逻辑,此时吧loop置false,使得对2号信号的处理逻辑结束。*/
  23. void donesig2(int sig)
  24. {
  25. cout << "get sig 3" << endl;
  26. cout << "loop = false, done sig2" << endl;
  27. loop = false;
  28. }
  29. void sigcb(int sig)
  30. {
  31. loop = true;
  32. cout << "get a sig:" << sig << endl;
  33. while (loop)
  34. {
  35. sigset_t pending;
  36. sigpending(&pending);//函数接口:获取目前的pending位图
  37. Print(pending);//打印出pending位图,便于观察
  38. sleep(1);
  39. signal(3, donesig2);//检测3号信号——在处理信号的同时依然可以接受并处理信号
  40. }
  41. }
  42. int main()
  43. {
  44. struct sigaction ac, oac;//一个结构体类型,内部存储有维护信号系统的一系列变量
  45. ac.sa_flags = 0;//暂时设为0
  46. /*sa_mask是一个sigset_t类型的位图(sigset_t是一个专门用于维护31个信号位的类型)
  47. 此处这个函数的作用是把这个位图的所有位置全置0(初始化)
  48. 但是这个位图目前还没有被设置进操作系统的信号位图*/
  49. sigemptyset(&ac.sa_mask);
  50. /*sa_handler是结构体内部的一个成员,是一个函数指针类型,需要用户自定义实现,
  51. 也就是当进程接受到特定信号之后需要做的处理动作*/
  52. ac.sa_handler = sigcb;
  53. while (true)
  54. {
  55. //这是一个和上述的结构体类型同名称的一个函数
  56. //参数:(需要屏蔽的信号,需要设置结构体类型,老的结构体类型,目的是为了保存设置之前的数据,防止用户想要撤回操作)
  57. sigaction(2, &ac, &oac);//对2号信号进行特殊处理
  58. sleep(1);
  59. cout << "I am process:" << getpid() << endl;
  60. }
  61. return 0;
  62. }

完~

未经作者同意禁止转载

标签: linux 运维 服务器

本文转载自: https://blog.csdn.net/2301_79465388/article/details/144155293
版权归原作者 水墨不写bug 所有, 如有侵权,请联系我们删除。

“[Linux] 信号(singal)详解(一)”的评论:

还没有评论