指北 | 聊聊中断机制

什么是中断


中断实际上是一种“中断”事件,中断具体表明什么意思须要考虑它所处的上下文环境参照对象是谁。考虑事件,咱们能够简单把中断抽象为这样一种模型:图片数组

当咱们分析某种中断事件时,咱们须要搞清楚这四个对象:异步

中断源ide

  • 中断源是谁
  • 中断源在什么条件下触发中断
  • 中断源如何触发

中断信号spa

  • 信号具体指的是什么
  • 信号是否须要存储
  • 如何存储

中断控制器操作系统

  • 中断信号的管理

好比说中断源发送的信号是否屏蔽,信号是否可被中断处理器重复处理,信号的处理是否有优先级...线程

中断处理器设计

  • 如何获取到信号
  • 拿到信号作什么样的操做
  • 处理完信号后作什么样的操做

在实际的中断事件中,并不必定恰好有上面提到的这四类对象,可能更复杂可能更简单化。可是当咱们考虑中断事件时,须要明确应该有相似功能的“对象”承担这样的逻辑。code

下面咱们主要围绕操做系统的中断机制Java的中断机制如何设计一个异步线程间的中断系统这三部分简单探讨下。orm

操做系统的中断机制


与操做系统有关的中断,一般是指:程序在执行过程当中,遇到急需处理的事件时,暂时停止CPU上现行程序的运行, 转去执行相应的事件处理程序,待处理完成 后再返回原程序被中断处或调度其余程序执行的过程。对象

按照中断事件自己的不一样,能够划分为处理器以外的中断事件异常,系统异常

处理器以外的中断事件

指由外围设备发出的信号引发的,与当前运行指令无关的中断事件。示意图以下:图片

咱们分别以上述四个对象来看:

  • 中断源

中断源:外部设备,如打印机,键盘,鼠标等。

触发条件:如外围设备报告I/O状态的I/O中断;外围设备发出的对应信号中断,如时钟中断,键盘/鼠标对应信号的中断,关机/重启动中断等。

触发方式:由外部设备向中断控制器发出中断请求IRQ。

  • 中断信号

也就是说中断源通知给中断控制器的是什么。

能够是经过一条信号线上产生特定的电平(利用高低电平表示是否中断两种状态),也能够在总线上发送特定消息或者消息序列,也能够是在中断寄存器中设置已发生的中断状态等。

  • 中断控制器

CPU中的一个控制部件,包括 中断控制逻辑线路和中断寄存器。负责中断的发现和响应。

也就是说负责检查中断寄存器中的中断信号,当发现中断时让CPU切换当前进程程序,去处理中断程序。响应示意图以下:

图片

  • 中断处理器

指的是CPU接收到不一样的中断信号该怎么处理。包括“中断处理过程”和“恢复正常操做”两部分。

1.中断处理过程

首先CPU须要将当前运行进程的上下文保存,从中断进程中分析PSW,肯定对应的中断源和执行对应的中断处理程序。

小贴士:PSW(Program Status Word): 是指在电脑中,一段包含被操做系统使用的程序状态信息的内存或硬件区域。通常用一个专门的寄存器来指示处理器状态。能够理解为咱们上面提到的中断信号存储装置.

2.恢复正常操做

当中断程序执行完毕,接下来执行哪一个进程由进程调度决定,由调度策略决定是否调度到中断执行前的进程。

较为完整的中断响应流程图以下:图片

异常 和 系统异常 这两类中断事件主要属于处理器执行特定的指令引发的中断事件。和上述硬件外围设备引发的中断事件的中断源不一样,中断的发起,控制和处理主要是由操做系统的指令逻辑和线路来承担。是一种同步的处理操做,而外部中断是由外部设备发起,是一种异步的处理操做。下面咱们简要介绍下。

异常

异常指当前运行指令引发的中断事件。包括错误状况引发的故障,如除零算数错误,缺页异常;也包括不可恢复的致命错误致使的终止,一般是一些硬件错误。

  • 异常的处理

对于故障的处理,根据故障是否可以被恢复,故障处理程序要么从新执行引发故障的指令,要么终止。

对于终止的处理,处理程序将控制返回给一个abort例程,该例程会终止这个应用程序。

系统异常

系统异常指执行陷入指令而触发系统调用引发的中断事件,如请求设备、请求I/O、建立进程等。

  • 系统调用的处理

这种有意的异常,称为陷阱处理。处理完成后陷阱程序会将控制返回给应用程序控制流的下一条指令。图片

总结一下,操做系统的中断类别行为以下:图片

好了,大头总算完了。由于小姐姐主要是Java码农,下面将主要介绍和Java相关的中断语义是什么。

Java的中断机制


理解了上面操做系统的中断以后,Java的中断机制就很easy了 :D

