0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是RTOS臨界段

汽車(chē)電子技術(shù) ? 來(lái)源:物聯(lián)網(wǎng)IoT開(kāi)發(fā) ? 作者: 杰杰mcu ? 2023-02-14 09:48 ? 次閱讀

什么是臨界段

代碼的臨界段也稱(chēng)為臨界區(qū),指處理時(shí)不可分割的代碼區(qū)域,一旦這部分代碼開(kāi)始執(zhí)行,則不允許任何中斷打斷。為確保臨界段代碼的執(zhí)行不被中斷,在進(jìn)入臨界段之前須關(guān)中斷,而臨界段代碼執(zhí)行完畢后,要立即打開(kāi)中斷。

臨界段的作用

其實(shí)在RTOS中,使用最多的臨界段是OS本身的調(diào)用,但是我們用戶(hù)也是需要對(duì)臨界資源進(jìn)行保護(hù)的(臨界資源是一次僅允許一個(gè)線(xiàn)程使用的共享資源),特別是一些全局變量,當(dāng)線(xiàn)程正在使用的時(shí)候不希望有人來(lái)打斷我的操作,就行很多時(shí)候我們寫(xiě)代碼時(shí),需要集中精力,不希望別人打斷我們的思路一樣。這樣子使得系統(tǒng)的運(yùn)行更加穩(wěn)定健壯。

什么時(shí)候會(huì)打斷代碼的執(zhí)行?

顧名思義,代碼正在正常運(yùn)行的時(shí)候,基本不會(huì)被打斷,能被打斷的都是系統(tǒng)發(fā)生了異常(中斷也是異常),在OS中,除了外部中斷能將正在運(yùn)行的代碼打斷,還有線(xiàn)程的調(diào)度——PendSV,系統(tǒng)產(chǎn)生 PendSV中斷,在 PendSV Handler 里面實(shí)現(xiàn)線(xiàn)程的切換。我們要將這項(xiàng)東西屏蔽掉,保證當(dāng)前只有一個(gè)線(xiàn)程在使用臨界資源。

如何關(guān)閉中斷?

其實(shí),在我們常用的MCU中,一般為Cortex-M內(nèi)核的,M內(nèi)核是有一些指令能快速關(guān)閉中斷,一起來(lái)看看Cortex-M權(quán)威指南吧(以Cortex-M3為例)。

圖片

簡(jiǎn)單來(lái)說(shuō),快速屏蔽中斷就是處理這些內(nèi)核寄存器,在Cortex-M中有相應(yīng)的操作指令,一般我們無(wú)需關(guān)注,因?yàn)镺S已經(jīng)給我們寫(xiě)好了這些底層的東西。不過(guò)如果你是想自己寫(xiě)一個(gè)OS的話(huà),可以了解一下,要訪(fǎng)問(wèn) PRIMASK, FAULTMASK 以及 BASEPRI,同樣要使用 MRS/MSR 指令,如:
1MRS R0, BASEPRI ;讀取 BASEPRI 到 R02MRS R0, FAULTMASK ;似上
3MRS R0, PRIMASK ;似上
4MSR BASEPRI, R0 ;寫(xiě)入 R0 到 BASEPRI 中
5MSR FAULTMASK, R0 ;似上
6MSR PRIMASK, R0 ;似上

只有在特權(quán)級(jí)下,才允許訪(fǎng)問(wèn)這 3 個(gè)寄存器。

其實(shí),為了快速地開(kāi)關(guān)中斷, CM3 還專(zhuān)門(mén)設(shè)置了一條 CPS 指令,有 4 種用法:

圖片

