一、信号的初认识
查看信号类型
kill -l
程序运行的时候键盘按下CTRL + C程序停止,本质是向进程发送了2号信号(SIGINT)。
信号的产生方式其中一种就是通过键盘产生,但键盘产生的信号只能用来终止前台进程。
一般进程收到信号的处理方案有三种:
1.默认动作 :一部分是终止自己、暂停等
2.忽略动作:是一种信号处理的方式,只不过什么也没干
3.自定义动作:我们上面例子所用的signal方法,就是在修改信号的处理动作(信号的捕捉)
注:9号信号不可以自定义
Linux下对不可访问的区域进行访问时会出现段错误,导致程序的崩溃。程序为什么会崩溃呢?
原因:程序在运行的过程中因为出现了段错误收到了11号信号。
在Windows or Linux进程崩溃的本质,是进程收到了对应的信号,然后进程执行信号的默认处理动作(杀死进程)。
为什么可以收到信号呢?
软件上的错误,通常会体现在硬件或者其他软件上。而OS是硬件的管理者,OS对硬件的异常进行识别负责。OS找寻到引起异常的进程并发送相关信号终止进程。
例如:C++/Python中的捕捉异常(try---catch),实际上是对信号的处理,对底层进行了封装。
当进程崩溃的时候,我们最想知道什么? 崩溃的原因
在进程学习的过程中我们了解了waitpid(),参数status中描述了进程崩溃的原因,收到的是什么信号。我们除了知道崩溃外,还想知道崩溃的具体位置,在哪一行崩溃。
在Linux中,当一个进程退出的时候,他的退出码和退出信号都会被设置(正常)。当一个进程异常的时候,进程的退出信号会被设置,表明当前进程退出的原因。
如果必要,OS会设置退出信息中的core dump标志位,并将进程在内存中的数据转储到磁盘上,方便我们后期调试。
进程 status:
进程如果异常的时候,被core dump该位置会被设置为1。但不是所有的信号都有core dump。
二、core dump的使用
注:云服务器上core dump是被关掉的
ulimit -c 10240 //允许进行core dump
使用gbd进行查看异常
gcc -o mytest test.c -g //运行gdb调试
gdb mytest
三、信号的产生
信号产生的方式:
1.通过键盘产生,键盘产生的信号只能用来终止前台进程。
2.程序中存在异常问题,导致我们收到信号退出。
3.通过系统调用产生信号。
1.通过终端按键产生信号
2.调用系统函数向进程发送信号
#include <signal.h>
int kill(pid_t pid, int signo); //发信号给别人
int raise(int signo); //发信号给自己
//这两个函数都是成功返回0,错误返回-1。
void abort(void); //像exit函数一样,没有返回值
3.由软件条件产生信号
SIGPIPE是一种由软件条件产生的信号,在“管道”中已经介绍过了。介绍alarm函数和SIGALRM信号。
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
//调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。
这个程序的作用是1秒钟之内不停地数数,1秒钟到了就被SIGALRM信号终止。
4.硬件异常产生信号
硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除 以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。