异常与中断
本节需要重点掌握 异常和中断的区别,尤其要分清事件来源、与当前指令的关系以及处理完成后的返回位置。关于中断方式的具体过程,参见 I/O 方式。
异常
在 CPU 中,异常 是指在程序执行过程中出现的非正常或意外情况,CPU 需要暂停当前执行,转而调用操作系统提供的异常处理程序。异常机制确保系统能够安全、有效地处理错误或特殊事件,并对程序执行做出相应调整。
类型
在执行指令的过程中,可能发生如下五类异常:
- 除法错误
- 触发条件:程序尝试除以零或执行非法除法操作。
- 处理方式:通常由操作系统捕获并中断程序执行,可能显示错误信息或终止程序。
- 浮点异常
- 触发条件:浮点运算出现溢出、下溢、除以零或非法操作(如对负数开平方)等情况。
- 处理方式:处理器会设置相应状态标志;异常未被屏蔽时可转入处理程序,被屏蔽时则可能按 IEEE 754 规则产生无穷大或 NaN 等结果。
- 缺页异常
- 触发条件:程序访问的内存页尚未加载到物理内存中。
- 处理方式:操作系统会将所需页从磁盘调入内存,更新页表后恢复程序执行。
- 保护错误
- 触发条件:程序试图进行非法操作,如写入只读内存、访问内核空间或执行特权指令。
- 处理方式:操作系统中断程序执行,防止非法访问。
- 硬件错误
- 触发条件:由硬件错误引起,如内存故障、总线错误、电源故障等。
- 处理方式:可能导致系统记录错误、尝试修复或直接宕机,具体行为依赖硬件和系统配置。
异常示例
下面给出了每种类型的一个具体实例,例如除零、非法浮点操作和缺页,帮助理解什么叫做异常:
- 除法错误
- 浮点异常
- 缺页异常
- 保护错误
- 硬件错误(机器检查)
int a = 10;
int b = 0;
int c = a / b; // 除以零,触发除法错误
float x = 0.0;
float y = sqrt(-1.0); // 无效操作:通常得到 NaN,并设置浮点异常标志
char* ptr = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE, fd, 0);
char c = ptr[0]; // 当访问 ptr[0] 时,触发缺页异常
// 内核通过页调度机制将数据从磁盘加载进内存,随后程序继续执行。
int* ptr = (int*)0xFFFF0000; // 指向只读或内核地址
*ptr = 42; // 写操作触发保护错误(Segmentation Fault)
// 机器检查异常通常由硬件引发,难以模拟。
// 示例:某些平台可使用特殊指令测试内存校验错误。
// 实际触发依赖硬件环境,下面为伪代码:
char* bad_addr = (char*)0xDEADBEEF;
char c = *bad_addr; // 假设该地址引发硬件错误
自陷
自陷(trap)是由当前执行指令同步引起的控制转移。狭义上,它常指程序显式执行陷阱/系统调用/断点指令后转入内核;更宽泛的教材口径会把由当前指令触发的同步异常也归入内中断。与外部中断不同,自陷与同步异常都不依赖外设异步请求。
自陷与同步异常的典型情形
- 同步异常处理:除零、非法内存访问、无效指令等由当前指令触发,处理器转入异常处理流程;它们不等同于程序显式发出的陷阱指令。
- 系统调用 用户程序请求操作系统服务(如打开文件、分配内存等)时,会使用特定的指令(如 x86 的
syscall)触发自陷,从而进入内核态执行系统调用处理程序。 - 调试断点 在调试程序时,可以设置断点。当程序运行到断点位置时,会触发自陷,暂停程序以供调试器介入。
自陷处理流程(简化)
- CPU 检测到自陷条件(显式系统调用/断点,或题设归入该类的同步异常);
- 暂停当前程序执行,保存体系结构规定的返回位置和状态;服务程序按需再保存通用寄存器;
- CPU 切换到内核态,转入操作系统预设的自陷处理程序;
- 操作系统根据具体情况处理异常或完成服务;
- 若问题可恢复,恢复程序状态,继续执行;否则终止程序。
陷阱指令 是显式由程序发起的指令,用于触发自陷事件。它常用于系统调用、调试等场景,是用户程序与操作系统交互的重要机制。
通过异常和自陷机制,CPU 和操作系统能有效应对运行中的各种突发情况,既保证系统稳定,又提供对错误的良好容错与控制能力。
中断
狭义的 中断 是 CPU 在正常执行程序过程中,由 外部设备 或外部事件发出的请求。它通常与当前正在执行的指令异步,促使 CPU 在满足响应条件时暂停当前程序,转去执行中断处理程序。软件指令主动进入内核属于自陷,不应与这种外部中断混为一谈。中断机制使 CPU 能及时响应输入设备、计时器和网络等事件。
分类
中断是一个比较大的概念,我们可以 按照其来源 或者 是否可以屏蔽 将其进行分类:
按照来源
- 外部中断:
- 触发来源:外部设备或外部事件触发,如输入设备、时钟、外部信号等。
- 响应:CPU 响应外部事件,执行相应的中断处理程序。
- 内部中断(也叫 异常):
- 触发来源:程序或 CPU 内部状态触发,如异常、错误等。
- 响应:CPU 根据内部条件触发中断,执行特定的中断处理程序。
按照是否可屏蔽
- 可屏蔽中断(Maskable Interrupt)
- 可以通过设置中断屏蔽位(如 CPU 的中断允许标志)来暂时禁止的中断。
- 通常为普通外设中断,如键盘、鼠标、网卡等。
- 不可屏蔽中断(Non-Maskable Interrupt, NMI)
- 无法被屏蔽的紧急中断,常用于处理系统级错误,如电源故障、内存校验错误等。
中断的分类可以通过下图辅助理解:
中断和异常的区别
异常 发生在 CPU 内部,在一般的分类方法中可以被看为中断类型的一种(内中断),但是在有的书上将中断和异常这两个概念区分了开来:
- 异常由当前指令执行或 CPU 内部状态引起,与当前指令同步;其中既有故障,也有系统调用等有意触发的自陷。
- 狭义中断来自 CPU 外部,通常与当前指令异步。
| 对比项 | 异常(内中断) | 狭义中断(外中断) |
|---|---|---|
| 来源 | 当前指令执行或 CPU 内部检测 | 外设、时钟等 CPU 外部事件 |
| 与当前指令关系 | 通常同步,可重复定位 | 通常异步,在指令边界响应 |
| 典型例子 | 除零、缺页、系统调用 | I/O 完成、定时器请求 |
| 返回位置 | 视故障、自陷、终止类型而定 | 通常返回下一条待执行指令 |
不同教材可能把异常和外部中断统称为“中断”,也可能把二者并列;解题时先确认题目的术语口径。
中断处理流程
中断处理流程参见 I/O 方式中的程序中断方式。
返回位置、精确状态与嵌套优先级
异常的同步性使处理器通常能把状态保存到一个精确的指令边界,但不同异常的恢复语义不同。故障类异常在指令尚未完成时发现,例如缺页或可恢复的地址错误;处理完成后应重新执行原指令。自陷常在指令完成后有意进入系统服务,返回位置通常是下一条指令。终止类异常表示当前程序无法可靠恢复,处理器或操作系统可能终止该进程而不返回原控制流。
外部中断一般在当前指令执行完后的边界响应,保存的断点通常指向下一条待执行指令。所谓“保护现场”不仅是把 PC 压栈,还包括处理器状态字、可能被服务程序改写的通用寄存器以及中断屏蔽状态;其中哪些由硬件自动完成、哪些由软件完成取决于体系结构和中断入口约定。恢复时必须以相反顺序还原,才能让被打断程序继续看到原来的寄存器和标志。
屏蔽与优先级解决不同问题
屏蔽位决定某一类可屏蔽请求在当前是否允许进入,优先级决定多个已允许请求中先响应谁,以及当前服务程序能否被更高优先级请求嵌套打断。不可屏蔽中断通常用于严重硬件事件,不能由普通中断允许位关闭,但仍要在体系结构规定的安全边界处理。服务程序若允许嵌套,应先建立可恢复现场并合理设置屏蔽级别;否则低优先级服务程序被打断后可能丢失临时状态或出现无界重入。
中断请求、响应、向量获取、保存现场、执行服务程序和中断返回是一条完整链路。只写“跳到中断服务程序”遗漏了断点与现场,无法解释处理结束后原程序为何能正确继续。