行业知识
Linux信号【产生-保存-处理】
���录
前言:
1、进程信号基本概念
1.1、什么是信号?
1.2、信号的作用
2、键盘键入
2.1、ctrl+c 终止前台进程
2.1.1、signal 注册执行动作
3、系统调用
3.1、kill 函数
3.2、模拟实现 myKill
3.3、raise 函数
3.4、abort 函数
4、软件条件信号产生(发送)的第三种方式:软件条件
4.1、alarm 设置闹钟
5、硬件异常
5.1、除 0 导致异常
5.2、状态寄存器
5.3、野指针导致异常
6.核心转储
6.2、打开与关闭核心转储
6.3、核心转储的作用
总结:
前言:
在 Linux 中,进程具有独立性,进程在运行后可能 “放飞自我”,这是不利于管理的,于是需要一种约定俗成的方式来控制进程的运行,这就是 进程信号,本文将会从什么是进程信号开篇,讲述各种进程信号的产生方式及作用
正文:
1、进程信号基本概念
1.1、什么是信号?
信号 是信息传递的承载方式,一种信号往往代表着一种执行动作,比如:
- 鸡叫 => 天快亮了
- 闹钟 => 起床、完成任务
- 红绿灯 => 红灯停,绿灯行
当然这些都是生活中的 信号,当产生这些 信号 时,我们会立马想到对应的 动作 ,这是因为 我们认识并能处理这些信号
我们能进行处理是因为受过教育,学习了执行动作,但对进程来说,它可没有接受过九年义务教育,也不知道什么时候该干什么事
于是程序员们给操作系统植入了一批 指令,一个指令表示一种特殊动作,而这些指令就是 信号(进程信号)
kill -l
这些就是当前系统中的 进程信号,一共 62 个,其中 1~31 号信号为 普通信号(学习目标),用于 分时操作系统;剩下的 34~64 号信号为 实时信号,用于 实时操作系统
- 分时操作系统:根据时间片实行公平调度,适用于个人电脑
- 实时操作系统:高响应,适合任务较少、需要快速处理的平台,比如汽车车机、火箭发射控制台
1.2、信号的作用
早在 《Linux进程学习【进程状态】》 我们就已经使用过 信号 了,比如:
- kill -9 pid 终止进程运行
- kill -19 pid 暂停进程运行
- kill -18 pid 恢复进程运行
就连常用的 ctrl+c 和 ctrl+d 热键本质上也是 信号
这么多信号,其对应功能是什么呢?
- 可以通过 man 7 signal 进行查询
man 7 signal
简单总结一下,1~31 号信号对应的功能如下(表格内容引用自 2021dragon Linux中的31个普通信号)
注意: 其中的 9 号 和 19 号信号是非常特殊的,不能修改其默认动作
1.3、信号的基本认知
进程信号由 信号编号 + 执行动作 构成,一个信号对应一种动作,对于进程来说,动作无非就这几种:终止进程、暂停进程、恢复进程,3 个信号就够用了啊,为什么要搞这么多信号?
- 创造信号的目的不只是控制进程,还要便于管理进程,进程的终止原因有很多种,如果一概而论的话,对于问题分析是非常不友好的,所以才会将信号细分化,搞出这么多信号,目的就是为了方便定位、分析、解决问题
- 并且 普通信号 就 31 个,这就是意味着所有普通信号都可以存储在一个 int 中,表示是否收到该信号(信号的保存)
所以信号被细化了,不同的信号对应不同的执行动作,虽然大部分最终都是终止进程
进程的执行动作是可修改的,默认为系统预设的 默认动作
- 默认动作
- 忽略
- 自定义动作
所以我们可以 更改信号的执行动作(后面会专门讲信号处理相关内容)
信号有这么多个,并且多个进程可以同时产生多个信号,操作系统为了管理,先描述、再组织,在 PCB 中增加了 信号相关的数据结构:signal_struct,在这个结构体中,必然存在一个 位图结构 uint32_t signals 存储 1~31 号信号的有无信息
//信号结构体源码(部分)struct signal_struct {atomic_tsigcnt;atomic_tlive;intnr_threads;wait_queue_head_twait_chldexit;/* for wait4() *//* current thread group signal load-balancing target: */struct task_struct*curr_target;/* shared signal handling: */struct sigpendingshared_pending;/* thread group exit support */intgroup_exit_code;/* overloaded: * - notify group_exit_task when ->count is equal to notify_count * - everyone except group_exit_task is stopped during signal delivery * of fatal signals, group_exit_task processes the signal. */intnotify_count;struct task_struct*group_exit_task;/* thread group stop support, overloads group_exit_code too */intgroup_stop_count;unsigned intflags; /* see SIGNAL_* flags below *//* * PR_SET_CHILD_SUBREAPER marks a process, like a service * manager, to re-parent orphan (double-forking) child processes * to this process instead of 'init'. The service manager is * able to receive SIGCHLD signals and is able to investigate * the process until it calls wait(). All children of this * process will inherit a flag if they should look for a * child_subreaper process at exit. */unsigned intis_child_subreaper:1;unsigned inthas_child_subreaper:1;//……};1.信号是执行的动作的信息载体,程序员在设计进程的时候,早就已经设计了其对信号的识别能力
2.信号对于进程来说是异步的,随时可能产生,如果信号产生时,进程在处理优先级更高的事情,那么信号就不能被立即处理,此时进程需要保存信号,后续再处理
3.进程可以将 多个信号 或 还未处理 的信号存储在 signal_struct 这个结构体中,具体信号编号,存储在 uint32_t signals 这个位图结构中
4.所谓的 “发送” 信号,其实就是写入信号,修改进程中位图结构中对应的比特位,由 0 置为 1,表示该信号产生了
5.signal_struct 属于内核数据结构,只能由 操作系统 进行同一修改,无论信号是如何产生的,最终都需要借助 操作系统 进行发送
6.信号并不是立即处理的,它会在合适的时间段进行统一处理
本文讲解的就是 信号产生 部分相关知识,下面正式开始学习 信号产生
2、键盘键入
信号产生(发送)的第一种方式:键盘键入
通俗来说就是命令行操作
2.1、ctrl+c 终止前台进程
系统卡***遇到过吧?程序***循环遇到过吧?这些都是比较常见的问题,当发生这些问题时,我们可以通过 键盘键入 ctrl + c 发出 2号信号终止前台进程的运行
下面是一段***循环代码:
#include #include using namespace std;int main(){ while(true) { cout
- 可以通过 man 7 signal 进行查询