我知道异常是一种软件中断,但是在中断之后,程序计数器总是返回到引发中断之前的地址,但是在异常之后,如果异常没有得到正确处理,程序可能会终止,这意味着程序计数器不再指向程序指令的内存地址,那么为什么处理会有如此大的差异呢?
假设我们有一个程序,它将两个数字 A 和 B 相除。首先,程序要求 B,打印 B,然后要求 A,打印 A 计算 B/A,最后打印 B/A。让我们暂时忽略来自键盘的中断。
因此,程序将第一个输入作为 B,然后显示中断中断主程序并执行在屏幕上显示 B 的指令,然后返回到中断发生时主程序的当前指令。现在假设 A 为 0,主程序没有内置处理异常(除以 0)的代码。现在屏幕中断和 DivideByZero 异常之间存在很大差异,因为在屏幕中断的情况下,在执行在屏幕上显示 B 的指令后,主程序的指令继续正常执行,而在 DivideByZero 异常的情况下,程序只是停止,并且由于操作系统无法处理异常,计算机退出程序。
因此,在第一种情况下,主程序的指令将继续执行,而在另一种情况下,主程序的指令将不再执行。
那么为什么不同类型的中断的处理如此不同?
答案1
在任何一种情况下,异常或中断的控制都由操作系统处理,然后代码执行才交还给应用程序。
一般流程是
- 程序代码执行
- 硬件引发中断
- 操作系统执行上下文切换并运行中断代码。当前程序状态被存储并保存
- 中断代码执行处理中断所需的工作,将数据存储在缓冲区中等等
- 中断将控制权返回给操作系统。
- 操作系统执行另一次上下文切换,这次切换到被中断的程序并继续执行。
异常可以看作是一种特殊的中断。如果程序执行了需要停止或终止的操作,那么显然没有任何东西可以将控制权交还给它。
在这种情况下,操作系统将继续进行并执行上下文切换到下一个需要 CPU 时间的程序。
答案2
从硬件的角度来看,中断是一种特殊类型的异常。
每当程序正常执行暂停并运行异常处理程序时,就会发生异常。通常,CPU 在跳转的同时进入“更高特权”模式,这是提升特权的唯一方法。
例外情况包括精确的,这意味着它们发生在特定指令上,并且处理程序代码会被告知这是哪条指令。这通常是由当前正在运行的程序引起的异常的情况,例如当解码无效指令时。
特定程序错误是否会导致精确的异常由实现定义——某些架构按顺序执行指令,某些架构竭尽全力假装顺序执行,如果内存访问被证明是非法的,则回滚推测执行的代码,而有些架构则让软件来调查错误。
中断通常是不精确的异常,因为引发的中断和正在执行的代码之间没有关系。