1CPSID I ;PRIMASK=1, ;關(guān)中斷
2CPSIE I ;PRIMASK=0, ;開(kāi)中斷
3CPSID F ;FAULTMASK=1, ;關(guān)異常
4CPSIE F ;FAULTMASK=0 ;開(kāi)異常
上面的代碼中的PRIMASKFAULTMASTCortex-M 內(nèi)核 里面三個(gè)中斷屏蔽寄存器中的兩個(gè),還有一個(gè)是 BASEPRI,這些寄存器都用于屏蔽中斷。具體的作用見(jiàn)表格(表格出自《【野火】RT-Thread 內(nèi)核實(shí)現(xiàn)與應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn)指南》)
名字 功能描述
PRIMASK 這是個(gè)只有單一比特的寄存器。 在它被置 1 后,就關(guān)掉所有可屏蔽的異常,只剩下 NMI 和硬 FAULT 可以響應(yīng)。它的缺省值是 0,表示沒(méi)有關(guān)中斷。
FAULTMASK 這是個(gè)只有 1 個(gè)位的寄存器。當(dāng)它置 1 時(shí),只有 NMI 才能響應(yīng),所有其它的異常,甚至是硬 FAULT,也通通閉嘴。它的缺省值也是 0,表示沒(méi)有關(guān)異常。
BASEPRI 這個(gè)寄存器最多有 9 位(由表達(dá)優(yōu)先級(jí)的位數(shù)決定)。它定義了被屏蔽優(yōu)先級(jí)的閾值。當(dāng)它被設(shè)成某個(gè)值后,所有優(yōu)先級(jí)號(hào)大于等于此值的中斷都被關(guān)(優(yōu)先級(jí)號(hào)越大,優(yōu)先級(jí)越低)。但若被設(shè)成 0,則不關(guān)閉任何中斷, 0 也是缺省值。

不同OS的處理臨界段的區(qū)別

FreeRTOS

FreeRTOS對(duì)中斷的開(kāi)和關(guān)是通過(guò)操作 BASEPRI 寄存器來(lái)實(shí)現(xiàn)的,即大于等于 BASEPRI 的值的中斷會(huì)被屏蔽,小于 BASEPRI 的值的中斷則不會(huì)被屏蔽。這樣子的好處就是用戶(hù)可以設(shè)置 BASEPRI 的值來(lái)選擇性的給一些非常緊急的中斷留一條后路。比如飛控的防撞處理。代碼在portmacro.h 中實(shí)現(xiàn):

屏蔽中斷:

1static portFORCE_INLINE void vPortRaiseBASEPRI( void )
 2{
 3uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
 4
 5    __asm
 6    {
 7        msr basepri, ulNewBASEPRI
 8        dsb
 9        isb
10    }
11}

打開(kāi)中斷:

1static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
2{
3    __asm
4    {
5        msr basepri, ulBASEPRI
6    }
7}

RT-Thread

FreeRTOS不同的是,RT-Thread 對(duì)臨界段的保護(hù)處理的很干脆,不管三七二十一直接把中斷全部關(guān)了(直接操作PRIMASK內(nèi)核寄存器), 只有NMI FAULT 和硬 FAULT能被相應(yīng)。 這種方法簡(jiǎn)單粗暴,是很不錯(cuò)的選擇。一般我們臨界段的處理時(shí)間是比較短的,關(guān)了再開(kāi)其實(shí)并沒(méi)有太大的影響。

現(xiàn)在要看看RT-Thread的關(guān)中斷的代碼實(shí)現(xiàn):
1rt_hw_interrupt_disable    PROC
2    EXPORT  rt_hw_interrupt_disable
3    MRS     r0, PRIMASK
4    CPSID   I
5    BX      LR
6    ENDP

開(kāi)中斷:

1rt_hw_interrupt_enable    PROC
2    EXPORT  rt_hw_interrupt_enable
3    MSR     PRIMASK, r0
4    BX      LR
5    ENDP

這短短的幾句代碼其實(shí)還是很有意思的,我就引用火哥的話(huà)來(lái)解釋一下這些處理操作(我個(gè)人是不會(huì)匯編的,但是跟著書(shū)來(lái)解讀這些代碼還是很輕而易舉的)

可能有人懂匯編的話(huà),就會(huì)看出來(lái),關(guān)中斷,不就是直接使用 CPSID I 指令就行了嘛~開(kāi)中斷,不就是使用 CPSIE I 指令就行了嘛,為啥跟我等凡人想的不一樣?

