Linux 信号详解

news2024/10/4 11:06:10

目录

一.前置知识

1.前台进程和后台进程

a.概念理解

b.相关指令

2.信号的前置知识

a.Linux 系统下信号的概念

b.进程对信号的处理方式

3.信号的底层机制

二.详解信号

1.信号的产生

a.键盘组合键

b.kill 指令和系统调用接口

① kill 指令

② kill() 系统调用接口

③ raise() 系统调用接口

c.硬件级异常问题产生信号

①除零报错

②野指针报错

d.由软件条件产生信号

①匿名管道

②闹钟

2.信号的发送

a.OS给进程发信号的实质

① Pending表(未决信号集)

② Block表(信号屏蔽集)

③ handler表(信号处理函数表)

④小结

b.信号集操作函数

①有关sigset_t类型位图操作的函数接口

②sigprocmask

③sigpending

c.屏蔽进程的指定信号(代码实战)

3.信号的处理

a.用户态和内核态

b.用户态和内核态间的切换方式

①系统调用

②抛异常

③中断

c.重谈地址空间

4.信号的捕捉

a.signal

b.sigaction

c.实战演练

三.信号驱动回收子进程(附加篇)


一.前置知识

1.前台进程和后台进程

a.概念理解

前台进程:Linux系统中,前台只能运行一个进程,并且在进程运行期间,命令行失效,此时,如果我们想控制该进程,就只能通过信号!!

后台进程:可以同时运行多个进程,进程在运行期间,命令行仍起作用,但我们无法以键盘组合键的方式向后台进程发送控制指令。

由于后台进程可能同时运行多个,所以,每个后台运行的进程都会有自己的编号 [x]

b.相关指令

当我们向运行某个可执行程序时,如:./test 即让 test 可执行程序在前台运行。如果我们在其后加上 & 如: ./test & 则表示使 test 可执行程序在后台运行。

jobs —— 查看系统后台进程情况

fg + [x] —— 可以将编号为x的进程切换到前台

Ctrl + z —— 暂停前台进程,同时将该进程转到后台去

bg+ [x] —— 将后台被暂停的编号为x的进程启动

2.信号的前置知识

a.Linux 系统下信号的概念

什么是信号?简单来说,操作系统向目标进程发送的控制指令就是信号。

进程和信号的关系

①进程必须要有能力“识别”并“处理”信号,即使进程还未收到这一信号。

②进程收到某一信号时,可能不会立即对这一信号做出处理动作,也就是说,进程在收到信号和处理信号间有一个“空窗期”,这就要求进程具备对信号的临时存储能力。

kill -l  查看Linux系统中的各个信号,如下图:

man 7 signal —— 用于查看信号相关信息的命令。该命令会展示关于信号机制的详细解释,包括信号的含义、产生原因、默认行为、处理方式。

b.进程对信号的处理方式

进程对信号的处理方式一共有三种:①默认动作;  ②忽略;  ③*自定义动作(信号捕捉)。

什么是默认处理动作?--- 就是进程处理某一信号时, 该信号的功能是系统默认赋予的。例如:9号信号的功能是终止某一进程,当进程收到9号信号时,执行的功能就是将自己终结。

忽略行为该如何理解?--- 进程收到信号,但却不执行信号的功能,就是忽略。

*自定义动作指的是什么?--- 用户捕捉某个或某些信号,并对它们的功能进行修改,当进程收到这些信号时,会执行用户重新为信号赋予的功能,这就是自定义动作。

3.信号的底层机制

情景:当前台进程正在运行时,我们输入的 Ctrl + C 是如何终止进程的?或者说,我们输入 Ctrl + C后,OS底层都做了哪些事?

首先,OS如何知道外设的数据输入??—— 中断技术

当硬件设备有数据输入时,产生的光电信号经过8259表的特殊处理,会激活CPU上与该外设相连接的针脚,在CPU寄存器上生成中断号,随后,OS通过该中断号遍历中断向量表,找到表上记录的相应硬件的处理方法,即OS会从键盘缓冲区读取数据,并对读取的数据类型做判断,若其为组合的控制键(如:Ctrl + c、Ctrl + v),则OS向前台进程发送对应的信号,若为普通的输入数据,则将其拷贝到指定的内存缓冲区上。

