0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是临界段 RTOS临界段的作用是什么

GReq_mcu168 作者:工程师李察 2018-10-06 14:38 次阅读

什么是临界段

代码的临界段也称为临界区,指处理时不可分割的代码区域,一旦这部分代码开始执行,则不允许任何中断打断。为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完毕后,要立即打开中断。

临界段的作用

其实在RTOS中,使用最多的临界段是OS本身的调用,但是我们用户也是需要对临界资源进行保护的(临界资源是一次仅允许一个线程使用的共享资源),特别是一些全局变量,当线程正在使用的时候不希望有人来打断我的操作,就行很多时候我们写代码时,需要集中精力,不希望别人打断我们的思路一样。这样子使得系统的运行更加稳定健壮。

什么时候会打断代码的执行?

顾名思义,代码正在正常运行的时候,基本不会被打断,能被打断的都是系统发生了异常(中断也是异常),在OS中,除了外部中断能将正在运行的代码打断,还有线程的调度——PendSV,系统产生PendSV中断,在PendSV Handler里面实现线程的切换。我们要将这项东西屏蔽掉,保证当前只有一个线程在使用临界资源。

如何关闭中断?

其实,在我们常用的MCU中,一般为Cortex-M内核的,M内核是有一些指令能快速关闭中断,一起来看看Cortex-M权威指南吧(以Cortex-M3为例)。

什么是临界段 RTOS临界段的作用是什么

简单来说,快速屏蔽中断就是处理这些内核寄存器,在Cortex-M中有相应的操作指令,一般我们无需关注,因为OS已经给我们写好了这些底层的东西。不过如果你是想自己写一个OS的话,可以了解一下,要访问PRIMASK, FAULTMASK以及BASEPRI,同样要使用MRS/MSR指令,如:

1MRSR0,BASEPRI;读取BASEPRI到R0中2MRSR0,FAULTMASK;似上3MRSR0,PRIMASK;似上4MSRBASEPRI,R0;写入R0到BASEPRI中5MSRFAULTMASK,R0;似上6MSRPRIMASK,R0;似上

只有在特权级下,才允许访问这3个寄存器。

其实,为了快速地开关中断,CM3还专门设置了一条CPS指令,有4种用法:

1CPSIDI;PRIMASK=1,;关中断2CPSIEI;PRIMASK=0,;开中断3CPSIDF;FAULTMASK=1,;关异常4CPSIEF;FAULTMASK=0;开异常

上面的代码中的PRIMASK和FAULTMAST是Cortex-M内核 里面三个中断屏蔽寄存器中的两个,还有一个是BASEPRI,这些寄存器都用于屏蔽中断。具体的作用见表格(表格出自《【野火】RT-Thread内核实现与应用开发实战指南》)

什么是临界段 RTOS临界段的作用是什么

不同OS的处理临界段的区别

FreeRTOS

FreeRTOS对中断的开和关是通过操作BASEPRI寄存器来实现的,即大于等于BASEPRI的值的中断会被屏蔽,小于BASEPRI的值的中断则不会被屏蔽。这样子的好处就是用户可以设置BASEPRI的值来选择性的给一些非常紧急的中断留一条后路。比如飞控的防撞处理。代码在portmacro.h 中实现:

屏蔽中断:

1staticportFORCE_INLINEvoidvPortRaiseBASEPRI(void) 2{ 3uint32_tulNewBASEPRI=configMAX_SYSCALL_INTERRUPT_PRIORITY; 4 5__asm 6{ 7msrbasepri,ulNewBASEPRI 8dsb 9isb10}11}

打开中断:

1staticportFORCE_INLINEvoidvPortSetBASEPRI(uint32_tulBASEPRI)2{3__asm4{5msrbasepri,ulBASEPRI6}7}

RT-Thread:

与FreeRTOS不同的是,RT-Thread对临界段的保护处理的很干脆,不管三七二十一直接把中断全部关了(直接操作PRIMASK内核寄存器), 只有NMI FAULT和硬FAULT能被相应。 这种方法简单粗暴,是很不错的选择。一般我们临界段的处理时间是比较短的,关了再开其实并没有太大的影响。

现在要看看RT-Thread的关中断的代码实现:

1rt_hw_interrupt_disablePROC2EXPORTrt_hw_interrupt_disable3MRSr0,PRIMASK4CPSIDI5BXLR6ENDP

开中断:

