【Linux课程学习】:第二十一弹---深入理解信号(中断,信号,kill,abort,raise,larm函数)

news/2024/12/15 5:41:40/

🎁个人主页:我们的五年

🔍系列专栏:Linux课程学习 

🌷追光的人,终会万丈光芒

🎉欢迎大家点赞👍评论📝收藏⭐文章

Linux学习笔记:
 https://blog.csdn.net/djdjiejsn/category_12669243.html

前言:

本篇是对上一篇信号的基础部分再一次讲解,对信号的有一个更深入的理解。相信看完下面的部分,我们能更清楚的认识到信号的本质。

目录

一.理解OS如何得键盘有数据

1.1硬件中断的定义:

1.2理解硬件中断和软件信号:

1.3阐述中断到CPU拿到数据的全过程:

 二.通过系统命令向进程发信号:

2.1系统命令发生信号的方法:

2.系统命令的预想:

 2.3结构分析:

 三.给后台进程发送终止信号的以后,为什么回车才能显示退出信息?

四.使用函数产生信号

🥪kill函数:

1.函数原型:

2.函数解析:

3.函数实践

🥪 raise函数和abort函数:

1.raise函数:

2.abort函数:

五.由软件条件产生信号

5.1alarm函数介绍:

5.2函数使用:

​编辑

5.3理解软件条件产生信号:

5.4OS如何管理信号:

六.硬件条件产生信号:

七.本篇总结:


一.理解OS如何得键盘有数据

信号
中断

1.1硬件中断的定义:

硬件中断是由与系统相连的外设(如磁盘、网卡、键盘、时钟等)自动产生的异步信号。这些外设通过总线将中断信号发送给中断控制器,再由中断控制器转发给CPU。每个设备或设备集都有自己的中断请求(IRQ)号,基于这个IRQ号,CPU可以将相应的请求分发到对应的硬件驱动上

每一个硬件都有自己的中断请求号(IRQ),所以以后的中断就能区分是哪个硬件发来的,就可以让CPU去哪个硬件读取数据。

中断确实是通过电路给CPU发信号的。

1.2理解硬件中断和软件信号:

1.信号其实是在模拟硬件中断的行为,只是信号是软件层面的,中断是硬件层面的。

2.中断是通过电路进行发生的,是发给CPU的,而信号是发给进程的。

3.两者有相似性,但是层级不同。

1.3阐述中断到CPU拿到数据的全过程:

当我们键盘按下以后,键盘通过电路(高电压)向CPU的针脚发送中断信息,CPU执行操作系统保存当前进程的代码和数据,然后操作系统停下来去读取外设的内存。


 二.通过系统命令向进程发信号:

2.1系统命令发生信号的方法:

通过kill -(信号编号)(进程pid):对进程发送信号

通过上面的方法就能给指定的进程发送指定的信号,下面的代码我们可以给指定的信号。

2.系统命令的预想:

我们可以让一个进程死循环,然后启动另外一个shell对该进程发送一系列的信号。或者我们可以通过对某个信号进程捕捉,然后给进程发该信号,然后去执行我们的自定义行为。有很多的中断进程的信号,我们还可以去发送其他的信号观察进程的反应情况。

#include <iostream>
#include <unistd.h>
#include <signal.h>void handle(int signo)
{std::cout << "signo:" << signo << "系统命令" << std::endl;
}int main()
{//自定义SIGINT-2号信号的行为,让二号信号不再执行终止进程的操作::signal(SIGINT, handle);while (true){std::cout << "pid:" << getpid() << std::endl;sleep(1);}return 0;
}

 2.3结构分析:

因为是前台进程,我们只能通过另外一个shell对死循环的进程发送2号信号,3号信号。发送2号信号,打印2号信号的数字2,还有系统命令。


 三.给后台进程发送终止信号的以后,为什么回车才能显示退出信息?

shell的设计理念是不希望用户的输入信息和出错的信息交错在一起。

所以为什么要按一次回车才能显示退出的信息是因为:

