1. 什么是信号
信号本质是一种通知机制,用户or操作系统通过发送信号通知进程,进程进行后续处理
在日常生活中就有很多例子,比如打游戏方面王者荣耀的“进攻”,“撤退”,“请求集合”,“干得漂亮!”.......这些就是信号,用来通知队友,传递某种信息,并采取行动。
信号主要具有以下特点:
- 进程必须具有 “识别” 的能力(认识+后续动作)
- 进程能够 “识别” 是程序员赋予的
- 信号的产生是随机的,可能在任意时间
- 信号被识别后可能不会立即处理
- 进程会临时记录信号,方便后续处理
- 至于在什么时候处理,合适的时候(还在写)
- 信号的产生相对于进程是异步的
2. 信号怎么产生的
信号的产生方式有四种:
- 键盘(ctrl+c)
- 系统调用接口(kill命令)
- 软件异常(闹钟)
- 硬件异常(除0错误,野指针)
或是命令或是异常错误,最终都是由OS接收到这些指令或者识别到某些错误,进而向进程PCB(task_struct)发送信号
kill -l
查看信号的种类
Linux一共有62种信号(没有32,33),其中 [1, 31] 是普通信号,[33, 64] 是实时信号,这里主要介绍普通信号
(这一块具体内容放在下一篇博客)
3. 信号处理方式
信号的处理方式有以下三种:
- 默认(进程自带,程序员写好了)
- 忽略
- 自定义捕捉
其中在< signal.h >头文件下定义了以SIG开头的一系列宏,对应信号的编号
并且typedef了一个函数指针类型sighandler参数为int返回值为void
分别对应着错误,默认,和忽略
signal函数介绍:
函数作用:
自定义信号处理方式,以达到信号捕捉。通过函数回调的方式,修改对应的信号的处理动作。
参数:
signum,修改的信号编号,可以传SIGINT,也可以传2
handler,函数的地址,实现一个函数,作为信号的处理动作
void handler(int args);调用时signum会作为args传入
返回值:不重要
当一个信号的处理方式是默认,那么信号会根据下面这张表格处理
Team | 终止 |
Ign | 忽略 |
Core | 终止 + 核心转储 |
Stop | 暂停 |
Cont | 继续 |
当一个信号的处理方式是忽略,则什么都不会发生
当一个信号的处理方式是自定义,会按照自定义的方式执行自定义的函数(如signal函数的handler)
拓展:
Core Dump(核心转储):当进程出现某种异常,OS会把进程在内存中的核心相关数据转存到磁盘上,在当前目录下生成core.pid的文件。目的是为了方便调试。
在我们之前的学习中,父进程等待子进程退出,status中
标志位为1标识发生核心转储,反之没有
如何利用core文件调试:
- 条件:当前生产环境打开core dump功能,并且程序在编译时-g了(Debug模式),进程发生了核心转储
- gdb 运行
- core-file core.pid(core文件)
就可以定位到出错位置
注意:一般而言,在云服务器上,core dump一般是关闭的,因为如果一直核心转储会消耗大量空间,打开只需要, ulimit -a 查看 ; ulimit -c 10240(你认为合适的大小)0 是关闭
4. 信号的发送的本质
进程如何保存信号,其实在进程PCB(task_struct)中有一个位图(Bitmap)来标识信号是否产生,如果产生就标1,没有就标0
(关于信号保存,会在后面的博客具体谈)
信号发送的本质就是,OS向目标进程写信号,修改PCB中的指定位图结构
完