操作系统-13-程序员应如何理解中断

在这一节中我们聊一聊,操作系统管理外设的中断机制。

为什么要在这一节聊一聊操作系统如何管理外设呢,外设管理是操作系统的核心任务之一,理解操作系统的外设管理机制对于我们理解操作系统工作原理至关重要。通过第二章的讲解,我们已经知道了,利用系统调用这种机制,我们可以向操作系统发起请求来创建进程、读写文件等等,虽然我们还没有讲解操作系统如何进行进程管理文件管理等,至少操作系统的这一部分工作机制,也就是系统调用,对于我们来说已经不再神秘了,但是我们依然不清楚操作系统是如何管理外部设备(鼠标、键盘、USB设备、打印机、磁盘等等,以下简称外设)的,因此在这里我们有必要讲解一下操作系统管理外设的机制是什么。

急性子领导(CPU)与慢性子员工(外设)
作为程序员我们需要知道CPU同样是通过机器指令来管理外设的,至于通过哪些机器指令来控制外设目前还不是我们的关注重点,目前为止,我们只需要知道,本质上,CPU是通过机器指令来控制外部设备就可以了。

CPU和外设是两种速度相差很大的硬件。相对于CPU的运行速度来说,各种外设简直不是一般的慢,这就好比一个波音747的速度一个是自行车的速度。两种运算速度相差如此迥异的设备之间该如何进行交流呢?如此高速的CPU该如何管理如此慢吞吞的外部设备呢?

注意,这里所说的管理,本质上就是:

1.CPU通过机器指令交给外设一项任务。
2.外设完成这项任务。
3.CPU需要知道这些任务是否完成。

所以你会看到其实CPU是管理者,外设是真正的执行者。管理者下达命令,执行者完成任务,同时管理者需要知道任务是否完成。我们面对的问题是这样的,CPU是个急性子(运算速度快),而外设恰恰相反是个慢性子,总是慢吞吞的(运算速度慢),如果是你要来设计这样一个管理方案的话,你该如何解决这个问题呢?在继续阅读下面的内容之前,希望读者能够先自己想想该如何解决。

如果你已经想得差不多了,那么接下来看看答案是否和你想的一样。

方案一:不断查询状态

我们能想到的最简单的方法就是CPU下达任务后不断的去问外设:“Hey,外设老兄,这个请求你处理完了吗?”,如果外设回答“还没有”那么CPU就一直不断的问下去直到外设回答“执行完毕”,如图所示:
在这里插入图片描述
这种方案非常简单,但是有一个缺点,那就是CPU要想知道外设是否完成任务,就只能不断的去查询外设的工作状态,这种不断查看设备状态的方法被称之为轮询,即Polling。在后面的课程中我们还会见到轮询在其它场景中的应用。我们需要意识到采用这种方案的话,CPU需要不断的去查看外设执行状态,在这期间CPU不能执行其它有用任务,不断轮询的这段时间CPU做的当然是无用功,因此这种方法有性能损耗,还有没有其它更好的方法吗?

方案二:中断(Interrupt)

方案一中待改进的一点就是CPU需要不断的查看外设是否完成任务,但是谁最清楚外设是否已经完成任务了呢,当然是外设自己,所以我们需要某种机制,在外设完成任务后通知CPU,这样CPU就不用不断的查询了,这种机制被称为中断(Interrupt),如图所示:
在这里插入图片描述

中断机制完美的解决了方案一中轮询所带来的性能损耗,外设在执行请求期间,CPU可以执行其它任务,作为程序员我们需要知道,此时CPU和外设是在并行处理任务,外设处理请求期间CPU没有再做无用功,因此这种方法可以更加高效的利用系统中的硬件资源。从这里我们可以看到并行是一种非常有用的设计思想,这就是为什么程序员必须要掌握多线程的原因,多线程可以充分利用系统中的多核资源,使多个CPU核心都忙碌起来从而高效利用计算资源加快任务处理速度,关于多线程后续课程会有非常详细的讲解。

