目录
关于进程信号,其实我们可以通过三个步骤来理解
1.信号的产生
2.信号的捕捉
3.信号的处理
知识储备:
发送信号的本质是:修改目标进程pcb中的信号位图,讲0变为1。
这里写信号的产生
1.键盘
我们有些信号是可以通过键盘的快捷键进行发送的
如ctrl+c就是发送的二号信号,让进程终止
2.命令
如kill-9
这是唯一一个不能被注册信号函数的信号?
那什么是注册函数呢?其实就是将信号处理的方式从默认改成自定义。
介绍一个函数
第一个参数传的是信号编号,比如我们像重定义2号信号,就传2,第二个参数是自定义的函数的函数指针。
举个栗子:我们将二号信号注册一下,对应的键盘快捷键为ctrl+c
void signaled(int i)
{
cout<<"666"<<endl;
}
char arr[100];
int size=0;
int main()
{
signal(2,signaled);
test();
return 0;
}
这时候我们ctrl+c就会答应666了
!!当然九号信号是不允许注册的!!
3. 软件条件
alarm定时器
传入一个定时的时间,到时间之后会默认关闭进程,返回值是剩余的时间,怎么去理解呢?这其实是第二次过后再使用这个函数才会去得到的返回值,第二次吊用这个函数其实是重新去定一个时间,然后再返回上一次定时器剩余的时间。传0的化就是关闭定时器。
int main()
{
alarm(3);
sleep(1);
int tm=alarm(4);
cout<<tm<<end;
return 0;
}
剩余时间就为2了,这里其实当第一个定时器结束后就会关闭进程了。
我们那个孤雁到
4.系统调用
直接传发送的信号编号,这个不说了
5.异常
其实异常也是一种发送信号的途径。
我们来搞一个10/0;
int main()
{
int i=10/0;
return 0;
}
其实就是信号8
我们来看一个奇怪的现象,如果我们将8号信号进行重定义函数
void signaled(int i)
{
cout << "666" << endl;
sleep(1);
}
int main()
{
signal(8,signaled);
int i=10/0;
return 0;
}
他就会死循环打印666这是为什么呢?
当cup执行10/0时,自己会判断被除数不能为0,然后再将状态寄存器上的对应比特位进行标记,然后cup就会告诉操作系统,op发送信号将进程的pcb中对应的信号位图上八号进行标记,再执行信号的函数,应为我们重新注册了函数,执行完了函数并不会退出,当再在cpu执行代码时,由于cpu保存了上下文,所以他的状态寄存器上一直标有1,所以会继续告诉操作系统,从此循环。
所以就会导致死循环。
补充知识:
1.上面信号的产生都必须由操作系统来执行,因为
2.信号不是立即处理。
3.信号如果不立即处理,他会保存在进程pcb信号位图中。
4.进程如果收到信号,如果不做处理会执行默认方法,如果进行注册则执行自己设置的方法,当然也可以忽略信号。
5.发信号其实是写信号,会讲进程pcb信号位图上的对应位置改为1。
core VS term
退出进程一般有两种core和term
core是一个文件,用来我们对代码进行调试的,如果以core退出,就是说明代码是有错误的相应的会将错误信息保存到core文件当中。方便我们调试,云服务器默认没有打开这个文件的,
ulimit -a就可以查看我们文件是否打开
但是我们进程怎么知道该不该写如信息呢?
其实我们之前就见过,只是没讲而已,我们waitpid就有一个status,来标记是否打开了core文件。
int main()
{
int id=fork();
if(id==0)
{
int a=10/0;
exit(1);
}
else
{
int statu;
waitpid(id,&statu,0);
cout<<"dump core: "<<((statu>>7)&1)<<endl;
}
return 0;
}
通过这样的代码就能查看到是否打开dump core,当然是没打开的怎么打开呢?
我们需要去设置一个大小:
ulimit -c 1024 //设置大小
这样就好了再次执行代码
再生成一个core文件,这个文件怎么用呢?其实是调试的时候用。
我们再gdb中core-file就行了。