0


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

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

@水墨不写bug

(图片来源于网络)

正文开始:

一、认识信号

1、认识信号

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

2、信号特点

    随时可能产生,信号的产生是没有预告的,与你的生活是异步的。

    你能识别信号(可以想想一下,如果不能识别信号,生活会变得怎么样),并且知道得到这个信号之后该怎么做。

    当你收到信号的时候,你可能正在做更加重要的事(比如在期末考),这时需要把信号保存起来,暂不处理。
     **转到OS层面:**
    在进程中,信号可能随时产生,(这意味着OS需要不停的检测信号是否产生),信号的产生和进程异步。

    进程能够识别信号,并且知道得到这个信号之后该怎么做(处理信号)。

    进程可能正在做更加重要的事情,于是可能会把信号暂不处理。

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

3、基本概念

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

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

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

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

ctrl + c :SIGINT(2号信号)

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

(见上图)

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

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

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

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

比如:

    管道read fd关闭,write fd还在写入,OS发送SIGPIPE (13号信号)来杀死write进程。

    alarm系统调用可以产生信号:![](https://i-blog.csdnimg.cn/direct/ebd2beb2120042bebc1bc520226440f5.png)
    **5.异常可以产生信号。**
     对于非法访问操作,被OS检测到,OS会发送信号。

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

    以发生除0错误为例,当发生除0时,CPU内部的eflag(寄存器)的溢出标记位被置1,表明本次运算的结果发生溢出,计算结果不可信。

    CPU是硬件,OS要管理硬件,于是OS会检测到CPU的这个标记位的错误信息,并通过发送信号的方式,终止发生错误的进程。

    **总结:OS通过检测硬件的标记位信息,来判断是否发生了错误。**

三、信号的保存

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

** 概念引入:**

   ** 信号递达:**实际执行信号的过程称为信号的递达(Delivery)。

   ** 信号未决:**信号从产生到递达之间状态称为信号未决(pending)。

   ** 信号阻塞:**进程可以阻塞某一信号,意味着这个信号一旦产生,永远不递达,一直是未决状态,直到主动解除阻塞为止,才执行递达的动作。

注意:

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

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


通过查看kill -l:

发现:

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

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

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

到这里,我们可以总结:

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

实验:检测信号的保存

     ** 注意:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。如何验证(常规信号在递达之前产生多次只记一次)呢?**

    通过下面的这一份实验测试,可以验证。但是你可能会对实验中使用的关于信号的函数接口有疑惑,鉴于此,我会在注释中尽可能详细注明;**并在后续的文章内容中详细讲解系统的信号部分的接口的使用。       **
#include <signal.h>
#include <unistd.h>
#include <iostream>

using std::cout;
using std::endl;
bool loop = true;

void Print(sigset_t &pending)
{
    for (int sig = 31; sig > 0; sig--) // 没有0号信号,信号的范围1——31,两闭
    {
        if (sigismember(&pending, sig))
        {
            cout << 1;
        }
        else
        {
            cout << 0;
        }
    }
    cout << endl;
}
/*一旦检测到3号信号,会走这里的处理逻辑,此时吧loop置false,使得对2号信号的处理逻辑结束。*/
void donesig2(int sig)
{
    cout << "get sig 3" << endl;
    cout << "loop = false, done sig2" << endl;
    loop = false;
}
void sigcb(int sig)
{
    loop = true;
    cout << "get a sig:" << sig << endl;
    while (loop)
    {
        sigset_t pending;
        sigpending(&pending);//函数接口:获取目前的pending位图
        Print(pending);//打印出pending位图,便于观察
        sleep(1);
        signal(3, donesig2);//检测3号信号——在处理信号的同时依然可以接受并处理信号
    }
}

int main()
{
    struct sigaction ac, oac;//一个结构体类型,内部存储有维护信号系统的一系列变量
    ac.sa_flags = 0;//暂时设为0

    /*sa_mask是一个sigset_t类型的位图(sigset_t是一个专门用于维护31个信号位的类型)
    此处这个函数的作用是把这个位图的所有位置全置0(初始化)
    但是这个位图目前还没有被设置进操作系统的信号位图*/
    sigemptyset(&ac.sa_mask);

    /*sa_handler是结构体内部的一个成员,是一个函数指针类型,需要用户自定义实现,
    也就是当进程接受到特定信号之后需要做的处理动作*/
    ac.sa_handler = sigcb;

    while (true)
    {
        //这是一个和上述的结构体类型同名称的一个函数
        //参数:(需要屏蔽的信号,需要设置结构体类型,老的结构体类型,目的是为了保存设置之前的数据,防止用户想要撤回操作)
        sigaction(2, &ac, &oac);//对2号信号进行特殊处理
        sleep(1);
        cout << "I am process:" << getpid() << endl;
    }

    return 0;
}

完~

未经作者同意禁止转载

标签: linux 运维 服务器

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

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

还没有评论