Java中断指的是 A线程发送中断信号给B线程,B线程再根据本身当前执行程序中的中断处理逻辑决定如何响应。嗯,就这么简单~

咱们来稍微分析一下中断事件中的“四个对象”:

  • 中断源

中断源:A线程

中断触发条件:A线程说了算

中断源触发方式:A线程中调用threadB#interrupt()方法.

实现机制也不难,扯淡以前咱们先思考两个问题:

问:

问题1: 线程之间如何通讯,A线程的中断信号怎么才能传给线程B?

问题2: 线程的状态有Running,Blocked,Waiting等,当线程B处在不一样的状态下,如何响应中断信号?

答:

问题1:这种状况下线程之间通讯用共享内存就能够了。只须要给每一个线程都设置一个中断标示位, 这样A线程中调用threadB#interrupt()方法,实际操做是把B线程的中断标示位设置为true。信号就算传递过去了

问题2:当B线程处于非阻塞状态时,B线程能够在本身须要处理中断逻辑的地方判断中断标示位是否为true,就能够响应处理中断。

可是当B线程处于阻塞状态时,这特么怎么查本身的中断标示位啊?

JVM帮帮忙,当B线程阻塞在Object#wait(),Thread#join(),Thread#sleep(),实现了InterruptibleChannel接口的IO操做 和Selector接口的select()这些操做时,JVM会让B线程立刻抛出异常或被唤醒,从而让B线程能够选择是否响应中断。

由于是Java实现的中断机制,中断标示位的设置也是JVM帮作的。

  • 中断信号

信号:线程的中断标示位。

存储方式:JVM说了算。

  • 中断控制器

JVM控制了信号的存储和让线程B及时唤醒。线程B控制了本身的中断响应逻辑,什么时候响应,如何响应。

  • 中断处理器

获取信号:B线程可经过调用threadB#isInterrupted()方法得知本身是否被中断,也就是经过本身主动拉取信号(poll方式)。

如何处理信号:B线程说了算。

处理完信号后作什么:B线程说了算。

Java的线程中断机制设计的比较灵活,使用者能够决定中断处理的较多事情。

总结下Java中和中断有关的方法:图片

在JDK中,线程池的ThreadPoolExecutor#shutdownNow()方法就是调用workers线程数组中每一个worker线程的interrupt()方法来关闭线程池。

这样暴力关闭线程会存在一个问题,线程池并不知道worker线程的中断执行状况,若是worker线程忽略了中断信号,那可能致使当前任务还在执行,发生意想不到的结果。

设计一个异步线程间的中断系统


咱们再来看Java的中断机制,它其实只是提供了A线程给B线程发送中断信号。

  • A线程并不能知道B线程的中断处理结果。
  • 若是A线程拿不到B线程的thread对象时,也就无法发送中断信号。

考虑这么一种场景:当咱们执行一个大任务Task1时,它太大了。咱们把它分为Task2Task3,丢进线程池中处理。它们一样很大,咱们把他们分别分为Task4Task5Task6Task7,一样丢进线程池中处理。

图片

若是此时咱们想取消task1的执行,如何保证图中全部的worker都成功取消对应task的执行?

  • 需求分析

当咱们取消task1时,想要作的是取消全部task程序的继续运行,而且可以得到全部task程序的取消结果

为何要强调task程序呢?由于worker可能并非只为一个task工做啊..好比task2的worker,它把task4和task5丢进线程池,就算完事了。若是咱们把取消task1变为取消task1的worker线程,可能会致使worker线程当前运行的非task1程序的失败。

咱们不太容易知道全部task程序当前运行的线程,咱们还须要知道全部task程序的运行结果。

  • 设计思路

只用Java的中断机制是知足不了咱们的需求的,可是咱们能够借鉴它的思路:

1.它用中断标示位记录线程是否应该中断

2.当线程阻塞时能够抛出异常

咱们这里要终止的是全部task程序的执行,因此咱们须要设计与task 强绑定的中断标示位,能够有未中断,中断中,中断成功中断失败四种 状态。为了让全部的线程均可以访问到,定义成全局共享变量就能够。

图片

中断源和中断处理器之间经过task的中断标示位来通讯就能够。若是运行task程序的线程一直在阻塞,怎么唤醒它让它判断中断状态 呢?

对于咱们这个场景,咱们很难知道当前运行task程序的阻塞线程是谁。。能作的只是多安插中断判断点,这样当阻塞线程醒来后,再次判断task 的中断标示位,就能够响应中断了。

另:

唤醒一个线程只有Java的中断机制能够作,可是若是当前worker不是你能管理的线程池,那么它的中断处理逻辑就控制不了。

若是你能控制运行task的全部worker,并且worker在执行task时是同步得到结果的。那么能够结合与task强绑定的中断标示位Java中断机制来作,这里前者的做用更可能是充当获取到任务的中断结果的做用。