瞎扯淡 中断的本质是什么

jiffies · 2012年08月14日 · 最后由 XQDD 回复于 2020年08月21日 · 12023 次阅读

洗澡的时候不知怎么突然又想到“中断”。 以前上学的时候就听的就不是很明白,许多书里也讲的似是而非,在后来编程的时候又遇到很多名词像 addListener,bind,槽,回调,事件,消息等等似乎都跟“中断”这个词有关。所以也上网看过许多帖子的解释,过程虽然很清晰明了,但是总觉得还是哪里隔着一层膜,让人那么的不舒服。 经常性的解释就是:

loop {
  check A  //假设check实在检查某事件是否发生
  do B
  check C
  do D
}

在 B 执行时,如果 C 发生了,C 不能得到及时相应,或者 A 一直不发生却一直检查 A 效率很低。 用中断机制时,

loop {
  do B

  do D
}

A,C 发生了会主动发出信号,CPU 再去处理。之前注册的两个回调 do A {} do B {}


实际上,在底层,CPU 执行完每条指令时都会去检查一个中断标志位,当发现某一位置 1(可能)时,知道有中断发生(不考虑多中断),CPU 会保存现场(context),转而执行我们提前注册过的程序,即 ISR(Interrupt Service Routine),实际就是一种回调函数。ISR 会调用具体硬件驱动程序的中断例程,这里的中断例程又是一种回调(linux 会用 request_irq 注册),它会去读硬件寄存器取得事件的具体信息。

之后的就不太熟悉了,猜测的,希望有高人教我 Linux 可能会是层层回调机制,最上层的应用程序注册的回调最终会被调用。 windows 可能用的事件机制(消息机制,一回事),事件从底层层层上传,windows 窗口程序有一个线程专门循环 GetMessage,检查一个事件队列。

不管怎么样,检查某个事件是否发生本质都是轮询+check,它没在代码里看到,只是发生在别的地方了,比如 CPU 层级;或者换了一种方式。经常举得例子里实际是用听力代替了视力去轮询(觉得这里有什么可以挖掘,还没想到),一定范围内,听力比视力的监察范围更广。

所谓的实时性,就是提高到了指令周期级别。每秒十亿次,但是在无限细分下去,仍然有无法响应的盲点,因为每一周期就是一个轮询。并行性也就是利用计算机极快的速度与人的反应的差别。并不是一直在运行,但是看上去似乎是的。

光速 30 万公里每秒,人的肉眼捕捉不到 24 帧以下的空隙,当有那么快的速度时,人就可以做到分身术了

推荐阅读《现代操作系统》 http://book.douban.com/subject/3852290/

cpu 的中断引脚是异步的,只管收到设备的信号就有中断了。

"检查某个事件是否发生本质都是 轮询+check"这句的一个反例是时钟中断,可编程时钟 (PIT) 就绝对不会是靠轮询来实现的。

相反,cpu 为了更好的利用主线,处处都留着异步的设计的痕迹。轮询 (或者同步操作) 在 cpu 一级,则属于能避免就避免的

楼主是希望得到硬件级别的解释吧

中断的本质是程序的转移

玩玩单片机就懂了。

我认为中断是现在操作系统的基础!!!! 很重要!!!

#2 楼 @fleuria 其实我想说的就是本质无论如何都是轮询,任何一个中断都需要检查才能发现

#4 楼 @kikyous 那是中断执行之后的事了,我想讨论如何发现中断

#3 楼 @firsthym 我是希望有大家来讨论下

#1 楼 @reus 简洁概括下啊

#5 楼 @jinleileiking 是的,但是我想讨论的是如何发现中断,

#9 楼 @jiffies 我想如果你概括地看下有关操作系统的书,你的疑惑会少很多 高级语言里的回调和事件等机制,和底层的中断之间是隔着很远的,驱动、固件、操作系统这些会处理好中断,实现编程语言的时候是不需要考虑这些底层的东西的,虽然原理类似。 曾经有人不理解异步 IO 的原理,后来我发现他以为自己写的程序会独占 cpu,完全没有多任务操作系统的概念…

