您當前的位置:首頁 > 遊戲

嵌入式作業系統-互斥訊號量mutex

作者:由 snowdream 發表于 遊戲時間:2022-09-20

在上一篇文章中,我們回顧了訊號量的基礎知識。也瞭解到,為了保證對共享資源的獨享,存在二值訊號量這樣一種保護機制。針對這種專用的訊號量,ucos特意為這種型別的EVENT事件起了一個新的名字——MUTEX訊號量。但是需要我們注意的是,

MUTEX除了具備傳統二值訊號量的基本特性外,還存在獨特的功能:專門為了解決優先順序反轉問題

什麼是優先順序反轉

設定有如下的多工場景:系統中有A,B,C三個任務,優先順序分別為10,15,20。即任務A的優先順序最高,任務C的優先順序最低。

嵌入式作業系統-互斥訊號量mutex

根據優先順序,假定任務A,B,C分別獲取CPU進行執行。在

T點

的時候,任務C剛剛獲取了某個共享資源的使用權,此時發生了任務切換。任務A被排程到CPU執行。

此時如果任務A也需要使用上述共享資源,那麼優先順序反轉就會在T點發生

。為什麼呢?任務A雖然優先順序很高,但是因為共享資源被優先順序低的任務C佔用,只能允許任務C執行完,才允許任務A繼續執行。

從執行的效果上看,即:高優先順序的任務讓位於低優先順序的任務執行

【如何解決優先順序反轉】

既然互斥訊號量專門為了解決優先順序反轉問題,那我們下面來分析一下具體是如何解決的。

解決優先順序反轉問題的核心問題在於

:任何排程時刻內,都是要保證高優先順序的任務優先於低優先順序的任務執行。

我們依然採用上面的例子。設定在T點時刻,任務A申請MUTEX訊號量用於使用共享資源。此時根據MUTEX的需要,我們在建立這個MUTEX的時候,MUTEX的優先順序為9。

注:優先順序編號越小,優先順序越高

嵌入式作業系統-互斥訊號量mutex

當T時刻發生時候:

1,

任務A(10)

呼叫OSMutexPend介面申請MUTEX。但是發現

任務C(20)

在T時刻前已經申請並使用了MUTEX資源。

2,

如果任務A掛起在MUTEX事件的話,

優先順序就會出現反轉

事實上

在任務A呼叫的OSMutexPend介面中

->

MUTEX機制發現該MUTEX已經被低優先順序的任務C佔用

->

任務C被賦予MUTEX的優先順序9

->

排程任務C(優先順序已經調整為9)繼續執行,任務A掛起在該MUTEX下,直到C釋放MUTEX資源

->

在任務C呼叫的OSMutexPost介面中

->

任務C優先順序調整為原來的20,並將任務A放入就緒佇列

3,雖然和前面一樣任務C先於任務A執行,但是透過MUTEX機制,任務C在搶佔任務A的時候,擁有高於任務A的優先順序,即並沒有出現優先順序反轉。

雖然執行的效果依然是C在前,A在後,但是從CPU排程的角度看,並沒有出現優先順序的反轉。

互斥訊號量的資料結構

互斥訊號量的資料結構,利用上一個章節中,我們介紹的OS_EVENT結構體。僅僅在型別的變數,使用訊號量的專有宏定義:

OS_EVENT_TYPE_MUTEX

嵌入式作業系統-互斥訊號量mutex

這裡,

16個bit的OSEventCnt變數,存在特殊的含義

。高8bit用於存放建立該互斥訊號量時候,分配給該互斥訊號量的優先順序prio。低8bit用於存放成功申請到該互斥訊號量的任務prio,如果沒有被佔用則使用OS_MUTEX_AVAILABLE宏定義(0xFF)。

互斥訊號量的建立

互斥訊號量在使用之前,需要呼叫

OSMutexCreate

介面進行建立。該介面首先實現對輸入優先順序的驗證和佔用,然後從ucos管理的(EVENT_FREE_LIST)事件空閒佇列中尋找未使用的一個EVENT結構體,並對型別值進行賦值。建立介面返回後,分配的EVENT管理結構體資料如下圖所示:

嵌入式作業系統-互斥訊號量mutex

互斥訊號量的使用

在建立完互斥訊號量後,即可以進行使用。訊號量的使用,從工作的角度而言,主要有以下兩個常用的呼叫介面:

OSMutexPend

OSMutexPost

。其中:

OSMutexPend用於申請互斥訊號量資源,獲取成功後可以使用訊號量保護的共享資源。當獲取不成功的時候,該任務會掛起,等待該訊號量可用。其中,Mutex的防止優先順序反轉機制會自動在條件合適的情況下完成優先順序的升位。我們作為最後的使用者,在實際的工作中不需要關注過多。該介面的關鍵原始碼如下圖所示:

嵌入式作業系統-互斥訊號量mutex

OSMutexPost用於釋放佔用的互斥訊號量資源,使其他等待互斥訊號量的任務可以使用該互斥訊號量保護的共享資源。當釋放互斥訊號量的時候,會尋找到目前掛起在該訊號量下優先順序最高的任務,並將該任務放入就緒佇列同時出發系統排程,完成任務的切換。同時會自動完成Pend介面中低優先順序任務的優先順序恢復。具體過程(掛起的最高優先順序任務恢復)如下圖所示:

嵌入式作業系統-互斥訊號量mutex

互斥訊號量的銷燬

當訊號量不再被使用,可以選擇銷燬OSMutexDel訊號量(雖然這個操作很少在工作中使用到)。在銷燬訊號量的時候,必須注意可能有多個任務企圖使用已經銷燬的訊號量導致系統崩潰。總之,在銷燬訊號量之前,要刪除所有可能操作該訊號量的任務。

互斥訊號量的查詢

在應用程式中,我們可以呼叫介面隨時獲取OSMutexQuery訊號量的當前狀態。查詢結果會返回儲存在名為OS_MUTEX_DATA的資料結構中。具體該結構的定義如下圖所示:

嵌入式作業系統-互斥訊號量mutex

透過該資料結構,我們能獲取到被查詢的訊號量的資源數值,掛起在當前被查詢訊號量下的所有任務的優先順序列表。

注意事項

】OSMutexDel和OSMutexPend不可以在ISR中進行呼叫,

原因就在於

:呼叫者會被OSMutexPend掛起,但是ISR不能被掛起。

以上內容,僅僅是個人的經驗總結,如有疏漏和錯誤地方,還請各位知友批評指正共同進步。另外如果想對嵌入式作業系統有深入和權威的瞭解,還可以自行閱讀以下書籍。本文章系列僅僅站在答主個人的理解角度,力求用通俗的語言向嵌入式愛好者們普及嵌入式的一些理論和實戰知識。

如果對嵌入式開發存在問題和需要幫助,也可以與大家一起探討和解決。