异常的分类:中断、陷阱、故障和中止
我在前面说了,异常可以由硬件触发,也可以由软件触发。那我们平时会碰到哪些异常呢我们就一起来看看。 第一种异常叫 中断 (Interrupt)。顾名思义,自然就是程序在执行到一半的时候,被打断了。这个打断执行的信 ,来自于 CPU 外部的 I/O 设备。你在键盘上按下一个按键,就会对应触发一个相应的信 到达 CPU 里面。CPU 里面某个开关的值发生了变化,也就触发了一个中断类型的异常。 第二种异常叫 陷阱 (Trap)。陷阱,其实是我们程序员“故意“主动触发的异常。就好像你在程序里面打了一个断点,这个断点就是设下的一个”陷阱”。当程序的指令执行到这个位置的时候,就掉到了这个陷阱当中。然后,对应的异常处理程序就会来处理这个”陷阱”当中的猎物。 最常见的一类陷阱,发生在我们的应用程序调用系统调用的时候,也就是从程序的用户态切换到内核态的时候。我们在 第 3 讲 讲 CPU 性能的时候说过,可以用 Linux 下的 time 指令,去查看一个程序运行实际花费的时间,里面有在用户态花费的时间(user time),也有在内核态发生的时间(system time)。 我们的应用程序通过系统调用去读取文件、创建进程,其实也是通过触发一次陷阱来进行的。这是因为,我们用户态的应用程序没有权限来做这些事情,需要把对应的流程转交给有权限的异常处理程序来进行。 第三种异常叫 故障 (Fault)。它和陷阱的区别在于,陷阱是我们开发程序的时候刻意触发的异常,而故障通常不是。比如,我们在程序执行的过程中,进行加法计算发生了溢出,其实就是故障类型的异常。这个异常不是我们在开发的时候计划内的,也一样需要有对应的异常处理程序去处理。 故障和陷阱、中断的一个重要区别是,故障在异常程序处理完成之后,仍然回来处理当前的指令,而不是去执行程序中的下一条指令。因为当前的指令因为故障的原因并没有成功执行完成。 最后一种异常叫 中止 (Abort)。与其说这是一种异常类型,不如说这是故障的一种特殊情况。当 CPU 遇到了故障,但是恢复不过来的时候,程序就不得不中止了。
异常的处理:上下文切换
在实际的异常处理程序执行之前,CPU 需要去做一次“保存现场”的操作。这个保存现场的操作,和我在 第 7 讲 里讲解函数调用的过程非常相似。 因为切换到异常处理程序的时候,其实就好像是去调用一个异常处理函数。指令的控制权被切换到了另外一个”函数”里面,所以我们自然要把当前正在执行的指令去压栈。这样,我们才能在异常处理程序执行完成之后,重新回到当前的指令继续往下执行。 不过,切换到异常处理程序,比起函数调用,还是要更复杂一些。原因有下面几点。 第一点,因为异常情况往往发生在程序正常执行的预期之外,比如中断、故障发生的时候。所以,除了本来程序压栈要做的事情之外,我们还需要把 CPU 内当前运行程序用到的所有寄存器,都放到栈里面。最典型的就是条件码寄存器里面的内容。 第二点,像陷阱这样的异常,涉及程序指令在用户态和内核态之间的切换。对应压栈的时候,对应的数据是压到内核栈里,而不是程序栈里。 第三点,像故障这样的异常,在异常处理程序执行完成之后。从栈里返回出来,继续执行的不是顺序的下一条指令,而是故障发生的当前指令。因为当前指令因为故障没有正常执行成功,必须重新去执行一次。 所以,对于异常这样的处理流程,不像是顺序执行的指令间的函数调用关系。而是更像两个不同的独立进程之间在 CPU 层面的切换,所以这个过程我们称之为 上下文切换 (Context Switch)。
总结延伸
这一讲,我给你讲了计算机里的“异常”处理流程。这里的异常可以分成中断、陷阱、故障、中止这样四种情况。这四种异常,分别对应着 I/O 设备的输入、程序主动触发的状态切换、异常情况下的程序出错以及出错之后无可挽回的退出程序。 当 CPU 遭遇了异常的时候,计算机就需要有相应的应对措施。CPU 会通过“查表法”来解决这个问题。在硬件层面和操作系统层面,各自定义了所有 CPU 可能会遇到的异常代码,并且通过这个异常代码,在异常表里面查询相应的异常处理程序。在捕捉异常的时候,我们的硬件 CPU 在进行相应的操作,而在处理异常层面,则是由作为软件的异常处理程序进行相应的操作。 而在实际处理异常之前,计算机需要先去做一个“保留现场”的操作。有了这个操作,我们才能在异常处理完成之后,重新回到之前执行的指令序列里面来。这个保留现场的操作,和我们之前讲解指令的函数调用很像。但是,因为“异常”和函数调用有一个很大的不同,那就是它的发生时间。函数调用的压栈操作我们在写程序的时候完全能够知道,而“异常”发生的时间却很不确定。所以,“异常”发生的时候,我们称之为发生了一次“上下文切换”(Context Switch)。这个时候,除了普通需要压栈的数据外,计算机还需要把所有寄存器信息都存储到栈里面去。
推荐阅读
关于异常和中断,《深入理解计算机系统》的第 8 章“异常控制流”部分,有非常深入和充分的讲解,推荐你认真阅读一下。
课后思考
很多教科书和 上的文章,会把中断分成软中断和硬中断。你能用自己的话说一说,什么是软中断,什么是硬中断吗和我们今天说的中断、陷阱、故障以及中止又有什么关系呢迎留言和我分享你的疑惑和见解。你也可以把今天的内容,分享给你的朋友,和他一起学习和进步。 确认放弃笔记弃后所记笔记将不保留。新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开量公开的笔记不会为你同步至部落 公开 同步至部落取消完成 0/2000划线 笔记 复制
20人觉得很赞给文章提建议
? 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。 文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92459 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!