RT-Thread的處理好像是多此一舉了,實(shí)則不然,“所有東西的存在必然有其存在的意義”這句話(huà)應(yīng)該沒(méi)人反駁吧~~因?yàn)?span id="z7pvffj"    class="hljs-variable">RT-Thread要防止用戶(hù)錯(cuò)誤地退出了中斷臨界段,因?yàn)檫@樣子可能會(huì)產(chǎn)生巨大的危害,所以RT-Thread將當(dāng)前的PRIMASK的狀態(tài)保存起來(lái),這樣子就必須要關(guān)多少次中斷就得開(kāi)多少次中斷。

怎么說(shuō)呢,用例子來(lái)證明吧:

1/* 臨界段 1 開(kāi)始 */
 2rt_hw_interrupt_disable(); /* 關(guān)中斷,PRIMASK = 1 */
 3{
 4  /* 臨界段 2 */
 5  rt_hw_interrupt_disable(); /* 關(guān)中斷,PRIMASK = 1 */
 6  {
 7  }
 8  rt_hw_interrupt_enable(); /* 開(kāi)中斷,PRIMASK = 0 */ (注意)
 9}
10/* 臨界段 1 結(jié)束 */
11rt_hw_interrupt_enable(); /* 開(kāi)中斷,PRIMASK = 0 */
如果直接操作PRIMASK,而不保存PRIMASK的狀態(tài),這樣子當(dāng)臨界段2結(jié)束后調(diào)用一次打開(kāi)中斷,那么連臨界段1的后半部分就無(wú)效了。而RT-Thread的實(shí)現(xiàn)就能很好避免這種問(wèn)題,也用代碼來(lái)說(shuō)明吧:
1/* 臨界段 1 開(kāi)始 */
 2level1 = rt_hw_interrupt_disable(); /* 關(guān)中斷,level1=0,PRIMASK=1 */
 3{
 4  /* 臨界段 2 */
 5  level2 = rt_hw_interrupt_disable(); /* 關(guān)中斷,level2=1,PRIMASK=1 */ 
 6  {
 7  }
 8  rt_hw_interrupt_enable(level2); /* 開(kāi)中斷,level2=1,PRIMASK=1 */ 
 9}
10/* 臨界段 1 結(jié)束 */
11rt_hw_interrupt_enable(level1); /* 開(kāi)中斷,level1=0,PRIMASK=0 */

這樣子就完全避免了對(duì)吧!

有人又會(huì)問(wèn)了,F(xiàn)reeRTOS的臨界段能允許嵌套嗎,答案是肯定的,F(xiàn)reeRTOS中早已給我們想好調(diào)用的函數(shù)了,并且全部使用宏定義實(shí)現(xiàn)了:
1#define portDISABLE_INTERRUPTS()                vPortRaiseBASEPRI()
2#define portENABLE_INTERRUPTS()                 vPortSetBASEPRI( 0 )
3#define portENTER_CRITICAL()                    vPortEnterCritical()
4#define portEXIT_CRITICAL()                     vPortExitCritical()
5#define portSET_INTERRUPT_MASK_FROM_ISR()       ulPortRaiseBASEPRI()
6#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)    vPortSetBASEPRI(x)
其實(shí)原理都是差不多的,通過(guò)保存和恢復(fù)寄存器basepri的數(shù)值就可以實(shí)現(xiàn)嵌套使用。
1UBaseType_t uxSavedInterruptStatus;
 2
 3uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
 4{
 5  uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
 6  {
 7     //臨界區(qū)代碼
 8  }
 9  portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
10}
11portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
進(jìn)入中斷源碼的實(shí)現(xiàn):
1static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
 2{
 3uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
 4
 5    __asm
 6    {
 7        mrs ulReturn, basepri
 8        msr basepri, ulNewBASEPRI
 9        dsb
10        isb
11    }
12    return ulReturn;
13}
退出中斷源碼實(shí)現(xiàn):(跟前面的函數(shù)一樣)
1static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
2{
3    __asm
4    {
5        msr basepri, ulBASEPRI
6    }
7}

總結(jié)