#12 楼 @jiffies 你没理解,中断不是主动去轮询发现的,那是同步的。 中断有两种,一种是硬的,一种软的,硬的明显就是指硬件中断了,时钟中断,键盘中断这些,主动去通知 cpu,而操作系统一般会设置一个中断描述符表去接收这些中断。

软的就懒得解释了。

总的一点,就是中断不是你来发现,是他来找你。对,跟艳遇差不多。

#13 楼 @hhuai 不可能,主体不去检查是不可能发现信号的,我想驳斥的就是这一点

#14 楼 @jiffies 你的思想大概是对的,确实是轮询,但并不是执行完一条指令去 check 一下中断标志位,而是每个时钟周期都要 check,但是如果不是指令最后一个周期,则封锁此中断请求。

这是因为有双周期和多周期指令的存在

#6 楼 @jiffies 『任何一个中断都需要检查才能发现』是错误的。中断打断 cpu 的执行流程时,并不是 cpu 主动。CPU 并不是计算机系统的独裁王者,它只是连接到主线的一个用户,与其它设备一样,共同遵循着主线的协议。中断发生的时候根本不由你检查不检查,只要没屏蔽就都得做。

你去打开一只台灯的开关,你不会认为台灯是主体去检查了开关。同样,你往中断引脚里传了信号,你也不该认为是 CPU 去检查了引脚。

找一本计算机组成的书籍静静的看一下,会比灵光一闪去驳斥自己未理解的东西对自己更加有益。

#15 楼 @ninehills 具体细节的确记不得了,主要是思想。多谢

#16 楼 @fleuria 这个问题上@jiffies 大体上是正确的。CPU 确实是计算机绝对的独裁王者,外部中断,不管是硬件中断也好,软件中断也好,最后不过是改变了 CPU 寄存器中某个小小的中断标志位。处理不处理这个中断标志位,那要看 CPU 的心情了。。。

#18 楼 @ninehills 只要没屏蔽都会压栈的,之前还会进入 trap gate 切换 cpu 的权限。操作系统可以选择忽略它们,但这由不得 cpu。

#18 楼 @ninehills 再小提醒下,cflags 的 IF 标志是做什么用的?

#19 楼 @fleuria 看来你的理解还停留在操作系统那一层上面。找本 51 单片机的书看一下吧,不需要操作系统也能写程序,还有各种中断可用。

#21 楼 @ninehills 我写过操作系统,对 cpu 不能没入门的。前面的问题您没有回答,cflags 的中断标志位是做什么用的? 『中断发生时也就是设置一下中断标志位』,是真的这样子么?

#16 楼 @fleuria 你说很有意思,不觉得很有哲学意味在里面么。书当然看了,书上说的并不透彻。所以我才想讨论下。 都知道软件硬件可以互相转化,你说的不由检不检查,实际就是人为的编程让 CPU 去检查的。如果 CPU 跟中断引脚分开了,它还能收到信号么,如果已经关机 CPU 停止工作了,就更不可能察觉到中断了。 其实你说的也是轮询,但区别是主动的还是被动的。我认为可以设想为主动的。想象一个植物人,外界的一个刺激可能仍然能通过神经传导到大脑,可是大脑已经不工作了,所以没有任何反应。 台灯似乎不是主体,但是无时无刻不在的电是不是在轮询呢,如果没有电一直在插头那端,按下开关也不会亮。

#23 楼 @jiffies 哲♂学并非偏离现实的借口。 如果一些基础概念不能固定下来,异步也可同步也可,哲♂学也没什么好谈的。

#19 楼 @fleuria 我的意思是说你认为 CPU 必须无条件接受中断信号,实际这个结果也是人对硬件编程或者说电路设计的结果,仍然是一个 check

