Linux信号的产生
Linux系列一、信号的产生
上篇文章我们已经介绍了信号的三种产生方式,这部分是对上篇文章的增补
1.1 异常
在编写程序时,我们的程序经常会出现如:除零错误、野指针错误,导致进程崩溃,而进场崩溃的根本缘故原由就是因为OS向我们的进程发送了信号,下面我们通过两个例子详细分析:
例一
#include<iostream>
using namespace std;
int main()
{
int a=10;
int b=0;
int c=a/b;
cout<<"sucess!!!"<<endl;
return 0;
}
https://i-blog.csdnimg.cn/direct/31968ffd87c6414d84ff773144b95e28.png
可以看到当程序发生除零错误后,直接崩溃不会再执行下面代码。
https://i-blog.csdnimg.cn/direct/faa7ec473a2f4ffb9e478717534d1032.png
上图信息通过:man 7 signal 查找得到
从上图可以看出进程是接受到八号信号,而退出的,下面我们通过捕获来验证:
#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
void handler(int numsig)
{
cout<<"I capture a signal:"<<numsig<<endl;
sleep(1);
return ;
}
int main()
{
signal(8,handler);
int a=10;
int b=0;
int c=a/b;
return 0;
}
https://i-blog.csdnimg.cn/direct/2504ee1d1df44a30b82557b0c9c165e6.png
我们能看到进程确实收到了8号信号,但是我们并没有写循环为什么handler方法不绝被执行呢?OS又是如何判断要给进程发送8号信号的?
https://i-blog.csdnimg.cn/direct/a94287a6e7b04008bf05357d73a840d2.png
在CPU中存在很多寄存器,当CPU执行程序,执行到除零运算时,状态寄存器的溢出标志位被置位(1),CPU发生硬件中断产生中断号,被OS识别,操纵系统根据中断向量表给进程发送信号,信号被进程捕获执行我们自己的方法,执行完毕返回进程并没有被退出,进程继承被调度,但是进程上下文数据并没有修改,溢出标志位不绝为1,OS 不绝发送信号…,如许就体现为handler方法不绝被调度。
例二
#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
// void handler(int numsig)
// {
// cout<<"I capture a signal:"<<numsig<<endl;
// sleep(1);
// return ;
// }
int main()
{
//signal(8,handler);
int *p=nullptr;//野指针
*p=2;
return 0;
}
https://i-blog.csdnimg.cn/direct/2019502f41b84870a1b8136a7d93c585.png
当进程发生野指针错误时,进程也会直接崩溃,此时进程接收到的是11号信号,你可以自己查察这里就不展示了。
https://i-blog.csdnimg.cn/direct/3c6964e768134a8182999e11cea44acb.png
当你对该信号捕获执行自定义方法,假如不退出进程,效果依然体现为handler方法不绝被调用。
https://i-blog.csdnimg.cn/direct/94ab584e8b03443d889eea3335406841.png
当我们内存访问时,CPU中存在存在一个MMU内存管理单元,资助我们把虚拟地址转化为物理地址,当转化失败(对该内存没有权限、不存在等)时,就会将转化失败的虚拟内存地址存放到CPU寄存器中,OS检测到后给进程发送信号。我们对于异常的处理,一般都为终止进程,并不会实验修复它,而这些异常信号可以被捕获,是OS方便用户对数据举行处理(保存、日志等)的。
上面的两个例子都是由硬件产生的,但是异常还可以由软件产生,这点我在管道部分介绍过了,下面会直接用作示例来介绍新的知识。
1.2 alarm()系统调用
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:设定一个定时器,在指定的秒数后向进程发送SIGALRM信号。
参数
[*]seconds:假如不为0在颠末seconds秒后,进程会收到SIGALRM信号。假如在定时器到期之前再次调用alarm函数,会重新设置定时器,之前剩余的时间被忽略,假如为0,定时器被取消,之前设置的任何未到期的定时器都会被清除,且不会发送信号。
返回值
[*]返回上一次设置定时器的剩余秒数,假如之前设置的定时器已经逾期返回0.
示例:
#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
void work()
{
cout<<"起床了!!!"<<endl;
}
void handler(int numsig)
{
work();//执行闹钟任务
return ;
}
int main()
{
signal(SIGALRM,handler);//捕捉信号,执行自定义任务
alarm(5);//5秒后给进程发送SIGALRM信号
int cnt=0;
while(1)
{
cout<<cnt++<<endl;
sleep(1);
}
return 0;
}
https://i-blog.csdnimg.cn/direct/30b06ac9eaf54cc38df18084b681f359.png
可以看到当我们的程序设置闹钟后,就可以通过捕获信号,完成指定任务的执行行,这种方式我们一般用来格一段时间,来打印一次日志信息。
这个别看:闹钟什么时候触发依赖于时间戳,对闹钟举行管理。。填充闹钟结构体属性。。。管理闹钟结构体。。系统维护当前时间。。。对比是否超时。。。堆结构,进步比较效率。。。。
二 、信号的默认行为
https://i-blog.csdnimg.cn/direct/d0e7d36b758347799a9da182d5228259.png
[*] Term:表示该信号的默认行为是终止进程。
[*] Core:意味着信号触发时,进程在终止的同时,会产生核心转储(Core Dump)文件,用于后续调试分析。
在我们介绍进程控制时,就遇到过了这个问题:
https://i-blog.csdnimg.cn/direct/61dd0b0eceaf4fd0a15e2ebf573cddaa.png
下面我们来实验获取这个标志,另外我们必要先将服务器Core 权限打开
https://i-blog.csdnimg.cn/direct/cb14f75259a049118d440ee19d6fa882.png
https://i-blog.csdnimg.cn/direct/30443deceee8471dba70dc9f8183ceb8.png
背面就必要根据你自己的系统设置了,大家可以结合自己的系统搜刮以下,我们直接跳入利用部分:
https://i-blog.csdnimg.cn/direct/131955aa7cb64773adf20b0a01f6492c.png
如许我们就可以直接利用,天生的转储文件,结合gdb调试工具,对错误信息举行,快速定位了。这种调试方法我们称为事后调试。
本篇内容比较乱,主要是用来总结、整合前面的知识的。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]