运行结果小伙伴们自己下去运行一下吧~这里就不截图了
MMU产生异常: 当进程访问非法地址时,mmu想通过页表映射来将虚拟转换为物理地址,此时发现页表中不存在该虚拟地址,此时会产生异常,然后OS将异常解释为SIGSEGV信号,然后发送给进程
#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>int main(){// MMU硬件产生异常,内核将这个异常处理为SIGSEGV信号发送给进程signal(11, handler);int* p = NULL;printf("%d\n", *p);return 0;}
signal函数实现信号的捕捉#include<signal.h>typedef void(*sighandler_t)(int);//它定义了一个类型sighandler_t,表示指向返回值为void型(参数为int型)的函数(的)指针sighandler_t signal(int signum,sighandler_t handler);功能:注册信号处理函数(不可用于SIGKILL、SIGSTOP信号),即确定收到信号后处理函数的入口地址 。此函数不会阻塞 。参数:signum:信号的编号,这里可以填数字编号,也可以填信号的宏义 。handler:取值有3种情况:SIG_IGN:忽略该信号SIG_DFL:执行系统默认动作信号处理函数名:自定义信号处理函数,如:func回调函数的定义如下:void func(int signo){//signo为触发的信号,为signal()第一个参数的值}返回值:成功:第一次返回NULL,下一次返回此信号上一次注册的信号处理函数的地址 。如果需要使用此返回值,必须在前面先声明此函数指针的类型 。失败:返回SIG_ERR
代码示例:
#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>//信号处理函数void fun1(int signum){printf("捕捉到信号:%d\n",signum);}//信号处理函数2void fun2(int signum){printf("捕捉到信号:%d\n",signum);}//信号注册函数int main(){//信号注册//ctrl+csignal(SIGINT,fun1);//ctrl+\signal(SIGQUIT,fun2);while(1){sleep(1);}return 0;}
运行结果如下:

文章插图
信号先注册,进程不要退出,然后等待信号的到达,信号到达之后就会执行信号处理函数 。
阻塞信号了解几个概念:
- 实际执行信号的处理动作称为信号递达
- 信号递达的三种方式:默认、忽略和自定义捕捉
- 信号从产生到递达之间的状态,称为信号未决(Pending)
- 进程可以选择阻塞 (Block )某个信号
- 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作
注意:
- 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作
- OS发生信号给一个进程,此信号不是立即被处理的,那么这个时间窗口中,信号就需要被记录保存下来,那么信号是如何在内核中保存和表示的呢?

文章插图
每个进程都存在一个PCB,在PCB中存在两个集合,一个是未决信号集,一个是阻塞信号集 。
以SIGINT为例说明未决信号集和阻塞信号集的关系:
- 当进程收到SIGINT信号(信号编号为2),首先这个信号会保存在未决信号集合中,此时对应的2号编号的这个位置上置为1,表示处于未决状态;在这个信号需要被处理之前首先要在阻塞信号集中的编号2的位置上区检查该值是否为1
- 如果是1,表示SIGINT信号被当前进程阻塞了,这个信号暂时不被处理,所以未决集上该位置上的值保持为1,表示该信号处于未决状态
- 如果是0,表示SIGINT信号没有被当前进程阻塞,这个信号需要被处理,内核会对SIGINT信号进行处理(执行默认动作,忽略或者执行用户自定义的信号处理函数),并将未决信号集合中编号2的位置将1置为0,表示该信号已经被处理了,这个时间非常短
经验总结扩展阅读
- 十二星座女生爱情的出发点是什么?
- 黑豆泡一晚上第二天煮可以吗
- 十二星座女没有那么喜欢你的一些行为
- 吃不完的白灼虾第二次怎么搞
- 二瓶啤酒要过多久才能不被测出来
- too同义词|too的同义词
- 2022年农历十一月十二适合乔迁吗
- 二 SpringCloud - Eureka注册中心,feign远程调用,hystrix降级和熔断
- 2022年腊月初二是阳历几月几号
- 2022年腊月初二日子吉利吗