#22 楼 @fleuria 不和你争论这个随便一本 51 书上写的清清楚楚的问题。

虽然 51 和 x86 一个是哈佛结构,一个是冯诺依曼结构,但基本原理都是一样的,CPU 的指令流水线都是一样的,中断的原理都是一样的。如果你不懂中断触发的原理,那么我只能说。。。。没啥关系,反正你只需要写软件就好了。这些都是被 CPU 自己处理掉了。

#22 楼 @fleuria P.S. google 关键词“单片机 中断 原理”,虽然网上不靠谱的东西多,但这种基础的东西还是很对的。。。都是摘抄自各种教材

#26 楼 @ninehills 不要拿 51 当好东西,落后二十年了。

英特尔的手册在那里可以免费下载,APIC 之类做的事情很多很多,这部分语义很微妙,但仔细看是可以找到主线的。如果连这种概念都含含混混的不能给个准,英特尔的工程师也就只能停留在 51 这层次上了。

#27 楼 @ninehills 根据你的关键词搜了一下,以下是第一第二个,实际并没有就我们讨论的焦点做什么说明,但是大致还是支持我的观点的

#28 楼 @fleuria 但是原理变过么?

#29 楼 @jiffies 第二个你再往后看一段就看到了。

#30 楼 @ninehills #29 楼 @jiffies

真理、本质这种词还是躲远些好。否则越来越糊涂。

你看到了中断发生时,51 设置中断标志位。但是中断标志位是做什么的你没有看。设置 IF 是为了防止中断时产生其它中断而造成同步问题。也就是说,在中断的处理例程中,不允许并发。51 这样自动设置,是个很简陋的设计。现代的操作系统和 CPU,是希望中断标志位设置的时间越短越好。x86 发生中断时会做很多检查,不过这检查更多是权限的检查,而把中断作为一个事实接受下来,会穿过 IDT,从 ring3 跳到 ring0,切换用户栈到内核栈,把一坨寄存器的值和中断号压进去,操作系统才知道是发生了哪个中断。很多事情需要做,中断的发生就是这么一个开关。信号在总线上按照同一个时钟周期流着,经过了一个与门,就打开了。

如果说检查,一个开关算什么检查,除非电流可以往回跑。除非水库开闸淹死了人,那责任是水的,而不是开闸的。

#32 楼 @fleuria 51 没有 IF 标志位,谢谢

#32 楼 @fleuria 你说的那个应该是 51 里面的 EA,开关 CPU 总中断的,这 TMD 是中断控制标志位好不好。和中断标志位是两码事好不好。

禁不住要咆哮体了。。

#34 楼 @ninehills 算了,我也想骂人了。觉得在这个世纪能见到 51 很二逼而已,交流不在一个层面,多说无益。晚安。

36 楼 已删除

#29 楼 @jiffies 意思就是“addListener,bind,槽,回调,事件,消息”这些跟中断没有关系,它们不是用中断实现的

好热闹啊

#32 楼 @fleuria 那请你解释一下一个最基本的机器指令能被中断么,显然不能。为什么不能,是人规定设计的,必须要在一个指令或周期完毕再处理中断,或者你说的打开某个门。这是不是一个循环的规范流程?

#40 楼 @jiffies 抱歉还真可以,Page Fault 就是的。

不得不说~ 用 Ruby 这么久,还能想到中断这个低级的玩意儿,楼主也算是很有想法了,顶你!

#39 楼 @reus 本来不了解中断原理对写程序一点影响都没有,CPU 硬件实现的

至于@fleuria 强烈质疑的,是这么一段话,我相信只要上过微机组成原理课的人,都能知道这句话的正确性与否:

