异常控制流

8.1 异常

异常就是控制流中的突变,用来响应处理器状态中的某些变化

8.1.1 异常处理

系统收到异常信号后,会将现在的指令暂存,然后去异常表找该异常对应的处理方式,执行完毕后,再看情况返回之前的指令

8.1.2 异常的类别

中断:收到外部I/O设备的异常信号,然后处理,返回 陷阱和系统调用:陷阱是有意的异常,是执行一条指令的结果。内核服务的调用就是通过通过一个跳转表来处理 故障:根据故障是否能够修复,要么重新执行引起故障的指令,要么终止 终止:abort,终止程序运行

8.1.3 Linux/x86-64系统的异常

介绍各种异常

8.2 进程

进程:一个执行中程序的实例

  1. 一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占地使用处理器
  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--

若无特别说明,本站文章均为原创,转载请保留链接,谢谢