是因为进程在退出之前就来到了shell命令行提示符,等待用户输入,此时shell不希望和输入交错,所以按回车以后才能打印退出的信息。

在Shell中,确实存在后台进程的退出信号和用户的输入可能交错在一起的情况,但这种情况并不是Shell所期望的,也不是设计上的必然结果。这种交错通常是由于多个进程同时向同一个输出流(如标准输出或标准错误)写入数据,并且输出缓冲机制的作用导致的。


四.使用函数产生信号

🥪kill函数:

1.函数原型:

头文件:

#include <sys/types.h>
#include <signal.h>

函数原型:

int kill(pid_t pid, int sig);

作用:

kill - send signal to a process

2.函数解析:

函数的作用是给一个指定的进程发送指定的信号,pid是指定进程的pid,sig是信号的编号。

3.函数实践

下面是通过kill给自己发信号,然后到达执行自定义行为的过程。通过kill函数,

我们可以获取命令行的信息,实现自己的kill命令,直接和系统接轨。

#include <iostream>
#include <unistd.h>
#include <signal.h>void handle(int signo)
{std::cout << "signo:" << signo << "系统命令" << std::endl;
}int main()
{// 自定义SIGINT-2号信号的行为,让二号信号不再执行终止进程的操作::signal(SIGINT, handle);sleep(2);::kill(getpid(), 2);while (true){std::cout << "pid:" << getpid() << std::endl;sleep(1);}return 0;
}

🥪 raise函数和abort函数:

1.raise函数:

raise函数只能给当前的进程发送一个指定的信号,进程的固定的,信号的种类可以选择。

使用场景:

当一个进程需要主动触发某个信号时,可以使用raise函数。例如,在信号处理函数中捕获到一个信号后,通过raise函数手动发送另一个信号作为后续操作。

头文件:

#include <signal.h>

函数原型:

int raise(int sig);

2.abort函数:

所在库:

#include <stdlib.h>

函数原型:

void abort(void);

abort没有返回任何值,总是运行失败。

使用场景:用于调试触发断点

abort函数主要用于处理系统错误,在调试中触发断点以便检查程序状态,以及确保程序在出现异常时不会继续执行无用操作。


五.由软件条件产生信号

本点的主人公是:alarm函数

5.1alarm函数介绍:

作用:
alarm - set an alarm clock for delivery of a signal

所在库:
#include <unistd.h>

函数原型:

unsigned int alarm(unsigned int seconds);

alarm的作用是给进程设置一个闹钟,到时间到了的时候,就会给进程发送一个SIGALRM信号。

如果参数为0,就是取消之前设置的闹钟,只能设置一个。当之前设置的闹钟还没结束,又去设置一个信号的闹钟,那么返回值就是之前闹钟剩余的秒数。

5.2函数使用:

#include <iostream>
#include <unistd.h>
#include <signal.h>void handle(int signo)
{std::cout << "signo:" << signo << "闹钟响啦" << std::endl;
}int main()
{// 自定义SIGLRM信号的行为,让信号不再执行终止进程的操作::signal(SIGALRM, handle);::alarm(3);while (true){std::cout << "pid:" << getpid() << std::endl;sleep(1);}return 0;
}

5.3理解软件条件产生信号:

alarm函数,是在操作系统内核设置了一个定时器,在时间到了的时候就会给进程发送SIGALRM信号,在操作系统内核设置,操作系统也是一个软件,所以是属于软件层面的。

这些条 件包括但不限于定时器超时(如alarm函数设定的时间到达)软件异常(如向已关闭的管道写数据产⽣的SIGPIPE信号)等。

5.4OS如何管理信号:

学了那么就的面向对象,在管理一个东西的时候,当然是先描述,再组织啦。

下面OS对于闹钟的描述,其中包括了剩余时间entry还有执行方法function

六.硬件条件产生信号:

当发生硬件异常的时候,硬件会通过异常等信息告诉操作系统,然后让操作系统结束该进程。当然,我们也可以捕捉这个信号,让它不执行结束进程的操作。