CPU 在执行完当前程序的每一条指令后,都会去确认在执行刚才的指令过程中中断控制器是否发送中断请求过来(51 是检查中断标志位,总之是 CPU 主动去 check),如果有那么 CPU 就会在相应的时钟脉冲到来时从总线上读取中断请求对应的中断向量。(这个指硬件中断的触发方法,先不考虑软件中断)

51 因为有多周期指令,我才说了#15 楼的那段话。

#41 楼 @fleuria 你没搞错吧,算了今晚先讨论到这,你可能对操作系统很了解 睡觉先

#41 楼 @fleuria 你这更扯了。CPU 流水线上的一个基本指令,比如 MOV,比如 ADD,怎么可能会被中断呢。。还有 ADD 一半的情况出现?

这是原子操作啊

46 楼 已删除

#46 楼 @ninehills 这些操作是可能产生缺页中断的啊

#47 楼 @luikore 那好,你给我举出个在单处理器系统中能够打断单条指令的例子出来。

#48 楼 @reus 但是普通中断只能发生在指令之间啊。你得等指令完成后才能去处理中断。就算是缺页中断,也并没有把指令给打断,而是要重新执行指令

#49 楼 @ninehills 例如 add 带内存操作数时,CPU 读入 add 指令,在执行中发现内存地址不在 cache 中,就中断了这个指令产生一个 page fault,跑去载内存后再回来重新执行 add,如果你是操作系统,就可以注册一个 page fault 的 handler,然后就可以选择不重新继续执行这个 add 之类的。。

#48 楼 @reus 指令访问了无效的地址空间引发的中断,指令本身并没有被执行,而是等待被重新执行。如果坚持说这个打破了指令的原子性。。。是不是有点勉强?

#51 楼 @luikore 这个就叫打断了指令的原子性有点勉强了。指令执行一般分三步:取指令、分析指令、执行指令。

而缺页中断出现在第二步,分析指令时就会出现,指令还没执行呢。。。这也是很多教科书不因为缺页中断就说指令没有原子性的原因。

先不提流水线,很多 CPU 指令的执行就包括 fetch, decode, ALU, access memory, update register, update pc 这几步,从定义看就是执行被打断了 ...

从化学反应的角度看,原子是不可分的,但是核反应就不一样了 ...

bug fix: 呃.. 化学反应里原子也是可分的

为什么,为什么要在 ruby 坛子里面, 讨论这么底层的问题,我根本就看不懂。

#52 楼 @ninehills 总之“一个最基本的机器指令能被中断"。有没有打破原子性,取决于你对“原子性”这个概念的定义,“能被中断”和“原子操作”不是同一个概念

#54 楼 @luikore 这个太较真了,那还不如提多核处理器中要想原子性还得给总线 LOCK 住。。。虚拟内存、多核这些,引入到像 lz 这样的基础讨论贴中不太合适。

#53 楼 @ninehills 你这么说也可以,执行指令不能打断,但指令执行可以打断 ...

#56 楼 @reus 好吧,只是定义不同。但至少我见过的教科书都声称中断是发生在指令之间的,然后指令是原子性的,证明主流思想还是将某些特殊情况排除在定义之外,特例特办。

在我看来,CPU 每次执行一条指令后,都要 check 中断状态是很 SB 的,CPU 原子指令与中断并不会冲突,因为 中断第一件事情,就是保存状态,研究中断是很 10 前的事情,现在完全没有去了解了;不过 ·@fleuria 的认知明显更正确

无语。

花点钱买个 demo 板 + jtag, 跟一下都明白了。

对我接触的几种 cpu 而言:

arm7tdmi, msp430, cortexa9, cortex-m0

中断就是这个意思:

当产生中断时,cpu 会看中断向量表,并保存目前的环境,然后跳转,执行中断向量所指的指令。执行完,回到刚才运行的语句,运行下一句。

多核没接触过。

#60 楼 @hysios 你说的对,用软件的轮询想象 cpu 的操作是很傻的,一块 fpga 所做的并发比纯软件强大的的多,不要认为 cpu 内部会轮询什么,cpu 不会轮询!