1rt_hw_interrupt_enablePROC2EXPORTrt_hw_interrupt_enable3MSRPRIMASK,r04BXLR5ENDP

这短短的几句代码其实还是很有意思的,我就引用火哥的话来解释一下这些处理操作(我个人是不会汇编的,但是跟着书来解读这些代码还是很轻而易举的)

可能有人懂汇编的话,就会看出来,关中断,不就是直接使用CPSID I指令就行了嘛~开中断,不就是使用CPSIE I指令就行了嘛,为啥跟我等凡人想的不一样?

RT-Thread的处理好像是多此一举了,实则不然,“所有东西的存在必然有其存在的意义”这句话应该没人反驳吧~~因为RT-Thread要防止用户错误地退出了中断临界段,因为这样子可能会产生巨大的危害,所以RT-Thread将当前的PRIMASK的状态保存起来,这样子就必须要关多少次中断就得开多少次中断。

怎么说呢,用例子来证明吧:

1/*临界段1开始*/ 2rt_hw_interrupt_disable();/*关中断,PRIMASK=1*/ 3{ 4/*临界段2*/ 5rt_hw_interrupt_disable();/*关中断,PRIMASK=1*/ 6{ 7} 8rt_hw_interrupt_enable();/*开中断,PRIMASK=0*/(注意) 9}10/*临界段1结束*/11rt_hw_interrupt_enable();/*开中断,PRIMASK=0*/

如果直接操作PRIMASK,而不保存PRIMASK的状态,这样子当临界段2结束后调用一次打开中断,那么连临界段1的后半部分就无效了。而RT-Thread的实现就能很好避免这种问题,也用代码来说明吧:

1/*临界段1开始*/ 2level1=rt_hw_interrupt_disable();/*关中断,level1=0,PRIMASK=1*/ 3{ 4/*临界段2*/ 5level2=rt_hw_interrupt_disable();/*关中断,level2=1,PRIMASK=1*/ 6{ 7} 8rt_hw_interrupt_enable(level2);/*开中断,level2=1,PRIMASK=1*/ 9}10/*临界段1结束*/11rt_hw_interrupt_enable(level1);/*开中断,level1=0,PRIMASK=0*/

这样子就完全避免了对吧!

有人又会问了,FreeRTOS的临界段能允许嵌套吗,答案是肯定的,FreeRTOS中早已给我们想好调用的函数了,并且全部使用宏定义实现了:

1#defineportDISABLE_INTERRUPTS()vPortRaiseBASEPRI()2#defineportENABLE_INTERRUPTS()vPortSetBASEPRI(0)3#defineportENTER_CRITICAL()vPortEnterCritical()4#defineportEXIT_CRITICAL()vPortExitCritical()5#defineportSET_INTERRUPT_MASK_FROM_ISR()ulPortRaiseBASEPRI()6#defineportCLEAR_INTERRUPT_MASK_FROM_ISR(x)vPortSetBASEPRI(x)

其实原理都是差不多的,通过保存和恢复寄存器basepri的数值就可以实现嵌套使用。

