【Linux系统】信号的产生

信号

关于信号举一些生活中的例子 --- 比如交通指示灯...

 - 信号在生活中,随时可以产生 --- 信号的产生和我们是异步的!(异步的意思就是信号的产生和我没有直接关系)

- 你能认识这个信号 --- 我们知道这是信号,我们才知道如何处理!

- 我们知道信号产生了,信号该怎么处理! --- 我们应该知道如何处理!

- 我们可能在做着更重要的事情,把到来的信号暂不处理 --- 1.我得记得这个事。2.什么时候处理?合适的时候!!!

那么转回我们的OS中,上面的“我”不就是进程吗!!!

在OS中有31个普通信号,后面35-64为实时信号,我们主要研究普通信号

使用kill -l 命令列出信号列表

信号概念的基本储备

信号:Linux系统提供的一种,向指定进程发送特定事件的方式,做识别和处理。

信号产生是异步的!

信号处理:1.默认动作 2.忽略动作 3.自定义处理 --- 信号的捕捉

进程处理信号,都是默认的 --- 默认动作通常:终止自己、暂停、忽略...

man 7 signal 查看各种信号的信息

 如何理解信号的保存和处理呢?

每个进程都有task_struct的结构体,其中有一个成员变量拥有32个比特位,那么保存就可以使用这些比特位,这就是使用位图来进行信号的保存,保存收到的信号!

发送信号:修改指定进程的PCB中的信号的指定位图,0变为1,写信号!

信号的产生

1.通过kill命令,向指定的进程发送指定的信号。

kill -9 pid --- -9代表要发送的信号,在信号表中,pid代表要发送给哪个进程号

2.键盘可以产生信号。

比如ctrl + c代表kill -9,ctrl + \代表3号信号SIGQUIT

3.系统调用。

kill --- 给指定进程发送指定信号

 raise函数 --- 给当前进程发送指定信号(内部其实本质是封装了系统调用)

abort函数 ---  执行的是6号信号SIGABRT(内部其实本质是封装了系统调用)

 signal --- 自定义捕捉指定信号,去执行handler函数,改变了默认的终止进程的动作

 测试一下signal

#include <iostream>
#include <unistd.h>
#include<signal.h>

void handler(int sig)
{
    std::cout << "get a sig:" << sig << std::endl;
}
int main()
{
    signal(SIGABRT, handler);
    while (true)
    {
        std::cout << "my pid is:" << getpid() << std::endl;
        sleep(1);
    }
    return 0;
}

 

 以上总总只为证明:真正发送信号的其实是谁,是OS!!!

思考:如果我们把所有信号都捕捉了,如何终止进程?

OS也想到了这个问题! --- 9号信号不允许被自定义捕捉

如何理解上面的信号发送?

不就是通过给指定进程发送指定信号,让指定进程做出相应反应吗?

4.软件条件

管道,当管道读端关闭,写端一直写,OS会发送13号SIGPIPE信号终止这个进程!

alarm --- 设置多少秒后再执行相应信号SIGALRM --- 设置一次就默认触发一次

测试代码:

#include <iostream>
#include <unistd.h>
#include<signal.h>

int cnt;

void handler(int sig)
{
    std::cout << "get a sig:" << sig << std::endl;
    exit(1);
}
int main()
{
    signal(SIGALRM, handler);
    alarm(3);
    while (true)
    {
        std::cout << "my pid is:" << getpid() << std::endl;
        cnt++;
        std:: cout << "cnt:" << cnt << std::endl;
        sleep(1);
    }
    return 0;
}

 alarm可以设置闹钟,多少秒后执行结束

alarm(0):取消闹钟

alarm还可以每隔一秒发送一次信号!

#include <iostream>
#include <unistd.h>
#include<signal.h>

int cnt;

void handler(int sig)
{
    alarm(1);
    std::cout << "cnt:" << cnt << " get a sig:" << sig << std::endl;
}
int main()
{
    signal(SIGALRM, handler);
    alarm(1);
    while (true)
    {
        //std::cout << "my pid is:" << getpid() << std::endl;
        cnt++;
        std:: cout << "cnt:" << cnt << std::endl;
        sleep(1);
    }
    return 0;
}

 验证IO --- IO很慢