1.当代码中有除以0,或者其他的错误,CPU会产生异常,操作系统OS对于这个异常的处理方法是:对进程发送SIGFPE信号。

2.⽐如当前进程访问了⾮法内存地址, MMU会产⽣异常,内核将这个异常解释为SIGSEGV信号发送
给进程。

除0导致的CPU异常。

#include <iostream>
#include <unistd.h>
#include <signal.h>void handle(int signo)
{std::cout << "signo:" << signo << ",CPU异常" << std::endl;sleep(1);
}int main()
{// 自定义SIGFPE号信号的行为,让SIGFPE信号不再执行终止进程的操作::signal(SIGFPE, handle);int n = 1 / 0;return 0;
}

 

在这里,为什么会循环打印这个了? 

因为在除0以后,进程PCB中,一直保存这该进程出现了异常,不能继续往下执行,所以CPU每次从信号处理完以后,准备进入主控制流的时候,还会进行检查,结果除0异常的信息还没被处理,那么OS又会给进程发送SIGFPE信号。

七.本篇总结:

🍒1.上面信号产生的方法,都要经过OS这一步,因为信号是发给进程的,OS是进程的管理者。

🍒2.信号是否立刻执行?不会立刻执行,只有当block解除以后,才能处理信号,如果不解除block,那么永远不会处理信号。

🍒3.在进程还没收到信号的时候,在handler表中就已经有对应信号的执行方法。

🍒4.如果信号是被立刻执行,那么它会把pending表对应的位图置为1。



http://www.ppmy.cn/news/1555220.html

相关文章

360智脑张向征:共建可信可控AI生态 应对大模型安全挑战

发布 | 大力财经 人工智能的加速发展&#xff0c;有力推动了社会的数智化转型&#xff1b;与此同时&#xff0c;带来的相关安全风险也日益凸显。近日&#xff0c;在北京市举办的通明湖人工智能开发与应用大会上&#xff0c;360智脑总裁张向征以“大模型安全研究与实践”为主题&…

编译glibc

首先下载glibc库 glibc官网&#xff1a;https://sourceware.org/glibc/sources.html 可以通过git的方式下载glibc对应的git库 ​git clone https://sourceware.org/git/glibc.gitcd glibcgit checkout master​ 也可以通过ftp下载对应版本的glibc的源码包 地址&#xff1a;…

服务发现Discovery和Eureka自我保护

服务发现Discovery和Eureka自我保护 1.controller添加 RestController Slf4j public class PaymentController {Resourceprivate DiscoveryClient discoveryClient;GetMapping(value "/payment/discovery")public Object discovery(){List<String> services…

基于python实现自动化的验证码识别:探索与实践

基于python实现自动化的验证码识别&#xff1a;探索与实践 一、验证码的类型及特点&#xff08;一&#xff09;图像验证码&#xff08;二&#xff09;短信验证码&#xff08;三&#xff09;语音验证码 二、验证码识别的方法*&#xff08;一&#xff09;传统图像处理方法&#x…

爬虫学习案例3

爬取美女图片 优美图库地址 一页图片 安装依赖库文件 pip install selenium requests beautifulsoup4import time import requests import random from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.service import Service fr…

前端(Axios和Promis)

Promise 语法 <script>// 创建promise对象// 此函数需要再传入两个参数,都是函数类型let pnew Promise((resolve,reject)>{if(3>2){resolve({name:"李思蕾",age:23,地址:"河南省"});}else{reject("error");}});console.log(p);p.th…

基于springboot的机器人学习交流网站系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

抓取价格数据,进行合同报价等工作已全面实现自动化

随着数字化转型的加速推进&#xff0c;企业面临的市场竞争日益激烈。为了在激烈的市场中保持竞争力&#xff0c;企业需要更快速、更高效地做出决策&#xff0c;尤其是在价格数据的抓取和合同报价环节。传统的手动操作方式不仅费时费力&#xff0c;还容易出错&#xff0c;拖慢了…