深入理解中断,异常,系统调用

应用程序的运行过程中,往往会需要外部设备的干预,比如键盘敲击输入文字、鼠标点击确认按钮,并且应用程序自己可能需要一些系统服务,比如文件读写、网络通讯;另外,在运行过程中,可能还会产生一些意料之外的异常。不论是主动调起还是被动触发,都会产生一个CPU信号,这些信号分为三类,中断/异常/系统调用,信号发出后,CPU都会交给操作系统进行相应处理

那么三者分别是什么含义,区别又是什么呢?我们分三个方面作下说明

1.来源:

        1.1.中断的来源是外部IO设备,键盘产生敲击事件,鼠标产生移动点击事件,网卡产生网络包事件,显卡声卡等等都会产生各种事件,这些外设产生的事件就称为中断

        1.2.异常是应用程序在执行过程中出现了意料之外的事情,不得不让操作系统去完成相应的处理,比如除了一个值为0的变量

        1.3.系统调用是应用程序明确要求操作系统提供某个服务,比如打开文件,关闭文件,读写文件,发送网络包

2.触发时机与处理方式:

      2.1.中断:应用程序无法知道外设何时发出了中断信号,操作系统在检测到中断信号后,会切换到中断程序去处理,完成后再切换回应用程序,这个过程对应用程序是透明的

       2.2.异常:应用程序执行到引发错误的指令后,立即触发异常信号,操作系统同步处理,可能会杀死当前进程,或者重新执行产生异常的指令

       2.3.系统调用:应用程序发起调用时,触发系统调用信号,操作系统处理方式可能为同步可能为异步,比如应用程序请求读一块数据,可以在发出后等待数据就绪后才接着干其他事情,也可以在发出后就干其他事情,操作系统处理完成后发出就绪事件通知应用程序

3.处理过程:

        三者的处理过程大致相似,是硬件处理和软件处理的结合,首先都是由CPU检测到信号,然后再交给操作系统处理

        拿中断来说,外部硬件设备需要服务时,会设置中断标记,CPU会检测到这个标记,然后根据这个标记得出中断号,将中断号发给操作系统,操作系统就根据中断号在中断向量表中找到处理程序地址,在跳转到处理程序前,操作系统保存被打断程序的执行现场,执行中断处理程序,处理完成后恢复之前保存好的程序执行现场,让程序继续执行,这个跳转和恢复的过程叫做上下文切换,如果你感兴趣,可以参考我的博文深入理解上下文切换

        异常是CPU执行到应用程序的某个特定指令时产生了错误,比如除0,同样的,CPU会发出一个异常号,并将其发给操作系统,操作系统在中断向量表中找到异常程序处理地址,上下文切换到异常处理程序,操作系统可能会认为错误是由自己的服务不到位产生的,会将错误弥补好,然后切回应用程序,让它重新执行,这里注意重新执行接着执行的区别。如果操作系统认为异常是无法恢复的,或者不应该发生的,也有可能会选择杀死进程

        应用程序运行时,可能会需要一些特定的服务,比如文件读写,网络包传输等,这些服务不能由应用程序直接执行,必须由操作系统来完成,这就需要操作系统对应用程序提供一些接口,应用程序通过接口调用,间接的对整个计算机系统进行控制和管理。在不同的操作系统,这些接口都是以API的形式提供出来的,使得应用程序可以像调用方法一样简单的使用系统调用接口,这些接口会触发一个从用户态到内核态的转换。内核态以及用户态的划分,是操作系统为了控制不同程序的权限等级而设定的,权限等级分为ring0~ring3四个级别,用户态处于ring3,权限最低,内核态处于ring0,权限最高(可以访问系统关键资源,比如文件读写,网卡读写),当处于用户态时,想要执行更高权限的指令是被禁止的,所以会先切换到权限更高的内核态,然后再执行指令。切换到内核态后,和上面一样,操作系统会根据调用号找到处理程序,进行相应处理,如果这个过程中涉及到数据传输,还会触发数据在内核态和用户态两个内存地址空间之间的拷贝,处理完成后,切换回用户态,并返回本次调用的结果,比如从socket中读到了一行数据,应用程序就可以接着处理了

        中断,异常,系统调用的处理各有不同,相同之处也很明显,它们都跨越了应用程序与操作系统的边界,为了维持这个边界,操作系统付出了一定的代价

        1.需要维护一个中断向量表,用于找到处理程序

        2.操作系统要维护自己的堆栈,不能和应用程序堆栈混淆,操作系统处理程序退出时保存堆栈,执行时弹出堆栈

        3.操作系统是不信任应用程序的,在应用程序发出系统调用后,需要进行参数验证

        4.涉及到数据读写时,存在内核态和用户态的数据拷贝

        既然维持边界代价不小,为啥还要这样做呢?为啥应用程序不能直接和外设交互,不能直接打开文件呢?

       因为从安全角度来讲,操作系统是可信的,但应用程序是不可信的,其行为具有不可预测性,应用程序直接访问外设,操作系统资源可能造成整个计算机系统崩溃。这种机制可以让应用程序运行在一个相对安全的环境中

       从方便角度来讲,不论是中断、异常、还是系统调用,都是操作系统对上层应用提供的统一接口,操作系统屏蔽了各种底层设施的复杂度和不同点,让程序更可以更方便的使用

       所以说,这些开销是必须的,也是值得的

PS:如果有不足之处,欢迎指出;如果解决了你的疑惑,就点个赞吧o(* ̄︶ ̄*)o

猜你喜欢

转载自blog.csdn.net/wb_snail/article/details/105369880