freeRTOS小結——資源管理

概述

資源管理是指嵌入式系統中,針對TASK 和中斷處理程冠希訪問CPU以外的硬件資源(如某段存儲空間,某個外設)的控制。

嵌入式系統中,一段時間內訪問硬件資源的TASK和中斷處理程序數量總是有限的。因此OS需要提供一套機制來保證訪問硬件資源的TASK數量收到限制。

以一個簡單的UART輸出爲例,假定,

·           TASK 1需要通過UART輸出字符串“[TASK 1]:ABC.\n”

·           TASK 2需要通過UART輸出字符串“[TASK 2]:abc.\n”

·           TASK 1優先級低於TASK 2,但初始時TASK 1佔據了CPU資源

·           期望UART輸出“[TASK 1]: ABC.\n [TASK 2]: abc.\n”

則可能發生如下圖所示情況,導致輸出類似於“[TASK[TASK2]: abc.\n 1]: ABC”的亂碼。

如下圖所示,

其中,

·           TASK 1在時刻t1開始輸出字符串“[TASK1]: ABC.\n”

·           時間段t1~t2中,TASK 1向UART完成了部分字符串“[TASK”的輸出

·           時刻t2發生了時間片中斷,OS中斷了TASK 1的執行,轉而執行TASK 2,

·           時間段t2~t3中,TASK 2佔據了CPU,向串口輸出了字符串“[TASK 2]: abc.\n”

·           時刻t3,TASK 2完成了輸出,主動放棄了CPU資源,OS轉而執行TASK 1

·           時間段t3~t4,TASK 1繼續向UART輸出字符“ 1]: ABC”

 

其中將TASK 1換成一中斷處理程序,也會出現類似情況。

 

 

基於臨界區的資源管理

臨界區機制用於一段時間內訪問硬件資源的TASK數量爲1的情況。

其基本原理是TASK在訪問硬件資源前關閉CPU中斷響應,以避免中斷觸發的任務切換,訪問完成後在恢復CPU中斷響應。

關閉CPU中斷響應到恢復CPU中斷響應之間的處理過程即爲臨界區(Critical Section)。

臨界區中關閉了CPU中斷響應,會導致CPU對於中斷響應的延遲,因此在實際的使用中,臨界區的執行時間要儘可能的短。

實際使用中,不推薦在臨界區內調用任何函數和定義爲特殊操作的宏,除非能夠確保這些函數和宏的執行時間十分短,並且在後期的代碼維護中不會修改。

 

同樣是之前給出兩個TASK向UART輸出字符串的例子,只需TASK 1和TASK2使用如下函數輸出字符串,則不會輸出類似亂碼,


其中,

·           taskENTER_CRITICAL()和taskEXIT_CRITICAL()爲freeRTOS提供的API宏,用於關閉和恢復CPU中斷響應,需要在freeRTOS移植時根據硬件平臺定義

·           taskENTER_CRITICAL()和taskEXIT_CRITICAL()之間的代碼區域即爲臨界區,臨界區內的代碼被執行時,CPU不會響應中斷

·           freeRTOS還提供xTaskSuspenddAll()和xTaskResumeAll()兩個API函數,用於暫停和恢復OS的TASK調度,也可以構造出類似的臨界區,但是隻能規避多個TASK對於硬件資源的訪問控制,不可規避中斷處理程序對於硬件資源的訪問控制,因此並不推薦使用

 

此時,TASK 1和TASK2在CPU上的執行時序如下圖所示,


基於互斥信號量的資源管理

 

互斥信號量機制用於一段時間內訪問硬件資源的TASK數量爲1的情況。

互斥信號量可以看做是 一個特殊的“全局變量”,其取值爲0或1,0表示對應資源沒有被TASK訪問,1表示正在被訪問。

TASK訪問該硬件資源時,都需要先獲取信號量:判斷該互斥信號量是否爲0,若爲0則將其置爲1;若爲1則進入鎖定態等待該硬件資源被釋放。

獲取信號量的TASK才能訪問該以硬件資源。

當TASK完成硬件資源的訪問後,需要釋放信號量:將互斥信號量置爲0,並喚醒等待該硬件資源的最高優先級的TASK。

整個過程如下圖所示,




同樣是之前給出兩個TASK向UART輸出字符串的例子,只需TASK 1和TASK2使用如下函數輸出字符串,則不會輸出類似亂碼,


其中,

·           xSemaphoreTake()和xSemaphoreGive()是freeRTOS提供的API函數,用於獲取和釋放信號量。

·           在使用信號量之前需要使用freeRTOS提供的API函數xSemaphoreCreate()創建信號量,一般是在OS啓動之前的初始化過程或任務的初始化過程中創建。

 

此時,TASK 1和TASK2在CPU上的執行時序如下圖所示,


然而,這並非互斥信號量的全部。

優先級翻轉

爲了避免優先級翻轉(priorityinversion)問題,OS可能會自動提升已獲取互斥信號量的TASK的優先級,以保證其不小於所有等待該互斥信號量的TASK,直到其釋放互斥信號量後恢復,即優先級繼承(priority inheritance)。

如下圖所示,其中假定存在一優先級介於TASK1和TASK 2之間的TASK 3,則

·           若沒有優先級繼承,則TASK 3會在t4時刻獲取CPU資源,導致優先級更高的TASK 2由於無法獲取互斥信號量而不能運行,即優先級翻轉。

·           若有優先級繼承,則t2時刻,OS發現等待互斥信號量的TASK 2優先級高於擁有互斥信號量的TASK 1,則立即暫時提高TASK 1的優先級,這樣在t4時刻,TASK 3無法再獲取CPU資源;在t5時刻,TASK 1釋放互斥信號量後,OS恢復其優先級,TASK 2順利獲得CPU資源。



死鎖

簡而言之,死鎖就是兩個TASK都擁有了對方期望獲取的互斥信號量,導致雙方都不能運行的情況,如下圖所示,


死鎖是OS無法避免的,只能依靠用戶從系統設計的層面上避免,如禁止任務在已經獲取了互斥信號量的情況下獲取其他互斥信號量,或合理安排任務執行的時序,當然這是以犧牲設計的靈活度爲代價的。

除此之外,大部分的RTOS包括freeRTOS都推薦獲取信號量時,將等待時間設置爲有限值,並在獲取不成功時進行容錯處理。

 

 

 

基於信號量的資源管理

信號量機制用於一段時間內訪問硬件資源的TASK數量有限(允許大於1)的情況。

同樣考慮之前提到的例子,但修改一些設定

·           UART提供雙通道(記爲UARTCHAN 1和UART CHAN 2),可同時允許兩個TASK輸出字符串

·           除之前的TASK 1和TASK 2外,還存在優先級介於它們之間的TASK 3,希望輸出字符串“[TASK 3] : Abc\n”

則可以基於信號量來對UART進行管理,如下圖所示。



信號量的使用和效果與互斥信號量多有類似,此處就不再敘述。

 

基於TASK的資源管理

爲避免臨界區和互斥信號量的各種缺陷,freeRTOS推薦了一種基於TASK的資源管理方案:設置與硬件資源相對應的專門任務(記爲Gate Keeper TASK),所有需要訪問硬件資源的任務都必須通過Gate Keeper TASK進行,如下圖所示,如此不會出現死鎖和中斷延遲的問題。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章