至于,当进程收到信号后,对信号的识别、存储和执行,咱们放在后文中细讲~~

但有一点需要先提一下:信号的本质就是用软件来模拟中断的行为!!

二.详解信号

1.信号的产生

a.键盘组合键

如:

Ctrl + c   向前台进程发送2号信号 —— 其功能默认是终止进程

Ctrl + \    向前台进程发送3号信号  —— 其功能默认是终止进程

注意:9号(暂停进程)和19号(杀掉进程)不能被signal自定义捕捉!!

b.kill 指令和系统调用接口

① kill 指令

命令行上,我们可以使用 kill -x  + pid,通过目标进程的pid,向目标进程发送 x 号信号。

② kill() 系统调用接口

代码中,我们可以使用 kill(pid_t pid , int signal)函数,通过进程的 pid,向目标进程发送 signal 号信号。若发送成功,返回0;发送失败,则返回-1.

为了能够灵活的指定目标进程的控制信号,我们可以通过用命令行参数的方式拿到目标进程的pid和控制信号,如:

运行效果:

③ raise() 系统调用接口

当代码执行到 raise(int signal)函数时,OS会向自身发送 signal 号信号。

c.硬件级异常问题产生信号

①除零报错

当源文件的代码有类似除零这样的运算错误时,可执行程序运行时报错的底层原理是什么??

当可执行程序被加载到内存后,OS先将进程的 task_struct 放到运行队列,随后CPU执行程序代码,当CPU状态寄存器发现有除零操作时,其溢出标记位直接被置为1,从而形成在硬件层面上的报错,作为硬件的管理者,OS会从CPU那里拿到错误信息,又作为进程的管理者,OS把CPU溢出标记位信息翻译成终止信号,最后向目标进程发信号将其终止掉。

②野指针报错

当程序中出现这样的代码时: int * p=nullptr; *p=1;  典型的野指针问题,程序运行出错(段错误),那么其底层的原理是什么?

nullptr进程地址空间上的位置是0号地址*p=1是通过页表将1写到“与0号地址空间构成映射关系”物理内存上,但是,由于页表并未记录物理内存与地址空间上0号地址的映射关系,并且0号地址非法,所以当CPU通过MMU(内存管理单元,可以将虚拟地址翻译成物理地址)将值写入内存时,MMU报错,即硬件层面上的出错!!报错信息会被OS捕捉到,然后OS会向该进程发送终止信号,把该进程杀掉。

d.由软件条件产生信号

①匿名管道

进程间通信机制中,有个东西叫做匿名管道(博主以前文章中有过详细讲解),当匿名管道的读端关闭,写端一直向管道内写入数据的话,OS就会向该进程发送13号信号(SIGPIPE)干掉进程!

②闹钟

alarm() 函数是一个用于设置定时器的系统调用函数,它的主要功能是设置一个定时器(闹钟),当定时器时间到达时,内核会向当前进程发送14号信号(SIGALRM)信号。

总结:产生信号的方式可能有很多,但向进程发送信号的只能是OS!!

2.信号的发送

a.OS给进程发信号的实质

OS通过进程pid找到进程的PCB,然后将发送的信号写到进程PCB内的信号位图上,这就是OS给进程发送信号的本质。

那么问题来了,信号位图是什么?

我们知道,进程PCB在创建时,就已经内置了对信号的处理方法,即PCB需要具有识别、存储并执行每一种信号的能力,那么,这个能力是什么??--- 进程PCB内有关信号的三张表

进程PCB内有关信号的三张表指的是什么?

① Pending表(未决信号集)

它本身是一个位图,其中,比特位的大小表示信号值(如:位图的第8个比特位表示8号信号),比特位的内容表示进程是否收到对应信号(如:位图的第8个比特位值为0,表示进程未收到8号信号;若值为1,则表示进程收到了8号信号),Pending 表的功能是用来记录当前进程收到了哪些信号。