当外设完成任务后通过中断机制通知CPU这一状态。其实这种机制在生活中我们已经习以为常了,我们还是以接收快递为例,我们不会不断的去问快递小哥到了没有(Polling),而是在没到之间我们该干啥干啥(并行),当快递到了之后自然会给我们打电话(中断),那时我去拿就好了,这就是中断机制在生活中的使用,这个道理在计算机中是一样的,你能理解接收快递就能理解这里的中断机制。其实你会发现计算机的各种技术没有那么神秘,就像艺术创作一样,来源于生活但高于生活。

中断一定比轮询高效吗?
当然在这里还要多说一句,轮询和中断是两种最基本的通知机制,无论像这里的硬件通知机制还是软件设计中的通知机制,这两种方法都广泛存在。从本文的描述中可能大家都觉得中断要好于轮询,实际上不完全是这样的,这两种方法都有各自的使用场景,在特定场景下可能轮询的效率会高于中断,假如我们提前知道了外设处理的速度非常非常快,速度基本上等同于CPU,那么这时使用轮询的效率是非常高的,因为CPU查询不了几次就能继续执行接下来的任务了(外设处理速度飞快),反而在这种情况下使用中断机制不一定高效,因为中断产生后CPU执行的任务发生变化,==这时CPU需要进行任务切换,作为程序员我们需要知道任务切换也是有代价的,当任务切换的代价高于轮询的代价时,中断机制就没有轮询机制的效率高了。==因此当我们讨论这两种机制哪个更高效时实际上讨论的是任务切换和不断查询哪个代价更低。在后面的课程中我们还会遇到这两种机制。

什么是中断
在上一小节中,我们已经知道了外设通过中断来通知CPU自己的状态。其实,外设是通过向CPU发送电子信号来通知CPU的,这些电子信号就被称之为中断(Interrupt),就好比快递小哥给你打电话一样。CPU在接收到这些电子信号后开始进入内核模式运行操作系统,操作系统根据信号源执行相应的函数来对外设进行相应的处理。

因此从这里我们可以看到CPU需要具备监测这些电子信号(中断)的能力,现代CPU都已经具备了这一能力,因此当外设产生中断时,CPU可以检测到。我们无需在硬件层面上理解这是如何实现的,只需要知道当外设产生中断信号时CPU是可以检测到的就可以了。到目前为止,关于CPU我们需要知道除了执行机器指令之外,CPU还可以检测到外设发出的中断信号,进而运行操作系统对外设进行管理。因此在这里,我们进一步完善了对CPU的认知,CPU的两项任务:
1.执行机器指令
2.监测外设中断信号

这里需要注意的一点是,外设向CPU发送中断信号是和CPU当前的状态没有关系的,不管CPU当前处于用户模式执行用户程序或者处于内核模式运行操作系统。也就是说外设在任何时间都可以向CPU发送中断信号。即,外设中断信号的产生相对于CPU来说是异步的,就好比快递小哥给你打电话一样,不管你是在吃饭睡觉上班还是在上课,快递小哥一到就给你打电话,快递小哥打电话相对于你来说就是异步的,与异步相对应的是同步,你主动给快递小哥打电话问到哪里了就是同步。

由于计算机中的外设多种多样,因此CPU仅仅接收到中断信号是不够的,CPU需要能清楚的知道是哪个外设发送的中断信号。幸好,外设的每个中断信号都被分配了唯一的一个整数值,这样CPU就能知道中断信号是从哪种外设发送过来的。因此这里需要大家清楚的意识到,CPU不但能接收到中断信号,还可以区分中断来自谁。

在这里我们已经知道了CPU可以检测到外设的中断信号,还能分辨出是谁发出的中断信号,然后运行操作系统进行处理,接下来我们看一下中断从产生到处理的整个过程。