while循环进行打印++现象

#include <iostream>
#include <unistd.h>
#include<signal.h>

int cnt;

void handler(int sig)
{
    std::cout << "cnt:" << cnt << " get a sig:" << sig << std::endl;
    exit(1);
}
int main()
{
    signal(SIGALRM, handler);
    alarm(1);
    while (true)
    {
        //std::cout << "my pid is:" << getpid() << std::endl;
        cnt++;
        std:: cout << "cnt:" << cnt << std::endl;
        //sleep(1);
    }
    return 0;
}

while循环不打印进行++现象

#include <iostream>
#include <unistd.h>
#include<signal.h>

int cnt;

void handler(int sig)
{
    std::cout << "cnt:" << cnt << " get a sig:" << sig << std::endl;
    exit(1);
}
int main()
{
    signal(SIGALRM, handler);
    alarm(1);
    while (true)
    {
        //std::cout << "my pid is:" << getpid() << std::endl;
        cnt++;
        //std:: cout << "cnt:" << cnt << std::endl;
        //sleep(1);
    }
    return 0;
}

明显后者更快!!!

为什么这样?这是因为当我们使用cout打印到显示器上的时候,是需要拷贝的,再者我们用的是云服务器,从远端服务器上推送到本地是有很大消耗的!!!所以IO很慢!!! 

理解闹钟

我们可以设置很多闹钟,那我们OS要不要对闹钟进行管理呢?

操作系统要对闹钟进行管理,先描述,再组织!

 其实闹钟就是一个结构体

struct alarm

{

        time_t expired;//未来的超时时间=second + Now();

        pid_t pid;

        func_t f;

        ...

};

描述有了,如何组织呢?

我们是不是可以让闹钟按超时时间进行排序,那我们可以使用小根堆,堆顶元素超时我们就pop!!!

闹钟的返回值

alarm的返回值是上一次设置的闹钟到这次设置的闹钟剩余的时间!

所以产生信号其实是系统调用alarm,发送信号是OS发的!!!

5.异常

程序为什么会崩溃???非法访问,操作 ---> 程序出现了异常,OS给进程发送信号了!!

程序崩溃了为什么会退出?--- 信号默认处理是终止进程

可以不退出吗?可以,使用signal捕捉该异常,但我们通常都推荐终止进程!

为什么推荐终止进程? --- 释放进程的上下文数据,包括溢出标志数据或者其他异常数据!

算术运算,逻辑运算原理 

 当我们进行10/0运算时,CPU如何得知运算是正常的还是异常的?

其实在CPU内部有很多的寄存器,有个可以状态寄存器内部有溢出标记位,标记为0,会把计算结果写回到内存,如果标记位为1,就说明运算出现了异常,CPU内部就会出现报错! 

那OS是软硬件资源的管理者,OS要随时处理这种硬件问题! --- 向目标进程发送指定信号!!!

那么回到为什么出现异常推荐终止进程呢?终止进程本质上是释放进程的上下文数据,包括溢出标志数据或者其他异常数据!

野指针为什么捕捉后一直报错?11号信号SIGSEGV

 Core、Term怎么理解?

term代表异常终止,没什么好说的!

core --- 异常终止但是他会帮我们形成一个Debug文件 --- 进程退出的时候的镜像数据!!

---  核心存储

云服务器默认是把core文件关掉的!!

我们来打开

 

 

 会同时为我们生成一个core文件,在Ubuntu下如果运行多次进程出现多次错误会只有1个core文件,而Centos中会有后缀pid跟着,故多次运行会产生多个core文件!!!

 云服务器为什么要关闭核心存储?

所以云服务器为什么要关闭,因为当我们执行错误代码,无意下多次执行的话,可能会造成大量的core文件,这可能会影响云服务器的正常运行,故默认是关闭的!

之前的退出码与信号码之间的core dump标志位就有了解释,1代表开启即Core,0代表关闭即Term!!

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花影随风_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值