② Block表(信号屏蔽集)

它也是一个位图,其中,比特位的大小表示信号值,比特位的内容表示对应信号是否被进程屏蔽。

注意信号屏蔽和信号忽略的区别

信号屏蔽:信号屏蔽是指进程对特定信号进行屏蔽,使得这些信号在发生时不会被立即处理,而是处于未决状态。只有当进程的信号屏蔽集发生改变,不再屏蔽这些信号时,这些信号才会被捕获并处理。信号屏蔽是一种将信号处理进行延后的机制。

信号忽略:信号忽略则是指进程对特定信号进行忽略处理,即当这些信号发生时,进程会接收到信号,但不会对信号进行任何处理。需要注意的是,并非所有信号都可以被忽略,如SIGKILL和SIGSTOP等信号就不能被忽略。

③ handler表(信号处理函数表)

定义:handler表是一个映射表,它将信号的编号(如SIGINT、SIGTERM等)与相应的处理函数(这些处理函数可以是用户自定义的,也可以是系统默认的)建立映射关系

作用:当进程接收到一个信号时,内核会暂停当前进程的执行,并根据信号的编号在handler表中查找对应的处理函数。如果找到了处理函数,则执行该函数;如果没有找到(即该信号被忽略或未设置处理函数),则根据信号的默认行为进行处理。

④小结

实际执行信号的处理动作称为信号递达(handler).

信号从产生到递达之间的状态称为信号未决(pending).

进程可以选择阻塞某个信号(block).

被阻塞的信号产生时将保持在未决状态,暂时不递达(不处理),直到进程解除对此信号的阻塞,才执行递达的动作。

b.信号集操作函数

①有关sigset_t类型位图操作的函数接口

int  sigemptyset( sigset_t*  set);   功能:将set中所有比特位的值置为0

int  sigfillset( sigset_t*  set);  功能:将set中所有比特位的值置为1

int  sigaddset( sigset_t*  set , int signo);  功能:在set中添加信号signo

int  sigdelset( sigset_t*  set , int signo);  功能:在set中将信号signo删除

int  sigismember( sigset_t*  set , int signo);  功能:判断set中信号signo是否存在

②sigprocmask

③sigpending

int sigpending(sigset_t *set); 函数能够查询当前进程或线程的未决信号集(也就是Pending表的内容),并将该集合复制到set参数指向的信号集中。

sigpending() 函数通常与sigprocmask() 函数一起使用,以管理进程的信号屏蔽字和未决信号集合。例如,在更改进程的信号屏蔽字之前,可以使用sigpending() 函数查询当前的未决信号集合,以便在之后恢复信号屏蔽字时能够正确处理这些未决信号。

c.屏蔽进程的指定信号(代码实战)

3.信号的处理

我们已经知道:OS向进程发送信号的实质是将信号写入进程PCB中的Pending表。那么,进程是在什么时候执行信号的具体功能的呢?--- 进程从内核态返回到用户态的时候,进行信号的检测和信号的处理。

那么,什么是内核态?什么又是用户态?进程又是如何从内核态返回到用户态的呢?

a.用户态和内核态

用户态和内核态是操作系统中的两种重要状态,它们分别代表了不同的运行级别和权限范围。

用户态:用户态是用户程序运行时的状态,在这种状态下,CPU只能执行非特权指令不能直接访问内存硬件设备,也不能执行特权操作,如修改系统配置、访问其他进程的内存等。用户态下的程序运行在用户空间,其资源访问权限受到严格限制,只能访问自己的[0 , 3GB]空间,以确保系统的安全性和稳定性。

内核态:内核态是操作系统内核运行时的状态,在这种状态下,CPU可以执行所有的指令,包括特权指令,可以访问所有的内存地址和硬件设备,拥有最高的权限。内核态下的程序运行在内核空间,负责管理系统资源、处理硬件事件、提供系统服务等。