中断机制的实现

很多同学觉得这一部分不好理解,就是因为中断机制的实现是软件和硬件通力合作完成的,如果你已经理解了系统调用的实现过程,那么这一部分就很简单了。接下来我们就以先硬件后软件的顺序来讲解一下中断机制的实现过程。

通过上一小节的学习,我们已经知道了外设可以向CPU发送中断信号,而CPU也可以检测到中断信号的产生,因此中断机制的硬件部分就是外设和CPU。

CPU在接收到中断信号后,根据每个中断被赋予的唯一整数值就可以知道中断来自哪个外设。接下来同系统调用过程一样,CPU开始切换到内核模式(如果CPU在这之前工作在用户模式下),跳转到一个提前定义好的内存地址运行操作系统,这时操作系统开始接管整个计算机。接下来就是软件的部分了。

值得注意的是,在《程序员应如何理解系统调用》(链接)这一节中我们讲过CPU执行系统调用后也会跳转到一个提前已经定义好的位置,而CPU因中断产生后CPU也会跳转到一个提前已经定义好的位置,这两个位置其实是同一个。

在这里我们明确一下,这个提前定义好的位置其实是在系统启动过程中定义好的,这个位置保存的信息就是一张表,表中的每一项保存的是处理当前中断的函数指针,每个对应的处理函数就叫做中断处理handler,这张表被称之为异常表(Exception Table)。

注意,由于系统调用和中断处理都的都是这一张表,因此张表指向的代码被成为之“处理异常代码”,这里的异常是系统调用和中断的统称(不要把这里的异常和编程语言当中的异常混淆,这里的异常仅仅是系统调用和中断的统称)。

在这里插入图片描述
这张表极其重要,你可以认为这是操作系统运行的总入口,操作系统不像我们的程序有一个main函数,这张表就可以理解为操作系统的“main函数”。

那么这里的异常又是指的什么呢?一般可以认为当我们的程序在运行时被称为“正常”,因为计算机的目的就是为了执行用户程序,而除此之外的就是“异常“。那么计算机中除了我们的程序还能有谁呢,剩下的就是操作系统了。因此当CPU暂停执行用户程序跳转到这张表的内存起始地址后,操作系统开始运行接管整个计算机。

我们之所以说这张表在内存中的地址是提前定义好的,是因为在计算机启动过程中,这张表在内存中的地址被保存到了CPU中一个特殊的寄存器当中,这个寄存器就叫做异常表基址寄存器(Exception Table Base Register)。有了这张表的地址再加上异常号我们就可以很容易的找到处理该异常的函数了(Excepetion Handler),这就好比给定数组arr以及数组下标i,我们就可以很容易找到想要的内容arr[i]了。我们以x86系列CPU以及Linux操作系统为例,x86中定义了255中异常,也就是说上表中的n是255,其中第128号用于系统调用,32-127以及129-238用于外设中断。因此得到异常号后,如果是128,我们就知道了这是用户程序在进行系统调用,如果是32-127、129-238范围内,这就是外设发出的中断信号。

在得到中断处理函数后剩下的工作就简单了,剩下的所有工作都交给了中断处理函数。一般情况下,对于处理外设中断信号的函数来说,该函数其实就是设备驱动程序的一部分。比如如果是键盘鼠标的异常处理handler,那么该函数的任务就是把键盘字符或者鼠标位置从设备拷贝到操作系统内存当中,如果是网卡异常处理handler,那么该函数的任务就是把网卡中的网络数据拷贝到操作系统内存当中。

整个过程如下图所示:

在这里插入图片描述

接下来我们用浏览器是加载网页的例子来形象的说明中断机制。

浏览器是如何加载网页的
作为程序员如果没有浏览器的话你还会写代码吗,请认真严肃的思考一下这个问题 😃 浏览器应该是程序员编程过程中使用频率最高的应用程序了,但是你知道一个网页加载的完整过程吗?

