第八章、异常控制流
控制转移;
控制流;
异常控制流(ECF);
异常控制流发生在计算机系统的各个层次。
理解ECF很重要。
一、异常
1、异常:是异常控制流的一种形式。一部分由硬件实现,一部分由操作系统实现。
2、异常处理
(1)异常表:当处理器检测到有事件发生时,它会通过跳转表,进行一个间接过程调用(异常),到异常处理程序。
(2)异常号:系统中可能的某种类型的异常都分配了一个唯一的非负整数的异常号。异常号是到异常表中的索引。
3、异常的类别:中断、陷阱、故障和终止
a)中断处理:异步是指硬件中断不是由任何一条指令造成的,而是由外部I/O设备的事件造成的。
b)陷阱和系统调用:系统调用是一些封装好的函数,内部通过指令int n实现。
陷阱最重要的用途是提供系统调用。系统调用运行在内核模式中,并且可以访问内核中的栈。
c)故障
d)终止
二、进程
进程就是一个执行中的程序实例。系统中的每个程序都是运行在某个进程的上下文中的。
进程提供给应用程序的关键抽象:a)一个独立的逻辑控制流 ;b)一个私有的地址空间
1、逻辑控制流
程序计数器(PC)值的序列叫做逻辑控制流,简称逻辑流。如下图所示,处理器的一个物理控制流分成了三个逻辑流,每个进程一个。
2、一些概念:
并发流:并发流一个逻辑流的执行在时间上与另一个流重叠。
并发:多个流并发执行的一般现象称为并发。
多任务:多个进程并发叫做多任务。
并行:并发流在不同的cpu或计算机上。
3、私有地址空间
一个进程为每个程序提供它自己的私有地址空间。
4、上下文切换
上下文切换:操作系统内核使用叫上下文切换的异常控制流来实现多任务。
a)保存当前进程的上下文;
b)恢复某个先前被抢占的进程被保存的上下文;
c)将控制传递给这个新恢复的进程
调度:内核中的调度器实现调度。
当内核代表用户执行上下文切换时,可能会发生上下文切换。
5、用户模式和内核模式
用户程序的进程初始是在用户模式中的,必须通过中断、故障或陷入系统调用这样的异常来变为内核模式。
6、系统调用
在Linux中,可以使用 man syscalls 查看全部系统调用的列表。系统级函数遇到错误时,通常返回-1,并设置全局变量 errno 。
strace 命令可以打印程序和它的子进程调用的每个系统调用的轨迹。
三、进程控制
1、获取进程ID
2、创建和终止进程
进程的三种状态:运行、停止和终止。
创建新进程可以使用 fork 函数。新创建的子进程和父进程几乎相同,它获得父进程用户级虚拟地址空间和文件描述符的副本,主要区别是它们的PID不同。
fork 函数调用一次,返回两次。
3、回收子进程:
回收:当一个进程终止时,内核并不立即把它从系统中清除。相反,进程被保持在一种已终止的状态中,直到被它的父进程回收。
僵死进程。
回收子进程的两种方法:
1.内核的init进程 ;2.父进程waitpid函数
1)如果父进程没有回收它的僵死子进程就终止了,那么内核就会安排init进城来回收它们。init进程的PID为1,并且是在系统初始化时创建的。
2)一个进程可以通过调用waitpid函数来等待它的子进程终止或停止。
waitpid函数有点复杂,默认地(当options=0时),waitpid挂起调用进程的执行,知道它的等待集合中的一个子进程终止。
4、wait函数:
wait(&status)函数,等价于调用wait(-1,&status,0)
5、让进程休眠:
sleep函数将一个进程挂起一段指定的时间。
pause函数让调用函数休眠,知道该进程收到一个信号。
加载并运行程序。
参数列表。
环境数组操作函数;
三、信号
在操作系统和应用程序之间:进程之间传送信号
一种更高层次的软件形式的异常,称为unix信号,它允许进程中断其他进程。
1、信号处理过程
1)发送信号:
2)接收信号:
注意:待处理信号,一种类型的信号只能有一种待处理信号,多余的不会排队,而是会舍掉 ; 信号还可以阻塞。
2、发送信号:/bin/kill , kill函数,键盘,alarm函数
进程组:
每个进程都只属于一个进程组,进程组是由一个进程组ID来标识的。默认的,一个子进程和它的父进程同属于一个进程组。
在任何时刻,至多只有一个前台作业和0个或多个后台作业。外壳为每个作业创建一个独立的进程组,一个作业对应一个进程组。
用kill函数发送信号:发送SIGKILL信号;
用alarm函数发送信号:发送SOGALARM信号;
3、接收信号
进程可以通过使用signal函数来修改和信号相关的默认行为。唯一的例外是SIGSTOP和SIGKILL,它们的默认行为不能被修改。
4、信号处理问题
当一个程序捕获多个信号时,容易有一些细微问题。
信号处理有以下特性:
1.信号处理程序阻塞当前正在处理的类型的待处理信号。
2.同种类型至多有一个待处理信号。
3.会潜在阻塞进程的慢速系统调用被信号中断后,在信号处理程序返回时不再继续,而返回一个错误条件,并将 errno 设为 EINTR 。
四、非本地跳转(应用层)
(1)c语言提供了一种用户级异常控制流形式,称为非本地跳转。通过setjmp和longjmp函数来提供。
setjmp函数只被调用一次,但返回多次:一次是当第一次调用setjmp,而调用环境保存在缓冲区env中时,一次是为每个相应的longjmp调用。另一方面,longjmp只调用一次,但从不返回。sig—函数是setjmp和longjmp函数的可以被信号处理程序使用的版本。
换句话,在信号处理程序中进行非本地跳转时应使用 sigsetjmp 和 siglongjmp 。如果 savesigs 非0,则 sigsetjmp 在 env 中保存进程的当前信号屏蔽字,调用 siglongjmp 时从 env 恢复保存的信号屏蔽字。同时,应该使用一个 volatile sig_atomic_t 类型的变量来确保 env 未设置时不被中断。
- 非本地跳转的一个重要应用就是允许从一个深层嵌套的函数调用中立即返回,通常是由检测到某个错误情况引起的。
- 非本地跳转的另一个重要应用是使一个信号处理程序分支到一个特殊的代码位置,而不是返回到达中断了的指令位置。
总结:
异常控制流发生在计算机系统各个层次,是计算机中提供并发的基本机制。
本次读书比较认真,收获很大。