b.用户态和内核态间的切换方式

①系统调用

用户态进程通过系统调用请求操作系统提供服务时,会触发从用户态到内核态的切换,系统调用是用户态进程主动要求切换到内核态的一种方式。

②抛异常

当CPU在执行用户态下的程序时,如果发生某些事先不可知的异常(如缺页异常),会触发由当前运行进程切换到处理此异常的内核相关程序中,从而转到内核态。

③中断

当外围设备完成用户请求的操作后,会向CPU发出中断信号。CPU在接收到中断信号后,会暂停执行当前的用户态程序,转而执行与中断信号对应的内核中断处理程序,从而完成从用户态到内核态的切换。

进程执行信号功能的底层示意图

图解:操作系统在用户态执行系统调用接口时,会从用户态——>内核态,以内核态的权限执行内核代码,当OS从内核态返回到用户态时会进行信号检测,若有用户自定义捕捉信号,则执行处理方法(内核——>用户),执行完后,会通过特定的系统调用接口,从用户再回到内核态,最后从内核态携着系统调用接口的返回信息回到用户态,即主控制流程。

c.重谈地址空间

就如曾经的库函数调用一样,调用系统调用接口,也是在进程的地址空间上进行的!!

操作系统的朴素理解:就是基于一个时钟中断的死循环!!

4.信号的捕捉

 什么是信号捕捉?本质是对某个或某些信号的功能进行重定义,当OS给当前进程发送相关信号时,进程会执行重定义后的功能,这就是信号捕捉。

如何进行信号捕捉?--- 系统调用接口:①signal;   ②sigaction。

接下来,咱们会详解这两个接口的功能~~

a.signal

sighandler_t  signal ( int signum , sighandler_t handler );

signum 是我们要自定义的信号,handler 是 void ( * )( int ) 类型的回调函数,该回调函数的功能需要我们自主实现。当进程的代码执行到该系统调用接口后,此时,如果我们在向该进程发送 signum 信号的话,进程执行的就是 handler 函数中的代码~~

示例:

我们知道,当进程收到信号时,对信号的处理有三种方式:①忽略;②默认处理;③自定义捕捉

而 signal() 接口不仅可以实现信号的捕捉,它还能决定进程对信号的处理方式。当 signal() 第二个参数传递咱们自定义的函数时,signal() 执行的是自定义功能;当 signal() 第二个参数传递的是 SIG_IGN 时,表示信号忽略;当 signal() 第二个参数传递的是 SIG_IGN 时,表示执行信号的默认处理方法;

信号的忽略 —— signal( signum , SIG_IGN );

信号的默认处理 —— signal( signum , SIG_DFL );

信号的自定义捕捉 —— signal( signum , handler );

b.sigaction

int sigaction(int signum, const struct sigaction* act, struct sigaction* oact);

第一个参数 signum:指定要操作的信号编号,除了9号信号(SIGKILL)19号信号(SIGSTOP)之外,其他所有信号都可以被处理。

第二个参数 act:用于指定新的信号处理方式,与 signal 中第二个参数作用类似。

第三个参数 oact:拿到老的 act,即上一次信号的处理方法。

详解struct sigaction 结构体

struct sigaction

{  
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask; 
    int sa_flags; 
};

sa_handler:信号处理函数指针,与signal函数中的handler参数类似。

sa_sigaction:作用是存放上一次使用的 handler。

sa_mask:信号屏蔽集,指定在信号处理函数执行期间应被阻塞的信号。

c.实战演练

情景:当进程在执行某个信号时,再次收到该信号会如何处理?我们又该怎么用代码得到我们想要的答案?

答:当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么,它会被阻塞到当前处理结束为止。如果在调用信号处理函数时,除了当前信号被自动屏蔽外,还希望自动屏蔽另外一些信号,则用 sigset_t sa_mask 字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字

代码验证如下:

运行结果如下:

三.信号驱动回收子进程(附加篇)

SIGCHLD信号——基于“信号驱动”回收子进程。

