异常控制流(ECF):当发生某种事件(例:一个硬件定时信号、包到达适配器后要求存储的事件等)操作系统使控制流发生突变来应对这些事件,称此突变为异常控制流(ECF)。
ECF发生在计算机系统的
各个层次。
如 硬件层,检测到事件会触发控制突然转移到 异常处理程序。
在os层, 内核通过上下文转换将 控制从 一个用户进程转移到另一个用户进程。
在应用层,一个进程可以发送信号到另一个进程,而接收者会将控制 突然转移给他的一个信号处理程序。且程序可以回避
通常的栈规则,并执行到其他函数任意位置的
非本地跳转来对错误做出反应。
应用层 通过使用 陷阱(trap)或系统调用(system call)的ECF形式,来向操作系统请求服务。
各层次上的各种形式的ECF:
系统调用--应用程序提供到操作系统的入口点的异常。
非本地跳转--应用层形式
异常
异常是ECF的一种形式,一部分有硬件实现,一部分有操作系统实现。 任意时刻当处理器检测到有事件发生时,他就会通过 异常表(一张跳转表),跳转到对应的 异常处理程序。完成后,会发生下列3种情况之一:
1.控制返回到当前的指令,继续执行。
2.控制返回到 当前指令的下一条指令,继续执行。
3.终止
异常的类别
四种:中断、陷阱、故障和终止
中断--异步--来自I/O设备的信号(硬件中断)--返回给下一条指令
陷阱--同步--主要用于
系统调用--返回给下一条指令
故障--同步--
缺页、除法错误等故障--故障修复后重新执行原指令(如不可恢复 则abort终止)
终止--同步--硬件错误--将控制返回给abort来终止
系统调用函数的封装
目标--减少代码量,提高可靠性
当Unix系统级函数遇到错误时,典型会返回-1,并设置全局变量errno来表示错误。完整的程序应包含错误类型如下:
当 fork() 创建一个进程。成功:返回 非负数(父进程中 返回 子进程pid号--整数,子进程返回0)
完整 检测
方法一:
if( (pid = fork()) < 0)
{
fprintf(stderr, "fork error:\s\n", strerror(errno));
exit(0);
}
做如下封装
void unix_error(char* msg)
{
fprintf(stderr, "%s:%s\n", msg, strerror(errno));
exit(0);
}
pid_t Fork()
{
pid_t pid;
if((pid = fork()) < 0)
unix_error("fork error");
return pid;
}
方法二:
pid = Fork();
对比:此时方法二较方法一 同样包含检错程序,且代码量更少,更清晰。