异常控制流
8.1 异常
异常就是控制流中的突变,用来响应处理器状态中的某些变化
8.1.1 异常处理
系统收到异常信号后,会将现在的指令暂存,然后去异常表找该异常对应的处理方式,执行完毕后,再看情况返回之前的指令
8.1.2 异常的类别
中断
:收到外部I/O设备的异常信号,然后处理,返回
陷阱和系统调用
:陷阱是有意的异常,是执行一条指令的结果。内核服务的调用就是通过通过一个跳转表来处理
故障
:根据故障是否能够修复,要么重新执行引起故障的指令,要么终止
终止
:abort,终止程序运行
8.1.3 Linux/x86-64系统的异常
介绍各种异常
8.2 进程
进程:一个执行中程序的实例
- 一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占地使用处理器
- 一个私有的地址空间,它提供一个假象,好像我们的程序独占的使用内存系统
8.3 系统调用错误处理
就是告诉你要处理errorcode
8.4 进程控制
父进程跟子进程有相同的用户栈,本地变量,全部变量以及相同的代码。但是他们确实相互独立的进程,有自己的私有地址空间,所以,子进程里面对值的修改,不会影响到父进程
8.5 信号
就是我们说的各种异常信号了。 通常是内核检测到错误给进程发送错误信号。当然,程序也可以显示的要求内核发送一个信号给目标进程,例如:kill,abort
1
2
3
所以,我们iOS中抓崩溃会用signal,其实就捕获信号,并进行处理:
sighandler_t signal(int signum,sighandler_t handler);
然后上面是signal的,属于内核异常,还有些先被系统捕获但没处理的异常,就需要用到:NSSetUncaughtExceptionHandler了
收到信号
:同一种信号如果发现前面有相同类型的信号待处理,那么后面的信号就会直接抛弃,程序就收不到这个信号了
信号处理
:因为信号的上述特征,所以,我们可能需要阻塞信号,来防止漏掉信号(例如进程被结束后,内核发信号让父进程回收,但是回收过程中另外一个子进程也结束了,这个时候,因为是同一种信号,所以会被忽略,从而导致进程没被回收,成为了僵尸进程)
8.6 非本地跳转
setjmp:保存当前的环境 longjmp:跳转到之前保存的环境。 大致就是不通过流程,直接通过保存的环境做跳转. 可以随意跳转,例如,下面代码的输出为’save jmp buf success\n save jmp buf success\n r == 1’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <setjmp.h>
jmp_buf buf;
void fun1(void){
longjmp(buf,1);
}
int main()
{
int r;
r = setjmp(buf); //保存环境
printf("save jmp buf success\n"); //输出
if (r == 0) {
fun1(); //执行跳转,回到上面保存环境的步骤,然后重新又输出了一边save jmp
} else if (r == 1) {
printf("r == 1\n");
}
return 0;
}
--EOF--
若无特别说明,本站文章均为原创,转载请保留链接,谢谢