在进程一章中讲过可以用 wait 和 waitpid 函数来解决僵尸进程问题. 其中,父进程可以阻塞等待子进程结束,也可以非阻塞轮询式查询子进程是否结束。若采用第一种方式,父进程阻塞了就不能执行自己的工作了;若采用第二种方式,父进程在执行自己任务的同时,还要记得时不时轮询式查询一下子进程的运行状态,程序实现较为复杂。

其实,子进程在终止时会给父进程发送 SIGCHLD 信号,该信号的默认处理方式是忽略。所以,父进程可以自定义 SIGCHLD 信号的处理函数,这样父进程只需专心处理自己的工作,不必关系子进程。当子进程终止时,会通知父进程,此时,父进程在信号处理函数中调用 wait 直接回收子进程即可。

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

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

相关文章

Stable Diffusion绘画 | 来训练属于自己的模型:打标处理与优化

上一篇完成的打标工作,是为了获取提示词,让AI认识和学习图片的特征。 因此,合适、恰当、无误的提示词,对最终模型效果是相当重要的。 Tag 如何优化 通过软件自动生成的 Tag 只是起到快速建立大体架构的作用,里面会涉…

2023年全国大学生数学建模竞赛C题——针对蔬菜类商品定价与补货决策的研究

摘要 本文针对生鲜超市中蔬菜类商品的补货和定价策略问题,建立时间序列预测模型,以及目标规划分析,从而让生鲜超市的收益达到最大。 针对问题一,首先对数据进行处理,对销售量异常值进行剔除、对缺失值补0 处理…

SOMEIP_ETS_150: SD_Send_triggerEventUINT8Multicast_Eventgroup_6

测试目的: 验证DUT在Tester订阅事件组后,能够响应Tester触发的triggerEventUINT8Multicast方法,并将TestEventUINT8Multicast事件发送到订阅请求中端点选项指定的IP地址和端口。 描述 本测试用例旨在确保DUT能够正确处理事件组的订阅请求&…

【nlp自然语言】知识图谱,全文检索,自然语言nlp,数据资产标签,集成管理平台

一、项目介绍 一款全源码,可二开,可基于云部署、私有部署的企业级知识库云平台,一款让企业知识变为实打实的数字财富的系统,应用在需要进行文档整理、分类、归集、检索、分析的场景。 为什么建立知识库平台? 助力企业…

基于SpringBoot+Vue+MySQL的旅游网站

系统展示 用户前台界面 管理员后台界面 系统背景 随着社会的不断发展和人们生活水平的提高,旅游活动逐渐成为人们生活中不可或缺的一部分。传统的旅游服务方式存在信息不对称、服务流程繁琐等问题。为了改善用户体验、提高服务效率,采用现代化的技术手段…

为什么说网站的可读性是引流量的重要环节

网站的可读性是指网站内容易于阅读和理解的程度。网站的可读性是引流量的重要环节,因为它直接影响到用户对网站内容的理解和吸收,进而影响用户的停留时间和转化率。以下是详细分析: 提升用户体验:网站的可读性好意味着用户可以更…

[uni-app]小兔鲜-06地址+sku+购物车

