[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 信号。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/144845.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

2024年及未来:构筑防御通胀的堡垒,保护您的投资

随着全球经济的波动和不确定性&#xff0c;通货膨胀已成为投资者不得不面对的现实问题。通胀会侵蚀货币的购买力&#xff0c;从而影响投资的实际回报。因此&#xff0c;制定有效的策略来保护投资免受通胀影响&#xff0c;对于确保资产的长期增值至关重要。在2024年及未来&#…

着色器ShaderMask

说明 实现一个渐变进度条&#xff0c;要求&#xff1a; 颜色渐变的过程是循序渐进的&#xff0c;而不是看起来像是将渐变条逐渐拉长了。 效果 源码 // 渐变进度条Stack(children: [// 背景色板Container(width: 300,height: 8,decoration: BoxDecoration(borderRadius: Bord…

Vue2中路由的介绍和使用

一.路由的基本概念 一说路由&#xff0c;大家首先想到的可能是路由器&#xff0c;路由器的原理就是给连接的设备一个IP地址&#xff0c;通过IP地址来映射到设备&#xff0c;实现连接&#xff0c;本质上是一种映射关系。 在vue2中就是路径与组件间的映射。 路由是使用vue2制作…

基于SpringBoot+Vue的“课件通”中小学教学课件共享平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

昇腾大模型推理解决方案MindIE部署

MindIE大模型推理套件 MindIE&#xff08;Mind Inference Engine&#xff0c;昇腾推理引擎&#xff09;是华为公司针对AI全场景推出的整体解决方案&#xff0c;包含丰富的推理加速套件。通过开放各层次AI能力&#xff0c;支撑客户多样化的AI业务需求&#xff0c;使能百模千态&a…

4G 网络下资源加载失败?一次运营商封禁 IP 的案例分享

在工作中&#xff0c;网络问题是不可避免的挑战之一。最近&#xff0c;我们在项目中遇到了一起网络资源加载异常的问题&#xff1a;某同事在使用 4G 网络连接公司 VPN 时&#xff0c;云服务的前端资源居然无法加载&#xff01;通过一系列的排查和分析&#xff0c;我们发现问题的…

数字产业中心:技术赋能产业,如何重塑行业格局!

在数字化浪潮的推动下&#xff0c;数字产业中心正逐步成为推动经济转型升级的重要引擎。这里&#xff0c;技术不仅仅是工具&#xff0c;更是重塑行业格局、引领未来发展的核心力量。 一、技术融合创新&#xff0c;打破传统边界 数字产业中心通过云计算、大数据、人工智能等前沿…

冬瓜排骨汤的做法

1、准备食材‌&#xff1a; 排骨&#xff1a;选择新鲜的排骨&#xff0c;最好使用肋排&#xff0c;因为肋排肉多&#xff0c;适合炖汤。 冬瓜&#xff1a;去皮去瓤&#xff0c;切成适当大小的块状。 姜片、葱段&#xff1a;用于去腥增香。 调味料&#xff1a;盐、胡椒粉、鸡精…

Simapps新版上线:诚邀广大用户体验,参与有奖调查问卷

Hi~朋友&#xff0c;在使用仿真软件时&#xff0c;是否有过以下困扰呢&#xff1f; Simapps是云道智造匠心打造的互联网时代的科学计算中心、基于云的仿真APP商店&#xff0c;承载海量面向场景和模型的仿真APP&#xff0c;为广大中小企业、高校及科研院所提供普惠仿真工具。 Si…

java框架

Oozie任务调度框架 Hue hadoop的WEB工具 seatunnel 数据同步框架 TIDB 大数据库支持事物 StreamX fink和spark的集成 OceanBase 阿里巴巴数据库 dooringx-lib、AntV 可视化H5工具 lowcode、Appsmith&#xff08;推荐&#xff09;、nocoBase 、Budibase、taskbuilder 低代…

创客匠人案例故事|闭关 20 天,私域大爆发,高额发售秘诀是什么?

不是你的能力决定了你的命运&#xff0c;而是你的决定改变了你的人生 王龙老师心赏教养法创始人心赏家园家庭“心生态”发起人国家二级心理咨询师 他是一名致力于解决家庭困境的老师&#xff0c;通过心赏转化五步法&#xff0c;帮助身陷家庭困境的父母&#xff0c;解决自我关系…

故障:ad18导入板框图后无法按外形生成板框

选择设计-板子形状-按照选择对象定义后 无法顺利生产板框&#xff0c;而是如下提示&#xff1a; could not board outline using primitives centerline due to the following errors: multiple paths found from location:(xxxmm,xxxmm) would you like to try finding bo…

Linux入门学习:Linux调试器gdb使用

1. 背景 程序的发布方式有两种&#xff0c;debug模式和release模式&#xff0c;debug是添加调试信息&#xff0c;release是取消调试信息&#xff0c; Linux gcc/g出来的二进制程序&#xff0c;默认是release模式&#xff0c;要使用gdb调试&#xff0c;必须在源代码生成二进制程…

展会上想要留住俄罗斯客户,柯桥成人俄语培训

展品 экспонат 模型 макет 证明(书) свидетельство 预算 бюджет 确认订单 подтверждение заказа 缺点,毛病,缺陷 недостаток 退换 возвращать 更换 заменять 调整 урегулир…

2024好评的开放式耳机排行榜10强?四款开放式蓝牙耳机推荐

在2024年的耳机市场上&#xff0c;有不少的开放式耳机因其高性价比和多功能性而受到关注。这些耳机不仅音质出色&#xff0c;而且舒适度也很高&#xff0c;能够适应多种使用场景&#xff0c;无论是日常通勤、跑步运动还是在家办公&#xff0c;都很能满足使用者的需求。 虹觅 Fi…

CCRC-CDO首席数据官引领构建活数据引擎

在数字化浪潮的强劲推动下&#xff0c;数据已然成为企业不可或缺的宝贵资产&#xff0c;它不仅记录着历史的足迹&#xff0c;更指引着未来发展的方向。 随着大数据、人工智能、云计算等技术的迅猛发展&#xff0c;数据的潜力获得了前所未有的激发。 首席数据官&#xff08;CD…

实习生上班摸鱼刷题,被开除了!

大家好&#xff0c;我是程序员鱼皮&#xff0c;之前分享过我们团队开发的程序员面试刷题工具 - 面试鸭&#xff0c;已经有 10 万多名同学在这里刷题了。 我们通过分析近期的系统用量发现&#xff0c;每天的 9 - 12 点、14 - 18 点&#xff0c;是刷题用户数的高峰&#xff1a; 这…

Sui Builder House: 新加坡的五大难忘时刻

新加坡Sui Builder House刚刚落幕&#xff0c;社区的参与热情空前高涨&#xff01;活动现场充满了令人振奋的公告、有趣的互动活动&#xff0c;以及社区成员和行业领袖之间的热烈讨论。仅一天时间内&#xff0c;超过600位来自各个社区和行业的参与者齐聚新加坡&#xff0c;纷纷…

【后端开发】JavaEE初阶——计算机是如何工作的???

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解计算机工作原理&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【MySQL】MySQL中JDBC编程——MySQL驱动包安装——&#xff08;超详解&#xff09; &#x1f308;感兴趣的小伙伴看一看小编主…

蓝队技能-应急响应篇Web内存马查杀JVM分析Class提取诊断反编译日志定性

知识点&#xff1a; 1、应急响应-Web内存马-定性&排查 2、应急响应-Web内存马-分析&日志 注&#xff1a;传统WEB类型的内存马只要网站重启后就清除了。 演示案例-蓝队技能-JAVA Web内存马-JVM分析&日志URL&内存查杀 0、环境搭建 参考地址&#xff1a;http…