對(duì)于時(shí)間關(guān)鍵的任務(wù)而言,恰如其分地使用 PRIMASK 和 BASEPRI 來(lái)暫時(shí)關(guān)閉一些中斷是非常重要的。

FreeRTOS源碼中就有多處臨界段的處理,除了FreeRTOS操作系統(tǒng)源碼所帶的臨界段以外,用戶(hù)寫(xiě)應(yīng)用的時(shí)候也有臨界段的問(wèn)題,比如以下兩種:
  • 讀取或者修改變量(特別是用于任務(wù)間通信的全局變量)的代碼,一般來(lái)說(shuō)這是最常見(jiàn)的臨界代碼。
  • 調(diào)用公共函數(shù)的代碼,特別是不可重入的函數(shù),如果多個(gè)任務(wù)都訪(fǎng)問(wèn)這個(gè)函數(shù),結(jié)果是可想而知的。
總之,對(duì)于臨界段要做到執(zhí)行時(shí)間越短越好,否則會(huì)影響系統(tǒng)的實(shí)時(shí)性。

那假如我有一個(gè)線(xiàn)程,處理的時(shí)間較長(zhǎng),但是我又不想被其他線(xiàn)程打斷,關(guān)中斷可能影響系統(tǒng)的正常運(yùn)行,怎么辦呢?其實(shí)很簡(jiǎn)單,在OS中一般可以直接掛起調(diào)度器,系統(tǒng)正常運(yùn)行,但是不會(huì)切換線(xiàn)程,當(dāng)我處理完再把調(diào)度器解除即可。

RTOS使用得好,開(kāi)發(fā)起來(lái)比裸機(jī)更簡(jiǎn)單,使用得不好,那將是噩夢(mèng)——杰杰

▲▲▲▲▲

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 中斷
    +關(guān)注

    關(guān)注

    5

    文章

    901

    瀏覽量

    42142
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4865

    瀏覽量

    69751
  • 執(zhí)行
    +關(guān)注

    關(guān)注

    0

    文章

    16

    瀏覽量

    12672