1UBaseType_tuxSavedInterruptStatus; 2 3uxSavedInterruptStatus=portSET_INTERRUPT_MASK_FROM_ISR(); 4{ 5uxSavedInterruptStatus=portSET_INTERRUPT_MASK_FROM_ISR(); 6{ 7//临界区代码 8} 9portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);10}11portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);

进入中断源码的实现:

1staticportFORCE_INLINEuint32_tulPortRaiseBASEPRI(void) 2{ 3uint32_tulReturn,ulNewBASEPRI=configMAX_SYSCALL_INTERRUPT_PRIORITY; 4 5__asm 6{ 7mrsulReturn,basepri 8msrbasepri,ulNewBASEPRI 9dsb10isb11}12returnulReturn;13}

退出中断源码实现:(跟前面的函数一样)

1staticportFORCE_INLINEvoidvPortSetBASEPRI(uint32_tulBASEPRI)2{3__asm4{5msrbasepri,ulBASEPRI6}7}

总结

对于时间关键的任务而言,恰如其分地使用PRIMASK和BASEPRI来暂时关闭一些中断是非常重要的。

FreeRTOS源码中就有多处临界段的处理,除了FreeRTOS操作系统源码所带的临界段以外,用户写应用的时候也有临界段的问题,比如以下两种:

读取或者修改变量(特别是用于任务间通信的全局变量)的代码,一般来说这是最常见的临界代码。

调用公共函数的代码,特别是不可重入的函数,如果多个任务都访问这个函数,结果是可想而知的。

总之,对于临界段要做到执行时间越短越好,否则会影响系统的实时性。

那假如我有一个线程,处理的时间较长,但是我又不想被其他线程打断,关中断可能影响系统的正常运行,怎么办呢?其实很简单,在OS中一般可以直接挂起调度器,系统正常运行,但是不会切换线程,当我处理完再把调度器解除即可。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 中断
    +关注

    关注

    5

    文章

    884

    浏览量

    41020
  • RTOS
    +关注

    关注

    20

    文章

    773

    浏览量

    118772
  • 代码
    +关注

    关注

    30

    文章

    4552

    浏览量

    66640

原文标题:RTOS临界段知识详解

文章出处:【微信号:mcu168,微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【安富莱】【RTX操作系统教程】第11章 临界,任务锁和中断锁

    多个任务都访问这个函数,结果是可想而知的。 总之,对于临界要做到执行时间越短越好,要不会影响系统的实时性。11.2中断锁 中断锁就是RTOS提供的开关中断函数,因为Cortex-M3/M4的RTX源码
    发表于 01-25 16:52

    转:第15章 FreeRTOS临界和开关中断

    第15章FreeRTOS临界和开关中断 本章教程为大家讲解两个重要的概念,FreeRTOS的临界和开关中断。 本章教程配套的例子含Cortex-M3内核的STM32F103和Cor
    发表于 08-31 10:15

    第11章 临界,任务锁和中断锁

    转rtx操作系统 本章教程为大家讲解几个重要的概念,临界,任务锁和中断锁。本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。11.1 临界
    发表于 10-04 19:58

    请问28335怎样处理代码临界问题

    28335 怎样处理代码临界问题,只用开关中断指令吗?
    发表于 08-22 07:34

    RTOS临界知识详解

    执行完毕后,要立即打开中断。 临界作用 其实在RTOS中,使用最多的临界是OS本身的调用,
    发表于 10-09 11:02

    【设计技巧】从单片机到操作系统(8)-RTOS临界知识详解

    断,而临界代码执行完毕后,要立即打开中断。临界作用 其实在RTOS中,使用最多的
    发表于 08-01 08:30

    使用UCOSIII延迟发布在临界代码发生中断

    各位好,我想问个问题,就是如果使用延迟发布,在临界代码中发生了中断,是不是将参数什么的写入终端队列后,让中断队列处理任务进入就绪态,但此时因为任务调度器是锁定的,应该会先把中断任务处的临界
    发表于 04-21 04:35

    FreeRTOS关于临界的疑问如何解答

    FreeRTOS中关于临界的函数有4个,taskENTER_CRITICAL():进入临界,用于任务中taskEXIT_CRITICAL():退出
    发表于 06-19 04:36

    请问STM32的FreeRTOS怎么使用临界

    STM32的FreeRTOS怎么使用临界
    发表于 08-28 08:06

    怎样去使用FreeRTOS的中断配置和临界

    STM32之FreeRTOS:(一) 中断配置和临界的使用文章目录STM32之FreeRTOS:(一) 中断配置和临界的使用前言 一、stm32的NVIC 分组配置二、FreeRT
    发表于 01-14 09:28

    求大佬分享FreeRTOS临界代码

    求大佬分享FreeRTOS临界代码
    发表于 02-07 06:28

    怎样去解决rtt临界处理和中断延时的问题

    我一直在找一个中断响应很快的系统看了一下rtt的代码,临界处理也是通过关中断来实现的,感觉这种处理虽然简单,但是对中断响应有比较大的影响,限制了在一些快速事件中断场合中的应用。有的时候需要捕捉到
    发表于 04-06 18:13

    请问一下RT-Thread临界的保护该怎样去实现呢

    临界用一句话概括就是一在执行的时候不能被中断的代码。Cortex-M 内核快速关中断指令CPSID I ;PRIMASK=1 ;关中断CPSIE I ;PRIMASK=0 ;开中
    发表于 05-26 14:58

    freertos中的临界是如何实现的?

    怎么实现对应临界的保护
    发表于 10-20 07:25

    什么是RTOS临界

    代码的临界段也称为临界区,指处理时不可分割的代码区域,一旦这部分代码开始执行,则不允许任何中断打断。为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而
    的头像 发表于 02-14 09:48 796次阅读
    什么是<b class='flag-5'>RTOS</b><b class='flag-5'>临界</b>段