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

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

@水墨不写bug

(图片来源于网络)

目录

一、认识信号

1、认识信号

2、信号特点

3、基本概念

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

三、信号的保存


正文开始:

一、认识信号

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系统调用可以产生信号:

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。
    到这里,我们可以总结:

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

实验:检测信号的保存

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

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

cpp 复制代码
#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;
}

完~

未经作者同意禁止转载

相关推荐
黑客呀35 分钟前
网络安全——防火墙
服务器·网络·php
明金同学1 小时前
腾讯云海外服务器Window切换为linux系统(从Window DD 到 Linux)
linux·服务器·腾讯云
CC大煊2 小时前
【Linux】vi/vim 使用技巧
linux·运维·vim
weixin_399380692 小时前
Tongweb7049M4有关SSL/TLS 服务器瞬时 Diffie-Hellman 公共密钥过弱的处理方案(by lqw)
服务器·网络协议·ssl
是十一月末2 小时前
Linux的基本功能和命令
linux·服务器·开发语言·数据库
聚名网2 小时前
什么叫中间件服务器?
运维·服务器·中间件
暮已深2 小时前
【RTAB-Map+VINS-Fusion+euroc】(Ubuntu 20.04)三维稠密重建-实践笔记
linux·笔记·ubuntu
浮尘笔记3 小时前
在Ubuntu服务器上备份文件到自己的百度网盘
linux·服务器·ubuntu
( •̀∀•́ )9203 小时前
深入理解 XPath:XML 和 HTML 文档的利器
xml·服务器·html
Hacker_xingchen3 小时前
影响 Linux、Unix 系统的 CUPS 漏洞可导致 RCE
linux·运维·unix