信號量的簡介
reeRTOS中的信號量是一種用于任務間同步和資源管理的機制。信號量可以是二進制的(只能取0或1)也可以是計數型的(可以是任意正整數)。信號量的基本操作包括“獲取”和“釋放”。
比如動車上的衛生間,一個衛生間同時只能容納一個人,由指示燈來表示是否有人在使用。當我們想使用衛生間的時候,有如下過程:
1、判斷衛生間是否有人使用(判斷信號量是否有資源)
2、衛生間空閑(信號量有資源),那么就可以直接進入衛生間(獲取信號量成功)
3、衛生間使用中(信號量沒有資源),那么這個人可以選擇不上衛生間(獲取信號量失敗),也可以在門口等待(任務阻塞)
信號量與隊列的區別如下:
信號量 | 隊列 |
主要用于管理對共享資源的訪問,確保在同一時刻只有一個任務可以訪問共享資源 | 用于任務之間的數據通信,通過在任務之間傳遞消息,實現信息的傳遞和同步。 |
可以是二進制信號量(Binary Semaphore)或計數信號量(Counting Semaphore) | 存儲和傳遞消息的數據結構,任務可以發送消息到隊列,也可以從隊列接收消息。 |
適用于對資源的互斥訪問,控制任務的執行順序,或者限制同時訪問某一資源的任務數量。 | 適用于在任務之間傳遞數據,實現解耦和通信。 |
二值信號量?
二值信號量(Binary Semaphore)是一種特殊類型的信號量,它只有兩個可能的值:0和1。這種信號量主要用于實現對共享資源的互斥訪問或者任務之間的同步。
- 兩個狀態: 二值信號量只能處于兩個狀態之一,通常用0和1表示。當信號量的值為0時,表示資源不可用;當值為1時,表示資源可用。
- 互斥訪問: 常用于控制對共享資源的互斥訪問,確保在同一時刻只有一個任務可以訪問共享資源。任務在訪問資源之前會嘗試獲取信號量,成功則繼續執行,失敗則等待。
- 任務同步: 也可以用于任務之間的同步,例如一個任務等待另一個任務完成某個操作。
信號量 API 函數允許指定阻塞時間。 阻塞時間表示當一個任務試圖“獲取”信號量時, 如果信號不是立即可用,那么該任務進入阻塞狀態的最大 “tick” 數。 如果 多個任務在同一個信號量上阻塞,那么具有最高優先級的任務將在下次信號量可用時最先解除阻塞 。
可將二進制信號量視為僅能容納一個項目的隊列。 因此,隊列只能為空或滿(因此稱為二值)。 使用隊列的任務和中斷 不在乎隊列容納的是什么——它們只想知道隊列是空的還是滿的。 可以 利用該機制來同步任務和中斷。
二值信號量相關函數:
函數 | 描述 |
xSemaphoreCreateBinary() | 使用動態方式創建二值信號量 |
xSemaphoreCreateBinaryStatic() | 使用靜態方式創建二值信號量 |
xSemaphoreGive() | 釋放信號量 |
xSemaphoreGiveFromISR() | 在中斷中釋放信號量 |
xSemaphoreTake() | 獲取信號量 |
xSemaphoreTakeFromISR() | 在中斷中獲取信號量 |
?計數型信號量
正如二進制信號量可以被認為是長度為 1 的隊列那樣,計數信號量也可以被認為是長度大于 1 的隊列。 信號量的用戶對存儲在隊列中的數據不感興趣,他們只關心隊列是否為空。
計數信號量通常用于兩種情況:
1、事件計數:在此使用方案中,每次事件發生時,事件處理程序將“給出”一個信號量(信號量計數值遞增) ,并且 處理程序任務每次處理事件(信號量計數值遞減)時“獲取”一個信號量。因此,計數值是 已發生的事件數與已處理的事件數之間的差值。在這種情況下, 創建信號量時計數值可以為零。
2、資源管理:在此使用情景中,計數值表示可用資源的數量。要獲得對資源的控制權,任務必須首先獲取 一個信號量——同時遞減信號量計數值。當計數值達到零時,表示沒有空閑資源可用。當任務使用完資源時, “返還”一個信號量——同時遞增信號量計數值。在這種情況下, 創建信號量時計數值可以等于最大計數值。
計數型信號量相關函數:
函數 | 描述 |
xSemaphoreCreateCounting() | 使用動態方法創建計數型信號量。 |
xSemaphoreCreateCountingStatic() | 使用靜態方法創建計數型信號量 |
uxSemaphoreGetCount() | 獲取信號量的計數值 |
優先級翻轉簡介?
優先級翻轉是一個在實時系統中可能出現的問題,特別是在多任務環境中。該問題指的是一個較低優先級的任務阻塞了一個較高優先級任務的執行,從而導致高優先級任務無法及時完成。
典型的優先級翻轉場景如下:
- 任務A(高優先級):擁有高優先級,需要訪問共享資源,比如一個關鍵數據結構。
- 任務B(低優先級):擁有低優先級,目前正在訪問該共享資源。
- 任務C(中優先級):位于任務A和任務B之間,具有介于兩者之間的優先級。
具體流程如下:
- 任務A開始執行,但由于任務B正在訪問共享資源,任務A被阻塞等待。
- 任務C獲得執行權,由于優先級高于任務B,它可以搶占任務B。
- 任務C執行完成后,任務B被解除阻塞,開始執行,完成后釋放了共享資源。
- 任務A重新獲取執行權,繼續執行。
這個過程中,任務A因為資源被占用而被阻塞,而任務B卻被中優先級的任務C搶占,導致任務B無法及時完成。這種情況稱為優先級翻轉,因為任務C的介入翻轉了高優先級任務A的執行順序。
互斥信號量?
互斥信號量是包含優先級繼承機制的二進制信號量。二進制信號量能更好實現實現同步(任務間或任務與中斷之間), 而互斥信號量有助于更好實現簡單互斥(即相互排斥)。
優先級繼承是一種解決實時系統中任務調度引起的優先級翻轉問題的機制。在具體的任務調度中,當一個高優先級任務等待一個低優先級任務所持有的資源時,系統會提升低優先級任務的優先級,以避免高優先級任務長時間等待的情況。
優先級繼承無法完全解決優先級翻轉,只是在某些情況下將影響降至最低。
不能在中斷中使用互斥信號量,原因如下:
- 互斥信號量使用的優先級繼承機制要求從任務中(而不是從中斷中)獲取和釋放互斥信號量。
- 中斷無法保持阻塞來等待一個被互斥信號量保護的資源。
互斥信號量相關函數:
函數 | 描述 |
xSemaphoreCreateMutex() | 使用動態方法創建互斥信號量。 |
xSemaphoreCreateMutexStatic() | 使用靜態方法創建互斥信號量。 |
互斥信號量的獲取和釋放函數與二值信號量的相應函數相似,但有一個重要的區別:互斥信號量不支持在中斷服務程序中直接調用。注意,當創建互斥信號量時,系統會自動進行一次信號量的釋放操作。