文章目录
- 前言
- 信号的初步认识
-
- 捕获信号的办法
- 键盘数据输入给内核的原理
- core dump
- 信号的产生
-
- 系统调用
- 异常
- 软件条件
- 信号的发送
- 信号的保存
前言
在 Linux 系统中,进程信号是一套高效的 “异步通信机制”—— 它如同给进程发送的 “通知”,能够打断进程的正常执行流程,触发预设的处理动作。小到ctrl+c终止前台进程,大到异常崩溃时的核心转储(core dump)、进程间的紧急通知,信号贯穿了 Linux 进程管理的方方面面。
信号的本质是内核向进程传递事件的 “软件中断”,其生命周期涵盖 “产生→发送→保存→递达→处理” 五大环节,背后依赖block(阻塞)、pending(未决)、handler(处理函数)三张核心表的协同工作。本文将从基础认知出发,层层拆解进程信号的核心逻辑:先讲信号的三种处理方式、前台 / 后台进程与信号的关联,再深入信号捕获的signal系统调用、键盘输入触发信号的底层原理;随后详解信号的五种产生途径(键盘、命令、系统调用、异常、软件条件),并剖析内核中信号的保存机制与阻塞 / 未决状态的核心概念;最后结合core dump调试、信号位图管理等实操技巧,帮读者打通 “理论原理” 与 “实际应用” 的壁垒。
无论你是刚接触 Linux 进程编程的新手,还是想深入理解内核信号机制的开发者,都能通过本文掌握信号的核心知识点 —— 包括不可捕获 / 阻塞的 9 号(SIGKILL)与 19 号(SIGSTOP)信号、原子操作的信号位图、alarm闹钟信号等关键细节,轻松应对进程中断、异常处理、进程间简单通信等实际开发场景。
信号的初步认识
1.进程必须要能识别和处理信号–就算这个信号没有被产生,进程也需要具备处理这个信号的能力
–对信号的处理能力,属于进程的内置功能
2.进程没有收到信号,也能知道这些信号的处理方法是什么
3.当进程真的收到了信号,进程可能不会立马处理这个信号,而是等到合适的时候处理
4.进程具有临时保存哪些信号发生了的能力
–因为信号产生到信号被处理之间会有时间窗口
信号的处理方式有三种:(只能三选一哈)
1.默认动作 2.忽略 3.自定义动作(比如:捕捉这个信号)
在Linux中,一次登陆就会有一个终端,一个终端一般只有一个bash;一个bash的话就只允许一个进程是前台进程,但是可以有多个进程是后台进程
这样的话算两次登录哈
把进程搞成后台运行的方法:最后加个& eg:./a.out &
注意:只有前台进程才能获取键盘输入 –前台进程搞成其他了的话,bash就用不了了
但是前台和后台进程都能显示到显示器上哈
ctrl+c只能杀掉前台进程,不能杀后台进程
捕获信号的办法

1到31的信号称为普通信号(掌握这些就就行了)
后面的称为实时信号
eg:SIGHUP这些是宏,其实就是1
想要知道这些信号是干啥用的:man 7 signal可以查询eg:信号的默认处理动作