收藏 0人收藏

    評(píng)論

    相關(guān)推薦

    【安富萊】【RTX操作系統(tǒng)教程】第11章 臨界,任務(wù)鎖和中斷鎖

    多個(gè)任務(wù)都訪(fǎng)問(wèn)這個(gè)函數(shù),結(jié)果是可想而知的。 總之,對(duì)于臨界要做到執(zhí)行時(shí)間越短越好,要不會(huì)影響系統(tǒng)的實(shí)時(shí)性。11.2中斷鎖 中斷鎖就是RTOS提供的開(kāi)關(guān)中斷函數(shù),因?yàn)镃ortex-M3/M4的RTX源碼
    發(fā)表于 01-25 16:52

    轉(zhuǎn):第15章 FreeRTOS臨界和開(kāi)關(guān)中斷

    第15章FreeRTOS臨界和開(kāi)關(guān)中斷 本章教程為大家講解兩個(gè)重要的概念,F(xiàn)reeRTOS的臨界和開(kāi)關(guān)中斷。 本章教程配套的例子含Cortex-M3內(nèi)核的STM32F103和Cor
    發(fā)表于 08-31 10:15

    第11章 臨界,任務(wù)鎖和中斷鎖

    轉(zhuǎn)rtx操作系統(tǒng) 本章教程為大家講解幾個(gè)重要的概念,臨界,任務(wù)鎖和中斷鎖。本章教程配套的例子含Cortex-M3內(nèi)核的STM32F103和Cortex-M4內(nèi)核的STM32F407。11.1 臨界
    發(fā)表于 10-04 19:58

    RTOS臨界知識(shí)詳解

    執(zhí)行完畢后,要立即打開(kāi)中斷。 臨界的作用 其實(shí)在RTOS中,使用最多的臨界是OS本身的調(diào)用,但是我們用戶(hù)也是需要對(duì)
    發(fā)表于 10-09 11:02

    【設(shè)計(jì)技巧】從單片機(jī)到操作系統(tǒng)(8)-RTOS臨界知識(shí)詳解

    斷,而臨界代碼執(zhí)行完畢后,要立即打開(kāi)中斷。臨界的作用 其實(shí)在RTOS中,使用最多的臨界
    發(fā)表于 08-01 08:30

    FreeRTOS關(guān)于臨界的疑問(wèn)如何解答

    FreeRTOS中關(guān)于臨界的函數(shù)有4個(gè),taskENTER_CRITICAL():進(jìn)入臨界,用于任務(wù)中taskEXIT_CRITICAL():退出
    發(fā)表于 06-19 04:36

    請(qǐng)問(wèn)STM32的FreeRTOS怎么使用臨界?

    STM32的FreeRTOS怎么使用臨界
    發(fā)表于 08-28 08:06

    怎樣去使用FreeRTOS的中斷配置和臨界

    STM32之FreeRTOS:(一) 中斷配置和臨界的使用文章目錄STM32之FreeRTOS:(一) 中斷配置和臨界的使用前言 一、stm32的NVIC 分組配置二、FreeRT
    發(fā)表于 01-14 09:28

    求大佬分享FreeRTOS臨界代碼

    求大佬分享FreeRTOS臨界代碼
    發(fā)表于 02-07 06:28

    freertos中的臨界是如何實(shí)現(xiàn)的?

    怎么實(shí)現(xiàn)對(duì)應(yīng)臨界的保護(hù)
    發(fā)表于 10-20 07:25

    什么是臨界 RTOS臨界的作用是什么

    代碼的臨界也稱(chēng)為臨界區(qū),指處理時(shí)不可分割的代碼區(qū)域,一旦這部分代碼開(kāi)始執(zhí)行,則不允許任何中斷打斷。為確保臨界代碼的執(zhí)行不被中斷,在進(jìn)入
    的頭像 發(fā)表于 10-06 14:38 ?1.2w次閱讀
    什么是<b class='flag-5'>臨界</b><b class='flag-5'>段</b> <b class='flag-5'>RTOS</b><b class='flag-5'>臨界</b><b class='flag-5'>段</b>的作用是什么

    FreeRTOS學(xué)習(xí)筆記--臨界代碼處關(guān)閉中斷

    FreeRTOS學(xué)習(xí)筆記--臨界代碼處關(guān)閉中斷一、臨界代碼二、Cortex-M4中斷管理三、中斷屏蔽實(shí)驗(yàn)四、結(jié)語(yǔ)一、臨界
    發(fā)表于 12-04 14:51 ?10次下載
    FreeRTOS學(xué)習(xí)筆記--<b class='flag-5'>臨界</b><b class='flag-5'>段</b>代碼處關(guān)閉中斷

    FreeRTOS臨界

    臨界斷代碼也叫做臨界區(qū),是指那些必須完整運(yùn)行,不能被打斷的代碼,F(xiàn)reeRTOS與臨界斷代碼保護(hù)有關(guān)的函數(shù)有4個(gè):taskENTER_CRITICAL() ——任務(wù)級(jí)進(jìn)入
    發(fā)表于 12-04 16:06 ?0次下載
    FreeRTOS<b class='flag-5'>臨界</b><b class='flag-5'>段</b>

    STM32之FreeRTOS:(一) 中斷配置和臨界的使用

    STM32之FreeRTOS:(一) 中斷配置和臨界的使用文章目錄STM32之FreeRTOS:(一) 中斷配置和臨界的使用前言 一、stm32的NVIC 分組配置二、FreeRT
    發(fā)表于 01-14 15:43 ?3次下載
    STM32之FreeRTOS:(一) 中斷配置和<b class='flag-5'>臨界</b><b class='flag-5'>段</b>的使用

    RTOS臨界知識(shí)詳解

    代碼的臨界也稱(chēng)為臨界區(qū),指處理時(shí)不可分割的代碼區(qū)域,一旦這部分代碼開(kāi)始執(zhí)行,則不允許任何中斷打斷。
    的頭像 發(fā)表于 06-13 14:07 ?1348次閱讀
    <b class='flag-5'>RTOS</b><b class='flag-5'>臨界</b><b class='flag-5'>段</b>知識(shí)詳解

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品