当我们用浏览器打开一个URL时,首先浏览器会向DNS发送域名解析请求,获取到该URL对应的IP地址后,我们的浏览器同该IP对应的服务器建立TCP链接,成功后浏览器向服务器发送HTTP请求,其中的请求路径就是URL。如果你学习过计算机网络,那么这个过程应该比较清楚,在这里我们更感兴趣的是接下来的过程,也就是服务器向浏览器发送数据后是什么样子的。

假设我们用Visual Studio Code一边写代码一边用浏览器查资料,以下是其完整过程:

浏览器向服务器发送HTTP请求后,调用系统调用比如receive()等待数据的到来,因为数据尚未收到,因此操作系统决定暂停执行浏览器并进行进程切换(我们会在下一节中详细讲解进程切换),切换到VS Code,这样VS Code开始执行。
网络数据到来:
1.网卡接收到服务器发送的数据
2.网卡接收到数据后向CPU发送中断信号
3.CPU检测到中断信号后开始切换到内核模式,暂停VS Code的执行
4.根据中断信号判断出是该中断是网卡产生的,5.CPU找到异常表并根据中断类型找到处理网卡相关的中断处理函数比如NetCard_Handler(),该函数开始运行,将数据从网卡中拷贝到操作系统内存当中
6.将数据拷贝到操作系统内存后,该中断处理函数把网络数据再次从操作系统拷贝到浏览器内存当中。
完成这些任务后,操作系统发现浏览器请求的网络数据已经接收到了,操作系统决定再次运行浏览器,因此CPU被再一次分配给浏览器,浏览器继续运行,此时我们最开始调用的receive()返回并继续运行接下来的浏览器代码,由于网络数据已经被操作系统拷贝到了浏览器内存当中,因此浏览器对获取到的网络数据进行解析并展示页面,整个过程如图所示:
在这里插入图片描述
更形象的理解就是,网络数据到来后,网卡朝操作系统喊了一声:“Hey,操作系统,我这有新鲜的网络数据,赶快来处理一下吧”,操作系统听到后放下手头上的任务(暂停运行用户程序),赶紧去网卡中接收数据,接收完数据后操作系统根据情况来决定接下来的任务。

总结:Hey,操作系统

在这一节中我们详细讲解了中断机制,中断机制涉及到了软件和硬件的密切合作,这也是很多同学理解上的难点,不过作为程序员我们不需要理解硬件层面中断是如何产生的,我们只需要知道外设可以向CPU发送中断信号,CPU切换到内核模式后操作系统开始运行并对其进行处理。接着我们用一个程序员常见的一边写代码一边查资料的例子详细的说明了中断机制。

虽然程序员不需要与中断打交道,但是我们需要意识到,按一下键盘按键,晃动一下鼠标,网络数据的到来,CPU都会检测到这些事件,检测到后就会暂停当前执行的任务(不管是用户程序还是操作系统中的任务),接着操作系统开始接管计算机,如果是键盘按键,那么操作系统获取按键的字符;如果是鼠标,那么操作系统获取鼠标位置;如果是网络数据,那么操作系统将数据从网卡复制到操作系统的内存当中,然后操作系统去查看是否有哪些进程在等着用这些数据,如果有的话,那么操作系统把数据拷贝给该进程,同时把CPU分配该该进程,这样被暂停执行的就得到了需要的数据,然后进程恢复执行。

因此每次外设有中断信号的时候其实就是外设在向操作系统say hey,“Hey,操作系统,停下你手上的任务,我这有数据需要你来处理一下”。

中断机制对于理解操作系统是如何运行的至关重要,理解了中断之后,在接下来的章节中我们来看一下操作系统是如何工作的。毫无疑问,作为计算机高手,你需要清楚的理解操作系统是如何工作的。
本文来自《码农的荒岛求生》

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发如雪-ty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值