收址模块 准备 地址管理分包页面 和 添加地址分包页面 新增和修改地址 import type { AddressParams, AddressItem } from /types/address import { http } from /utils/http/*** 添加收货地址* param data 请求参数*/ export const postMemberAddressAPI (data: AddressPara…

Stable Diffusion绘画 | 插件-Deforum:动态视频生成(上篇)

Deforum 与 AnimateDiff 不太一样, AnimateDiff 是生成丝滑变化视频的,而 Deforum 的丝滑程度远远没有 AnimateDiff 好。 它是根据对比前面一帧的画面,然后不断生成新的相似图片,来组合成一个完整的视频。 Deforum 的优点在于可…

多模态系统中专家混合(MoE)复杂性的解读

引言 在迅速发展的人工智能领域,整合多种数据模态(如文本、图像、音频和传感器数据)是一个极具挑战性的任务。传统的单一模型AI系统通常难以应对同时处理多模态时产生的指数级复杂性。而这正是混合专家(Mixture of Experts&#…

如何正确拆分数据集?常见方法最全汇总

将数据集划分为训练集(Training)和测试集(Testing)是机器学习和统计建模中的重要步骤: 训练集(Training):一般来说 Train 训练集会进一步再分为 Train 训练集与 Validation 验证集两…

ElasticSearch备考 -- Update by query

一、题目 有个索引task,里面的文档长这样 现在需要添加一个字段all,这个字段的值是以下 a、b、c、d字段的值连在一起 二、思考 需要把四个字段拼接到一起,组成一个新的字段,这个就需要脚本, 这里有两种方案&#xff…

geodatatool(地图资源下载工具)3.8更新

geodatatool(地图资源下载工具)3.8(新)修复更新,修复更新包括: 1.高德POI数据按行政区划下载功能完善。 2.修正高德POI数据类型重复问题。 3.对高德KEY数据访问量超过最大限制时,提示错误并终止…

RK3568平台(显示篇)车机图像显示偏白问题分析

一.显示偏白图片对比 正常图像: 偏白图像: 二.分析过程

手把手教你使用Tensorflow2.7完成人脸识别系统,web人脸识别(Flask框架)+pyqt界面,保姆级教程

目录 前言一、系统总流程设计二、环境安装1. 创建虚拟环境2.安装其他库 三、模型搭建1.采集数据集2. 数据预处理3.构建模型和训练 五、摄像头测试六、web界面搭建与pyqt界面搭建报错了并解决的方法总结 前言 随着人工智能的不断发展,机器学习和深度学习这门技术也越…

YOLO11改进|注意力机制篇|引入注意力与卷积混合的ACmix

目录 一、ACmix注意力机制1.1ACmix注意力介绍1.2ACmix核心代码 二、添加ACmix注意力机制2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、ACmix注意力机制 1.1ACmix注意力介绍 ACmix设计为一个结合了卷积和自注意力机制优势的混合模块&am…

Redis: 集群测试和集群原理

集群测试 1 ) SET/GET 命令 测试 set 和 get 因为其他命令也基本相似,我们在 101 节点上尝试连接 103 $ /usr/local/redis/bin/redis-cli -c -a 123456 -h 192.168.10.103 -p 6376我们在插入或读取一个 key的时候,会对这个key做一个hash运算&#xff0c…

判断有向图是否为单连通图的算法

判断有向图是否为单连通图的算法 算法描述伪代码C语言实现解释在图论中,单连通图(singly connected graph)是指对于图中的任意两个顶点 m 和 v,如果存在从 m 到 v 的路径,则该路径是唯一的。为了判断一个有向图是否为单连通图,我们需要确保从任意顶点出发,到任意其他顶点…

开发能够抵御ICS对抗性攻击的边缘弹性机器学习集成

论文标题:《Development of an Edge Resilient ML Ensemble to Tolerate ICS Adversarial Attacks》 作者信息: Likai Yao, NSF Center for Cloud and Autonomic Computing, University of Arizona, Tucson, AZ 85721 USAQinxuan Shi, School of Elect…

【数据库差异研究】别名与表字段冲突,不同数据库在where中的处理行为

目录 ⚛️总结 ☪️1 问题描述 ☪️2 测试用例 ♋2.1 测试单层查询 ♏2.1.1 SQLITE数据库 ♐2.1.2 ORACLE数据库 ♑2.1.3 PG数据库 ♋2.2 测试嵌套查询 ♉2.2.1 SQLITE数据库 ♈2.2.2 ORACLE数据库 🔯2.2.3 PG数据库 ⚛️总结 单层查询 数据库类型别名…

字节终面问 Transformer,太难了。。。

最近已有不少大厂都在秋招宣讲了,也有一些在 Offer 发放阶段。 节前,我们邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对新手如何入门算法岗、该如何准备面试攻略、面试常考点、大模型技术趋势、算法项目落地经验分享等热门话题进行了…