精华内容
下载资源
问答
  • linux内核里,如果驱动申请注册中断的时候没有特别的指定,do_irq中断响应时候开启中断的,如果驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被...
  • 中断

    2017-04-20 00:05:49
    当单片机正在执行程序的时候,突然某个按键按下了(产生外部中断),单片机就必须得去处理那个按键(中断响应),看看发生了什么事,按键处理完后继续回来执行程序(中断的返回)。同样,单片机正在执行程序的...

    当单片机正在执行程序的时候,突然某个按键按下了(产生外部中断),单片机就必须得去处理那个按键(中断的响应),看看是发生了什么事,按键处理完后继续回来执行程序(中断的返回)。

    同样,单片机正在执行程序的时候,内部的定时器溢出(定时器后面会单独讲到),或者检测到单片机的电压低于正常值等等(单片机内部产生的中断叫内部中断),单片机就得去处理这些事情,然后再返回来。
    

    在单片机里面,中断是有特殊的功能寄存器控制的,单片机里面一共有两个中断,一个是中断0,一个是中断1 ,和两个定时器T0,T1,定时器就是你打开它后,它会自动数数,当数到你给它限定的值时,它就会溢出,产生中断让CPU处理(就像一个桶,你打开水龙头后,水越来越多,当达到你需要的水位时,就会产生中断叫你去处理它)。这些我们先不深入了解他是什么东西,我们只需知道中断是用下面这几个关键词控制的就行了:


    IT0 声明外部中断0的类型,IT0=1是边沿触发,0是电平触发
    边沿触发就是当检测到外部电平发生变化,即由低变高,或者由高变低时,就会产生一个中断
    电平触发就是检测到高电平或者低电平时,产生中断

    IE0 外部边沿触发产生中断后,它的值会变1,当CPU响应后,会自动变为0

    IT1 和IT0一样的含义
    IE1 和IT0一样的含义

    EX0 外部中断0控制器,EX0=1是允许外部中断,0是禁止外部中断,也就是不理会外部中断
    ET0 这个是定时器中断控制器,ET1=1是允许定时器产生中断,0是禁止
    EX1,ET1的含义跟上面的都一样。
    EA 总中断控制器,1是允许有中断产生,0是禁止所有中断,就算天打雷劈也不理会

    *另外,还有一个中断优先级的控制器,就是控制是去帮妈妈拿东西的优先级高还是去撒尿的优先级高。

    PX0 外部中断0的优先级控制,假如内外都产生了中断,1就是优先处理外部中断,0就是优先处理内部中断

    PT0 定时器0优先级控制器,1就是优先相应定时器0

    PT1 定时器1优先级控制器,1就是优先相应定时器1

    还有个概念,就是***中断请求的撤销***,也就是说,产生中断后,会产生一个中断请求,为1,当CPU处理完中断后,必须清除这个请求,不然CPU又会认为这个中断没有处理又跑去处理它……
    
    对于两个定时器产生的中断,当CPU响应后,会自动清除TF0,TF1这两个定制器中断请求,处理完后就跳出来,回到原来的地方继续执行。
    

    对于外部中断INT0,INT1,如果中断类型是边沿触发,单片机会自动清除中断请求IE0,IE1

    若是电平触发,如果有一个电平,使中断产生后,这个电平仍然还保持着,那么这个电平还会触发中断,这样CPU就死在中断的石榴裙下出不来了。。。

    实验中按照助教所说,中断可能会产生累积,比如说在执行当前中断的过程中,外部又发生了中断,那么它就会排队,于是使用了CLR IE0来清楚中断执行过程中发生的扰动。

    /转载/

    展开全文
  • 目态程序运行的时候,发生中断中断装置响应中断,进入操作系统,操作系统进行中断处理,处理过程中如果发生优先级更高的中断,就会发生中断嵌套,中断乃至嵌套中断的现场保存在什么地方?系统栈,大家一定记住;...

    目态程序运行的时候,发生中断,中断装置响应中断,进入操作系统,操作系统进行中断处理,处理过程中如果发生优先级更高的中断,就会发生中断嵌套,中断乃至嵌套中断的现场保存在什么地方?系统栈,大家一定记住;中断处理过程中,如果因为等待或者被剥夺处理机,现行进程会进入等待或就绪状态,处理机会分给另外一个就绪进程,此处会发生进程切换,那么,进程切换时的现场保存在什么地方呢?PCB,再次请大家记住,中断的现场保存在系统栈,切换的现场保存在PCB。

    3.2.3节的中断处理逻辑图,是想进一步说明,目态进程因中断进入操作系统之后,可能会多次等待,多次被剥夺处理机,可能既有等待又有剥夺发生,等待或剥夺时现行进程现场保存到其PCB中;以后被唤醒并获得处理机时由其PCB中恢复现场,继续运行。中断处理完,如果是嵌套中断,由系统栈恢复现场回到上层中断,如果不是嵌套中断,由系统栈恢复现场回到目态。这个中断处理逻辑给出了中断处理的完整过程,从中断发生,到处理完毕。

    以read为例理解此过程:在这里插入图片描述
    传送第15块发生中断
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • linux内核里,如果驱动申请注册中断的时候没有特别的指定,do_irq中断响应时候开启中断的,如果驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被...

    关于中断嵌套:

    在linux内核里,如果驱动在申请注册中断的时候没有特别的指定,do_irq在做中断响应的时候,是开启中断的,如果在驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被立即处理,还是被pending,等当前中断处理完成后,再做处理。
    在2.4和2.6内核里,关于这一块是否有什么不同。

    一般申请中断的时候都允许开中断,即不使用SA_INTERRUPT标志。如果允许共享则加上 SA_SHIRQ,如果可以为内核熵池提供熵值(譬如你写的驱动是ide之类的驱动),则再加上 SA_SAMPLE_RANDOM标志。这是普通的中断请求过程。对于这种一般情况,只要发生中断,就可以抢占内核,即使内核正在执行其他中断函数。这里有两点说明:一是因为linux不支持 中断优先级,因此任何中断都可以抢占其他中断,但是同种类型的中断(即定义使用同一个 中断线的中断)不会发生抢占,他们会在执行本类型中断的时候依次被调用执行。二是所谓 “只要发生中断,就可以抢占内核”这句是有一定限制的,因为当中断发生的时候系统由中断门 进入时自动关中断(对于x86平台就是将eflags寄存器的if位置为0),只有当中断函数被执行 (handle_IRQ_event)的过程中开中断之后才能有抢占。 对于同种类型的中断,由于其使用同样的idt表项,通过其状态标志(IRQ_PENDING和 IRQ_INPROGRESS)可以防止同种类型的中断函数执行(注意:是防止handle_IRQ_event被重入, 而不是防止do_IRQ函数被重入),对于不同的中断,则可以自由的嵌套。因此,所谓中断嵌套, 对于不同的中断是可以自由嵌套的,而对于同种类型的中断,是不可以嵌套执行的。 
    以下简单解释一下如何利用状态标志来防止同种类型中断的重入:
    当某种类型的中断第一次发生时,首先其idt表项的状态位上被赋予IRQ_PENDING标志,表示有待处理。 然后将中断处理函数action置为null,然后由于其状态没有IRQ_INPROGRESS标志(第一次),故将其状态置上IRQ_INPROGRESS并去处IRQ_PENDING标志,同时将action赋予相应的中断处理函数指针(这里是一个重点,linux很巧妙的用法,随后说明)。这样,后面就可以顺利执行handle_IRQ_event进行中断处理,当在handle_IRQ_event中开中断后,如果有同种类型的中断发生,则再次进入do_IRQ函数,然后其状态位上加上IRQ_PENDING标志,但是由于前一次中断处理中加上的IRQ_INPROGRESS没有被清除,因此这里无法清除IRQ_PENDING标志,因此action还是为null,这样就无法再次执行handle_IRQ_event函数。从而退出本次中断处理,返回上一次的中断处理函数中,即继续执行handle_IRQ_event函数。当handle_IRQ_event返回时检查IRQ_PENDING标志,发现存在这个标志,说明handle_IRQ_event执行过程中被中断过,存在未处理的同类中断,因此再次循环执行handle_IRQ_event函数。直到不存在IRQ_PENDING标志为止。

    2.4和2.6的差别,就我来看,主要是在2.6中一进入do_IRQ,多了一个关闭内核抢占的动作,同时在处理中多了一种对IRQ_PER_CPU类型的中断的处理,其他没有什么太大的改变。这类IRQ_PER_CPU的中断主要用在smp环境下将中断绑定在某一个指定的cpu上。例如arch/ppc/syslib/open_pic.c中的openpic_init中初始化ipi中断的时候。

           其实简单的说,中断可以嵌套,但是同种类型的中断是不可以嵌套的,因为在IRQ上发生中断,在中断响应的过程中,这个IRQ是屏蔽的,也就是这个IRQ的中断是不能被发现的。

           同时在内核的临界区内,中断是被禁止的

    关于do_IRQ可能会丢失中断请求:

    do_IRQ函数是通过在执行完handle_IRQ_event函数之后判断status是否被设置了IRQ_PENDING标志来判断是否还有没有被处理的同一通道的中断请求。 但是这种方法只能判断是否有,而不能知道有多少个未处理的统一通道中断请求。也就是说,假如在第一个中断请求执行handle_IRQ_event函数的过程中来了同一通道的两个或更多中断请求,而这些中断不会再来,那么仅仅通过判断status是否设置了IRQ_PENDING标志不知道到底有多少个未处理的中断,handle_IRQ_event只会被再执行一次。
    这算不算是个bug呢? 不算,只要知道有中断没有处理就OK了,知道1个和知道N个,本质上都是一样的。作为外设,应当能够处理自己中断未被处理的情况。
     
    不可能丢失的,在每一个中断描述符的结构体内,都有一个链表,链表中存放着服务例程序

    关于中断中使用的几个重要概念和关系:

    一、基本概念

    1.

      产生的位置 发生的时刻 时序
    中断 CPU外部 随机 异步
    异常 CPU正在执行的程序 一条指令终止执行后 同步

    2.由中断或异常执行的代码不是一个进程,而是一个内核控制路径,代表中断发生时正在运行的进程的执行

    中断处理程序与正在运行的程序无关

    引起异常处理程序的进程正是异常处理程序运行时的当前进程


    二、特点

    1.(1)尽可能快

    (2)能以嵌套的方式执行,但是同种类型的中断不可以嵌套

    (3)尽可能地限制临界区,因为在临界区中,中断被禁止


    2.大部分异常发生在用户态,缺页异常是唯一发生于内核态能触发的异常

    缺页异常意味着进程切换,因此中断处理程序从不执行可以导致缺页的操作


    3.中断处理程序运行于内核态

    中断发生于用户态时,要把进程的用户空间堆栈切换到进程的系统空间堆栈,刚切换时,内核堆栈是空的

    中断发生于内核态时, 不需要堆栈空间的切换


    三、分类

    1.中断的分类:可屏蔽中断、不可屏蔽中断

    2.异常的分类:

    分类 解决异常的方法 举例
    故障 那条指令会被重新执行 缺页异常处理程序
    陷阱 会从下一条指令开始执行 调试程序
    异常中止 强制受影响的进程终止 发生了一个严重的错误

    四、IRQ

    1.硬件设备控制器通过IRQ线向CPU发出中断,可以通过禁用某条IRQ线来屏蔽中断。

    2.被禁止的中断不会丢失,激活IRQ后,中断还会被发到CPU

    3.激活/禁止IRQ线 != 可屏蔽中断的 全局屏蔽/非屏蔽

    可以有选择地禁止每条IRQ线。因此,可以对PIC编程从而禁止IRQ,也就是说,可以告诉PIC停止对给定的IRQ线发布中断,或者激活它们。禁止的中断时丢失不了的,它们一旦被激活,PIC就又把它们发送到CPU。这个特点被大多数中断处理程序使用,因为这允许中断处理程序逐次地处理同一类型的IRQ

    假定CPU有一条激活的IRQ线。一个硬件设备出现在这条IRQ线程上,且多APIC系统选择我们的CPU处理中断。在CPU应答中断前,这条IRQ线被另一个CPU屏蔽掉;结果,IRQ_DISABLED标志被设置。随后,我们的CPU开始处理挂起的中断;因此,do_IRQ()函数应答这个中断,然后返回,但没有执行中断服务例程,因为它发现IRQ_DISABLED标志被设置了,因此,在IRQ线禁用之前出现的中断丢失了。

    为了应付这种局面,内核用来激活IRQ线的enable_irq()函数先检查是否发生了中断丢失,如果是,该函数就强迫硬件让丢失的中断再产生一次

    它们最大的不同是上半部分不可中断,而下半部分可中断


    五、中断描述符表IDT

    1.基本概念

    中断描述符表是一个系统表,它与每一个中断或异常向量相联系,每一个向量在表中有相应的中断或异常处理程序入口地址。

    在允许发生中断以前,必须适当地初始化IDT

    TSS只能位于GDT中,IDT能位于内存的任何的地方


    2.中断描述符

    硬件提供的中断描述符:

    (1)任务门:中断信号发生时,必须取代当前进程的那个进程的TSS选择符存放在任务门中

    (2)中断门:包含段选择符和中断处理程序的段内偏移

    (3)陷阱门:与中断门的唯一区别是,通过中断门进入服务程序后,自动关中断,而通过陷阱门进入服务程序不自动关中断

    Linux中使用的中断描述符:

    中断描述符的类型 用户态能否访问 用户态的访问方式 能激活的程序
    中断门   所有的Linux中断处理程序
    系统门 into、bound、int $0x80 向量号为4,5,128的三个Linux异常处理程序
    系统中断门 int 3 与向量3相关的异常处理程序
    陷阱门   大部分Linux异常处理程序
    任务门   Linux对Double fault异常的处理程序
    Linux中的系统门、系统中断门、陷阱门使用的都是硬件中的陷阱门

    Linux利用中断门处理中断,利用陷阱门处理异常

    Double fault是唯一用任务处理的异常


    3.中断向量与中断和异常的关系

    (1)每个中断和异常是由0-255之间的一个数来标识的,这个数就是1中的中断向量

    (2)大约有20种异常,内核为每一个异常分配了一种中断/异常向量分别是0-19

    (3)0x80是系统调用的中断向量

    (4)32-255是内核为什么中断分配的中断向量。然而,224个中断向量显然不够,因此系统为每个中断向量设置一个队列,根据每个中断源所使用的中断向量,将其中断服务程序挂到相应的队列中。中断发生时,先执行与中断向量相对应的一段总服务程序,再根据具体的中断源设备号在其所属的队列找到特定的中断服务程序加以执行。


    4.中断向量、与中断向量相对应的总服务程序、某个中断源的中断服务程序之间的关系如图所示:

    (1)irq_desc是中断向量描述符队列(中断描述符是INT的一项,中断向量描述符是一个数据结构,用于描述与中断向量相关的服务程序)

    (2)irq_desc_t是中断向量描述符的数据结构

    (3)irqaction是挂在某个中断向量的具体的中断服务程序的描述符,组成一个队列

    (4)hw_irq_controller是这个中断向量的总服务程序



    六、IDT的初始化

    1.两次初始化

      运行模式 初始值 使用者
    第一次 实模式 空处理程序 BIOS例程
    第二次 保护模式 有意义的中断处理程序或异常处理程序 Linux系统


    2.在IDT表的初始化完成之初,每个中断处理队列都是空的,此时即使打开中断并且某个外设中断真的发生了,也得不到实际的服务,因为没有执行具体的中断处理程序。

    真正的中断服务要到具体设备的初始化程序将其中断处理程序ISR挂入某个中断请求队列后才会发生


    3.在允许发生中断以前,必须适当地初始化IDT


    七、激活中断或异常(以下内容都是由硬件自动完成)

    1.确定与中断或异常相关的中断向量号

    中断:硬件设备控制器通过IRQ向CPU发出信号,中断管制器把接受到的信号转换为中断向量号i

    异常:对于软件指令发出或产生的异常,CPU会差别归类错误的类别,这个类别号就是中断向量

    2.IDT第i项 -----> 段选择符 ----->段描述符 -----> 段基址

    3.IDT第i项 -----> 偏移量

    4.段基址 + 偏移量 -----> 中断处理程序第一条指令的地址

    5.在栈中保存EFLAGS、CS、EIP的内容

    6.如果异常产生了一个出错码,把它保存在栈中

    7.装载CS、EIP,其值分别是2-段选择符和4-偏移量,由这两个寄存器可得到中断或异常处理程序第一条指令的地址



    八、找到中断或异常处理程序的第一条指令后,跳转这到这一指令的过程

    1.中断

    (1)在当前进程的内核堆栈中保存IRQ的值,为什么与系统调用号区分,保存的是-n

    (2)在当前进程的内核堆栈中保存寄存器的值:SAVE_ALL

    EFLAGS、CS、EIP、SS、ESP不包括在内,因为它们由控制单元自动保存(见七-7)

    (3)把栈顶的地址存放到EAX中

    (4)把用户段的选择符装到DS和ES中

    (5)调用do_IRQ(),地址保存在CS、EIP中(见七-7)

    (6)为正在给IRQ线服务的PIC(中断控制器)一个应答,这将允许PIC进一步发出中断

    (7)执行共享这个IRQ的所有设备的ISR(总服务程序称为IRQ,某个设备的具体的服务程序称为ISR

    (8)跳到ret_from_intr()的地址后终止

    (6)(7)(8)都是在(5)中被调用的,见十

    2.异常

    (1)如果异常发生时,控制单元没有自己把一个出错码压出栈中(见七-6),则压入一个空值。

    这个“凑数”的出错码不在正常的出错码应该在的位置,以下-步是为了把它调整到它应该在的位置

    (3)把异常处理程序的地址压入栈中

    (4)把异常处理程度可能用到的寄存器保存到栈中

    (5)把栈中位于ESP+36处的硬件出错码拷贝到EDX中,给栈中这一位置存上-1

    (6)把保存在栈中ESP+32位置的异常处理程序的地址装入EDI中,给栈中的这一位置写入ES的值

    (7)把栈当栈顶拷贝到EAX中

    (8)把用户段的选择符装到DS和ES中

    (9)调用地址在EDI中的异常处理程序


    九、从中断或异常处理程序返回的过程

    1.跳转到用于返回的代码的入口点

    (1)中断ret_from_intr()

    (2)异常:ret_from_exception()

    2.把当前线程描述符的地址装载到EBP

    3.根据栈中的CS和EFLAGS确定要返回到用户态还是内核态

    4.如果有进程调度请求则调度

    5.通过执行iret指令结束控制,被中断的程序重新开始执行


    十、总的中服务务程序IRQ

    1.为正在给IRQ线服务的PIC(中断控制器)一个应答,这将允许PIC进一步发出中断

    2.发生以下任何一种情况,则返回

    (1)相应的IRQ线被禁止

    (2)另一个CPU正常处理这类中断

    (3)没有相关的ISR

    3.执行共享这个IRQ的所有设备的ISR

    4.检查是否有可延迟函数在等待执行,如果有do_softirq()

    5.ret_from_intr()

    十一、中断服务例程
    一个中断服务例程(ISR)实现一种特定设备的操作。当中断处理程序必须执行ISR时,它就调用hand_IRQ_event()函数。

    十二、IRQ线的动态分配
    在激活一个准备利用IRQ线的设备之前,其相应的驱动程序调用request_irq()。这个函数建立一个新的irqaction函数,并用参数值初始化它。然后调用setup_irq()函数把这个描述符插入到适合的IRQ链表。如果setup_irq()返回一个出错码,设备驱动程序中止操作,这意味着IRQ线已有另一个设备所使用,而这个设备不允许中断共享。当设备操作结束时,驱动程序调用free_irq()函数从IRQ链表中删除这个描述符,并释放相应的内存区。
    request_irq()
    free_irq()

    1.Linux把紧随中断要执行的操作分为三类

      特点 处理方法 举例
    第一类 紧急的 在禁止可屏蔽中断的情况下立即执行 修改设备和处理器同时访问的数据结构
    第二类 非紧急的 在开中断的情况下立即执行 修改那些只有处理器才会访问的数据结构(例如,按下一个键后读扫描码)
    第三类 非紧急可延迟的 由独立的函数来执行 把缓冲区的内核拷贝到某个进程的地址空间

    2.把可延迟中断从中断处理程序中抽出来,由独立的函数来执行,有助于使内核保持较短的响应时间


    3.Linux2.6使用可延迟函数和工作队列来处理可延迟中断,这两个都是内核函数。


    二、可延迟函数

    1.可延迟函数包括软中断和tasklet,tasklet是在软中断之上实现的

    tasklet是I/O驱动程序中实现可延迟函数的首选方法。

    tasklet建立在HI_SOFTIRQ和TASKLET_SOFTIRQ这两个软中断之上

    几个tasklet可以与同一软中断相关联,每个tasklet执行自己的函数

      分配方式 并发性 可重入性
    软中断 编译时静态分配 可以并发地在多个CPU上运行 必须是可重入的,并明确地使用自旋锁保护其数据结构
    tasklet 运行时动态分配 相同类型的tasklet总是被串行地执行。不同类型的tasklet可以在几个CPU上并发地执行 不必是可重入的

    2.由给定CPU激活的一个可延迟函数必须在同一个CPU上执行

    可延迟函数执行时不允许内核抢占,因为从一个CPU移到另一个CPU的过程需要将进程挂起


    3.中断与软中断所使用的数据结构比较

      中断 软中断
    中断向量号描述符 irq_desc[中断向量号] softirq_vec[软中断号]
    中断请求寄存器 中断请求寄存器 __softirq_active
    中断屏蔽寄存器 中断屏蔽寄存器 __soft_mask
    中断处理程序 do_handler_name bh[]:32个
    中断处理程序描述项 irqaction softirq_action
    中断机制的初始化 trap_init():异常初始化
    init_IRQ():中断初始化
    softirq_action
    中断请求队列初始化 init_ISA_irqs() open_softirq
    中断处理程序与中断请求队列相关联 request_irq() init_bh()
    执行中断 do_IRQ() do_softirq

    4.激活可延迟函数

    (1)激活软中断

    A.把软中断置为把挂起状态,并周期性地检查处于挂起状态的软中断。如果有,就调用do_softirq()

    B.一般是在以下几个点来检查挂起的软中断的a.调用local_bh_enable()激活本地软中断时b.do_IRQ()完成I/O中断的处理即将退出时c.用于周期性检查挂起状态软中断的内核线程ksoftirqd被唤醒时d.else,我觉得不太重要

    (2)激活tasklet

    A.把自己定义的描述符加入到tasklet_vec指向的链表中即可。调用tasklet_action()时,依次处理队列中的每个tasklet描述符,然后清空tasklet_vec指向的链表。

    B.tasklet的每次激活至多触发tasklet函数的一次执行,除非tasklet函数重新激活自己


    三、工作队列

    1.它们允许内核函数被激活,并稍后由一种叫做工作者线程的特殊内核线程来执行

    如果系统有n个CPU,就会创建n个工作者,但是只会创建一个工作队列


    2.工作队列与可延迟函数的区别:

    可延迟函数运行中断上下文中,而工作队列运行在进程中下文中。

    可延迟函数不能阻塞,工作队列可执行可阻塞函数

    可延迟函数被执行时不可能有任何正在运行的进程,工作队列中的函数由内核线程来执行,不访问用户态地址空间


    3.工作队列的激活

    把要执行的函数的描述符插入到工作队列中。

    工作者等待函数被插入队列,被唤醒后把函数描述符取下并执行。

    由于工作队列函数可以阻塞,工作者线程可以睡觉,或移动另一个CPU


    总而言之:

           当发生一个中断时,如果发现中断被屏蔽,这个中断好似不会丢失的,会被再次触发!!

    展开全文
  • 中断分析

    2019-04-16 18:51:25
    什么要软中断? 编写驱动的时候,一个中断产生之后,内核在中断处理函数中可能需要完成很多 工作。但是中断处理函数的处理关闭了中断的。也就是说在响应中断时,系统 不能再次响应外部的其它中断。这样的后果会...
  • 本文试图对以下内容进行阐述和说明: 1. Java中断是协作式中断,“协作式中断”的含义; 2. Java中断并不是立即响应,那么线程什么时候中断?又在什么时候响应中断?如何响应中断

    一、概要

    本文试图对以下内容进行阐述和说明:

        1. Java中断是协作式中断,“协作式中断”的含义;

        2. Java中断并不是立即响应,那么线程什么时候中断?又在什么时候响应中断?如何响应中断?


    二、详解

    1. 协作式中断的含义

        借鉴INFOQ文章中的例子(链接:点击打开链接),协作式中断就像逢年过节回家,长辈总会告诫我们出门在外要照顾好自己,我们收到告诫后心里面就会记下来,但并不是立即就好好照顾自己(因为此时并不需要),而是等到我们出现需要照顾自己的场景的时候(譬如在外生病啦、孤独啦等等),回想到长辈的告诫,才去响应这个告诫,然后自己对自己好一点,去买平时舍不得买的东西,吃平时舍不得吃的东西。这段话有两个点,一个是通过长辈告诫我们,另一个是在恰当的场景下我们才会去响应并执行这个告诫,但是最终响应并执行这个告诫始终是我们自己<标记1>

        由此,可以引出java协作式中断的含义,辅助参看下面一段代码<标记2>

    public static void main(String[] args) {
    	// 初始化一个线程
    	Thread thread = new Thread("中断") {
    		public void run() {
    			try {
    				/**
    				 * 注意:sleep方法揭示了java线程何时、如何响应中断
    				 * public static native void sleep(long millis) throws InterruptedException;
    				 */
    				Thread.sleep(600 * 1000);
    			} catch (InterruptedException e) {
    				/**
    				 * 结果为true,因此当前线程thread中断状态标志位已经置位
    				 */
    				if(Thread.interrupted())
    					System.out.println("当前线程状态:中断");
    				e.printStackTrace();
    			}
    		};
    	};
    	/**
    	 * 当“中断”线程启动以后,此时系统中存在两个线程
    	 * 1. main线程;
    	 * 2. “中断”线程;
    	 */
    	thread.start();
    	// 为了通过工具分析线程状态,这里将主线程暂停一分钟,方便观察
    	try {
    		Thread.sleep(10*1000);
    	} catch (InterruptedException e) {
    		e.printStackTrace();
    	}
    	/**
    	 * 在主线程中中断(告诫)thread,此时thread修改了中断标志位,但是并没有立即响应
    	 */
    	thread.interrupt();
    	/**
    	 * 输出false,因为主线程此时并没有被中断
    	 */
    	System.out.println(Thread.interrupted());
    }

        Thread类中与中断直接相关的方法有四个,如下图所示<标记3>


        interrupt方法将会设置线程中断状态,表示该线程中断,但是并不是立即中断(因为还没有响应,下一节介绍),而是该线程在“合适”的时候;interrupted方法是一个静态方法,该方法会返回当前线程的中断状态并重置状态为false,当线程中断标志位为true时,调用inerrupted方法返回true并将标志位设置为false,再次调用interrupted的时候,将返回false(因为第一次调用的时候已经重置中断标志位了);而isInterrupted方法则返回线程的中断标志位;isInterrupted(boolean)是一个native方法,返回线程中断状态,其中传入的boolean参数用于控制是否需要重置线程中断标志位,interrupted和isInterrupted方法均基于该方法(逻辑简单,请自行参见源码)。

        结合三个标记的材料,可以对java协作式中断进行分析。

        1. 我们在主线程中调用thread的interrupt方法重置了thread的中断状态,此时thread记住了重置的中断状态(对应的是长辈对我们的告诫,然后我们将告诫记在心中),但是此时线程并没有立即中断;

        2. 最终当thread的run方法执行到sleep的时候,thread会去检查这个中断标志位,如果Thread.interrupted()为true,则throw new InterruptedExctption(),注意,interrupted方法会重置中断标志位(重点:最终是否响应中断,在于我们自己写的代码中是否有中断状态的判断,如果没有主动写中断状态判断的代码,也没有调用已经写了中断状态判断的代码,则线程永远不会响应中断,这对应着标志1中“恰当的场景和最终响应并执行告诫的永远是我们自己”);

        值得商榷的是,是否一定要在其它线程中调用thread的中断方法。可以把主线程中thread.interrupt()方法撤掉,然后再thread的run方法中来写,在sleep之前this.interrupt()一样可以达到中断thread的效果,不过这样的场景并不多见,因此不做更深的讨论。

    2. 中断响应

       重点:最终线程是否响应中断,在于代码中是否有中断状态的判断,如果既没有主动写中断状态判断的代码,也没有调用已经写了中断状态判断的代码,则线程永远不会响应中断。

        所以,java协作式中断的响应,在于代码中中断方法和中断异常的配合,要么自己主动写,要么调用JDK中已经写好了的代码。要想知道JDK中哪些常见代码可以响应中断,打开Thread类和Object类,搜索方法签名抛出中断异常InterruptedException即可。

    /**
     * public static native void sleep(long millis) throws InterruptedException
     * public final void join() throws InterruptedException
     * public final native void wait(long timeout) throws InterruptedException;
     */
        要想主动写中断判断的代码来使用java协作式中断机制,四个中断方法(JDK中sleep、join和wait采用类似interrupted方法)和一个中断异常搭配即可,参看如下示例代码。

    package cn.wxy.thread;
    
    import java.util.concurrent.TimeUnit;
    
    public class JavaInterrupted extends Thread {
    	public void run() {
    		try {
    			mySleep(TimeUnit.SECONDS.toSeconds(1)); // 线程执行到这里的时候,将会成为time_wait状态,此时释放执行权(不释放锁),当中断方法被调用后,线程的time_wait状态被中断
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/**
    	 * Thread.sleep(long)方法中中断逻辑的代码
    	 * @param seconds
    	 * @throws InterruptedException
    	 */
    	private static void mySleep(long seconds) throws InterruptedException {
    		/**
    		 * Thread.sleep方法:OS睡眠逻辑+中断判断代码,本处省略OS睡眠逻辑的代码
    		 */
    		if(Thread.interrupted())
    			throw new InterruptedException();
    	}
    }
        所以,要想让你的程序响应中断,只需要在你的代码中通过interrupted方法和InterruptedException异常结合即可。因为interrupted方法会清除线程的中断状态,因此如果想继续保持中断状态,则在异常处理中继续调用interrupt方法即可。


    附注:

        本文如有错漏,烦请不吝指正,谢谢!

    展开全文
  • Linux 软中断机制分析

    千次阅读 2018-09-12 11:57:37
    中断分析  最近工作繁忙,没有时间总结内核相关的一些东西。上次更新博客到了linux内核中断子系统。这次总结一下软中断,也就是softirq。...也就是说在响应中断时,系统不能再次响应外部的其它中断...
  • linux中断嵌套以及中断丢失

    千次阅读 2014-05-07 23:01:20
    linux内核里,如果驱动申请注册中断的时候没有特别的指定,do_irq中断响应时候开启中断的,如果驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被...
  • 同步中断 异步中断

    千次阅读 2012-11-30 14:25:11
    断”的发生完全异步的,因为不知道什么时候会发生。CPU对其的响应也完全被动的, 可以通过“关中断”指令关闭对其的响应。 由软件产生的中断一般由专设的指令,如X86中的“INT n”程序中有意产生的,
  • 同步中断和异步中断区别

    千次阅读 2019-02-27 17:02:21
    断”的发生完全异步的,因为不知道什么时候会发生。CPU对其的响应也完全被动的, 可以通过“关中断”指令关闭对其的响应。 由软件产生的中断一般由专设的指令,如X86中的“INT n”程序中有意产生的, 主动...
  • 一.... FreeRTOS会关键区即taskENTER_CRITICAL()和taskEXIT_CRITICAL()包裹的...即关闭中断时候,进行进程切换。 我们已经知道,即便关闭中断,PowerPC的sc中断,还是可以得到响应。但是时钟中断呢?这个...
  • 同步中断 和 异步中断

    千次阅读 2014-09-18 17:50:01
    断”的发生完全异步的,因为不知道什么时候会发生。CPU对其的响应也完全被动的, 可以通过“关中断”指令关闭对其的响应。 由软件产生的中断一般由专设的指令,如X86中的“INT n”程序中有意产生的,
  • 中断服务子程序如何被执行的 ?

    千次阅读 2020-05-25 00:07:18
    前言 笔者 《程序如何 CPU 中运行的(二)》中从 PC 指针寄存器的角度分析了一级函数调用和二级函数调用执行的过程,那么中断服务子程序又如何被执行的呢?...中断响应及处理过程 回顾函数调
  • 中断 和软中断以及时钟中断

    千次阅读 2010-06-20 19:38:00
    查了些书,并未有详细描述硬中断是在何时执行,我觉得应该是在每个时钟信号结束之后吧。 而软中断只有在几个特定的时刻被激活: 1 do_IRQ()完成了中断处理的时候。 2 时钟中断到来后会执行软...
  • 也就是说在响应中断时,系统不能再次响应外部的其它中断。这样的后果会造成有可能丢失外部中断。于是,linux内核设计出了一种架构,中断函数需要处理的任务分为两部分,一部分在中断处理函数中执行,这时系统关闭...
  • 但是注意,这个中断可以说是被动的,因为你不知道它什么时候会发生中断,打个比方,就比如你打LOL,正在精彩团战的时候,你女朋友打电话来叫你给她打一点钱,这个时候你不得不暂停游戏,去给女朋友打钱,打完钱...
  • Linux 中断

    2014-07-31 22:47:41
    1介绍我们知道,处理器的处理速度比硬件来说要快上N个数量...最好的办法,就是让硬件需要的时候才向内核发出信号,然后处理器去响应硬件的请求。这就是中断机制。1.1什么是中断当硬件需要和处理器通信时,会产生一个
  • RT_Thead 中断

    千次阅读 2015-08-26 10:42:16
    对于执行程序来说,这种“中断”的发生完全异步的,因为不知道什么时候会发生。CPU对其的响应也完全被动的, 可以通过“关中断”指令关闭对其的响应。 然而由软件产生的中断一般由专设的指令,如X86中的“INT...
  • 想写一个串口中断,输入一些值的时候能跳入中断响应, 中断标志位,子中断标志位,中断屏蔽位,子中断屏蔽位都有定义, 串口输入一些值后,能显示进入了中断并且能读到, 但是会一直循环进入串口中断, SRCPND1 ...
  • 也就是说在响应中断时,系统不能再次响应外部的其它中断。这样的后果会造成有可能丢失外部中断。于是,linux内核设计出了一种架构,中断函数需要处理的任务分为两部分,一部分在中断处理函数中执...
  • 关于中断(补充中)

    2020-09-13 19:53:03
    1.什么是中断中断是由硬件或软件所发送的一种称为...3.中断什么时候发生? (1)当I/O设备向CPU发来中断信号。 (2)CPU内部的事件,如:进程运算中发生了上溢或下溢。或者程序出错:非法指令,地址越界,电源故障
  • 只不过这些函数必须按照特定的类型声明,以便内核能够以标准的方式传递处理程序的信息,其他方面它们与一般的函数没有什么不同,中断处理程序与其他内核函数的真正区别在于中断处理程序被内核调用来响应中断的。...
  • 对于执行的系统来说,这种中断发生完全"异步"的,根本无法预测到此类中断在什么时候发生。因此,CPU(或者软件)对于此类外部中断完全"被动"的。不过,软件可以通过关中断的形式来关闭对中断响应,把它"反映...

空空如也

空空如也

1 2 3 4 5
收藏数 100
精华内容 40
关键字:

中断响应是在什么时候