这个系统调用接口可以用来捕捉信号–程序里只需要设置一次,往后都有效(但是进程结束了也就没了哈)
这里面的handler是用来修改特定进程对于信号的处理动作的,也可以设置成eg:SIG_IGN这样的(这是信号处理动作的宏定义)
信号处理动作的宏定义:
1.SIG_IGN:忽略该信号
2.SIG_DFL:使用系统默认的信号处理动作
–也就是用来改当前进程的handler表
使用方法:
void myhandler(int signo) signo是读取到的信号的编号
{....里面可以对这个东西做处理}
signal(SIGINT,myhandler)//写成signal(2,myhandler)是一样的
注意:不是所有信号都能被signal捕捉到的,在普通信号里面9和19是不行的
键盘数据输入给内核的原理
键盘上有按键输入时会产生硬件中断(通过中断号和中断单元通知CPU),CPU通过中断向量表找到处理问题的方法,然后OS就会接管并执行对应的处理中断的程序
这个中断向量表是OS维护的哈,里面存的是处理中断的那些方法的地址
执行中断的程序:比如:ctrl+c这种特殊组合键,就被OS处理成了信号
普通按键的话就被搞入系统缓冲区,然后给用户缓冲区…..
直接访问外设的方式,主要是磁盘,显示器,键盘
CPU保存数据的原理:给寄存器的针脚发送高低电平信号
信号其实就是用软件方式,对进程模拟的硬件中断(但不是真的硬件中断哈)
引申:键盘回显到显示器,如果显示器上还要其他数据显示,是不会打乱输入的:
因为键盘的输入是存在自己的缓冲区里面的,只是把这部分数据拷贝了一份给显示器的缓冲区而已
不同的文件会使用不同的缓冲区
core dump
core dump:核心转储
用法:开启gdb调试器之后,core-file core.pid文件 ,然后就会给出出错行是哪个以及报错的信息
SIGINT和SIGQUIT的区别就是SIGQUIT除了终止进程,还会core dump
一个进程异常终止时,如果信号的Action是Core的话,OS会将进程在内存中的运行信息转储到进程的当前目录(和进程同一级哈)里面形成core.pid文件 比如core.30238
是core的话,进程状态那个core dump那个位置就是1
在默认情况下,云服务器的core功能是关闭的–害怕挂起之后又运行,这样就会产生很多个core.pid文件,这个文件的大小又很大
一些相关的指令:
ulimit -a:列出当前用户所有的进程资源限制配置(比如:核心转储文件大小的限制)
ulimit -c:显示核心转储文件大小的限制
ulimit -c m:把核心转储文件大小的限制改成m(比如1024)–改成非0的,也就开启了core功能
信号的产生
信号的产生和代码的运行是异步的
也就是说,信号可以在代码执行的任何时刻产生
信号的产生常见的方法有五种:
1.键盘组合键 eg:ctrl+c 产生的就是2号信号
2.kill命令 kill 信号的号数(比如2) 给哪个进程(填pid)
3.系统调用
4.异常
5.软件条件
系统调用
主要有kill raise abort
kill:

sig就是要填几号信号
返回值:成功返回0,失败返回-1
raise:这个的话是对调用者(当前进程)发信号

返回值:成功返回0,失败返回非0值
abort:

这个的话是给当前进程发送SIGABRT信号(也就是6号信号)
但是这个跟直接给这个进程发送6号信号有点不一样
调用了abort的话,这个信号被捕获了之后,程序还是会被终止(kill raise不行哈)
异常
比如:野指针时会让进程崩溃–因为产生了段错误,发送了11号信号
–这种的如果用signal改了行为的话,就会一直发送11号信号
如果此时进程不崩溃的话,这个进程就一直会被调度运行–但是一调度就会被挂起(因为一直出问题)
–也就是出异常了,操作系统不会直接把这个进程给干掉
这是OS给进程发送的信号
–过程:CPU里面存的是虚拟地址,然后交给MMU(内存管理单元)转换成物理地址;但是比如野指针就会导致地址转换失败,触发硬件异常,然后OS就知道有问题了,就会…
引申:1.OS是硬件的管理者
2.进程对CPU寄存器的修改操作,只会影响自身进程–因为进程的上下文机制
3.现在MMU一般在CPU内部
异常不是只有硬件会产生,软件也是会的
比如:管道的读端关闭了,写端还在继续写,这个时候就会异常
软件条件
比如:闹钟alarm
闹钟不是异常,是系统层面的一种软件条件
alarm:时间到了会发送14号信号

seconds:想多少秒之后触发就写多少
返回值:返回的是上一次的闹钟还有多久触发(已经触发了的话,返回的是0)
闹钟是设置多少次就响多少次–跟signal区分
信号的发送
对于普通信号,进程会记录有没有收到信号,收到的是哪种信号
用的是位图去管理(接收到这个信号,就那个位置变为1)–相同的多个信号还没被处理的话,最后也就被处理一次
如果是实时信号的话,需要立即处理,而且接收到几次就要处理几次
这里的发送信号,本质是OS去修改task_struct的信号位图对应的比特位
–因为OS是进程的管理者,只有它有资格去修改task_struct内部的属性
信号的保存
为什么需要保存信号?–信号被进程接受后,并不一定立即处理,这时就需要有一个时间窗口

信号是几号,那它对应的block pending handler下标就是几
block里面为1,表示信号被阻塞
pending里面为1,表示信号未决
handler里面存的是处理方法的地址
信号保存的话,要保存它的block状态 pending状态
block(阻塞,也叫屏蔽):被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作 —信号还没产生,就可以先把这个信号block了
–9号信号SIGKILL和19号信号SIGSTOP不能被阻塞
pending(信号未决):信号从产生到递达之间的状态
信号递达:实际执行信号的处理动作
对于1-31号的信号pending的位图,多久从1变成0:
在执行信号捕捉方法之前变 是先清0,再调用信号捕捉函数
网硕互联帮助中心


评论前必须登录!
注册