#35 楼 @fleuria 别看不起 51, 其实差不多都是一个道理。而且嵌入式这玩意,用 51 赚大钱的有的是... 51 全懂了,arm 也差不多了,ps: 我没真玩过 51, 玩的 arm 居多。

#26 楼 @ninehills 现代的 x86 以及 x86_64 CPU 早已不是单纯的冯诺依曼结构了,事实上,核心部分是相当纯粹的哈佛结构。不然你也不会看到 L1 Cache 是区分数据和指令的。

http://en.wikipedia.org/wiki/Athlon_64#Sledgehammer_.28130.C2.A0nm_SOI.29

#66 楼 @jinleileiking 恩,确实不该黑 51。如果能把 51 学好,也断不至于说出那些偏颇的话出来。

但以后用 51 赚钱会越来越难。直到前两年我还对手持设备用上多核处理器的可行性感到十分怀疑,可是现在的手机都四核了。未来是现代体系结构的,它们需要面对更加复杂的问题。考虑这么多问题应接不暇的时候,谈本质其实是想偷懒。

#6 楼 @jiffies 你把概念搞乱了,这个检查不需要轮询 (轮询在这里是指用一条指令去检查一下寄存器),这种检查是在电路层面解决的。你就把它当成一个触发器。

当然了 CPU 完全可以不实现中断,不得不说还是能买到这种类型的 CPU 的。

假如你非要说是轮询,那它就是轮询了。反正不是主动就对了,这就是个硬件层面的逻辑,没有主动或者被动的概念。

谁要能从 8086 的门电路一路往上解释到 IOCP 就牛叉了。就像我面试老喜欢问人一个问题:“百度一下,你觉得都发生了什么?”,感谢这个问题让我开始回忆单片机。

#68 楼 @fleuria 这个讨论可一告一段落了,现在工作用不到那么底层的。但是理解底层肯定是有好处的。 你说考虑这么多问题应接不暇的时候,谈本质其实是想偷懒。我完全不能赞同,如果这样就只能见到一个一个纷繁复杂的问题而不知从何下手,而反观大师们解决问题都是从本质思考的。 问题讨论到这里有不少收获,但是我的想法没有完全确立,你的观点也没说服我。以后有时间有兴趣再思考啦。 谢谢你参与讨论

#69 楼 @bhuztez 软件硬件没有明显界限。轮询是一种模型。至于主动还是什么没有深入思考,觉得跟哲学也很有关系。有时间再考虑了。感谢参与讨论

#65 楼 @jinleileiking 我不能同意,电路的设计也是编程,它被设计完成这么一个循环流程操作。我觉得不要把计算机想的太神奇,它诞生还没有一个人的寿命长,基本思想是朴素的。谢谢参与讨论

@jiffies 问题在于也许你觉得需要循环来解决问题,但实际并不需要。

看过....感觉这个应该是一个硬件级的问题,其实大家讨论的时候主要都是一个底层上的"主动轮询"使 CPU 感知中断,还是中断触发信号存在迫使 CPU 感知...这个没研究过硬件..不懂~不过感激大牛们的讨论

抱歉挖一下坟,我的看法和楼主一致,下面是我的总结: 中断其实是硬件轮询,只是恰好利用上 cpu 的机制而产生一种比轮询效率高的错觉,因为 cpu 是本身是轮询的,即隔一段时间进行分片调度切换上下文,这时候正好可以取检查有没有事故发生了。中断其实把所有种类的轮询都统一交给 cpu 处理了 (类似线程池这样的概念),这样就不用不停的分心去检查很多个 io 信号,造成 cpu 空置浪费,让本来多次的轮询合并变为一次轮询(而这个轮询本身是必须的,相当于没给钱有人免费给你装了一个电话)

需要 登录 后方可回复, 如果你还没有账号请 注册新账号