1. 程式人生 > >FreeRTOS 二值信號量,互斥信號量

FreeRTOS 二值信號量,互斥信號量

形象 iii 說明 reat 互斥 機制 容易 del 情況

本章節講解 FreeRTOS 任務間的同步和資源共享機制,二值信號量。 二值信號量是計數信號量的一種特殊形式,即共享資源為 1 的情況。

FreeRTOS 分別提供了二值信號量和計數信號量,其中二值信號量可以理解成計數
信號量的一種特殊形式,即初始化為僅有一個資源可以使用,只不過 FreeRTOS 對這兩種都提供了 API
函數,而像 RTX,uCOS-II 和 III 是僅提供了一個信號量功能,設置不同的初始值就可以分別實現二值信
號量和計數信號量。 當然,FreeRTOS 使用計數信號量也能夠實現同樣的效果。 另外,為什麽叫二值信號
量呢?因為信號量資源被獲取了,信號量值就是 0,信號量資源被釋放,信號量值就是 1,把這種只有 0


和 1 兩種情況的信號量稱之為二值信號量

函數 xSemaphoreCreateBinary
函數原型:
SemaphoreHandle_t xSemaphoreCreateBinary(void)
函數描述:
函數 xSemaphoreCreateBinary 用於創建二值信號量。
? 返回值,如果創建成功會返回二值信號量的句柄,如果由於 FreeRTOSConfig.h 文件中 heap 大小不
足,無法為此二值信號量提供所需的空間會返回 NULL。

技術分享

FreeRTOS 重要的資源共享機制---互斥信號量(Mutex,即 Mutual Exclusion 的縮寫)。
註意,建議初學者學習完前兩個信號量後再學習本章節的互斥信號量


互斥信號量的主要作用是對資源實現互斥訪問,使用二值信號量也可以實現互斥訪問的功能,不過互
斥信號量與二值信號量有區別。 下面我們先舉一個通過二值信號量實現資源獨享,即互斥訪問的例子,讓
大家有一個形象的認識,進而引出要講解的互斥信號量。
運行條件:
? 讓兩個任務 Task1 和 Task2 都運行串口打印函數 printf,這裏我們就通過二值信號量實現對函數
printf 的互斥訪問。 如果不對函數 printf 進行互斥訪問,串口打印容易出現亂碼。
? 用計數信號量實現二值信號量只需將計數信號量的初始值設置為 1 即可。
代碼實現:

技術分享

技術分享

技術分享

技術分享

技術分享

有了上面二值信號量的認識之後,互斥信號量與二值信號量又有什麽區別呢?互斥信號量可以防止優
先級翻轉,而二值信號量不支持,下面我們就講解一下優先級翻轉問題。

技術分享

運行條件:
? 創建 3 個任務 Task1,Task2 和 Task3,優先級分別為 3,2,1。 也就是 Task1 的優先級最高。
? 任務 Task1 和 Task3 互斥訪問串口打印 printf,采用二值信號實現互斥訪問。
? 起初 Task3 通過二值信號量正在調用 printf,被任務 Task1 搶占,開始執行任務 Task1,也就是上圖的起始位置。
運行過程描述如下:
? 任務 Task1 運行的過程需要調用函數 printf,發現任務 Task3 正在調用,任務 Task1 會被掛起,等
待 Task3 釋放函數 printf。
? 在調度器的作用下,任務 Task3 得到運行,Task3 運行的過程中,由於任務 Task2 就緒,搶占了 Task3
的運行。 優先級翻轉問題就出在這裏了,從任務執行的現象上看,任務 Task1 需要等待 Task2 執行
完畢才有機會得到執行,這個與搶占式調度正好反了,正常情況下應該是高優先級任務搶占低優先級
任務的執行,這裏成了高優先級任務 Task1 等待低優先級任務 Task2 完成。 所以這種情況被稱之為
優先級翻轉問題
? 任務 Task2 執行完畢後,任務 Task3 恢復執行,Task3 釋放互斥資源後,任務 Task1 得到互斥資源,
從而可以繼續執行。
FreeRTOS 互斥信號量的實現
FreeRTOS 互斥信號量是怎麽實現的呢?其實相對於二值信號量,互斥信號量就是解決了一下優先級
翻轉的問題。 下面我們通過如下的框圖來說明一下 FreeRTOS 互斥信號量的實現,讓大家有一個形象的認識。技術分享

運行條件:
? 創建 2 個任務 Task1 和 Task2,優先級分別為 1 和 3,也就是任務 Task2 的優先級最高。
? 任務 Task1 和 Task2 互斥訪問串口打印 printf。
? 使用 FreeRTOS 的互斥信號量實現串口打印 printf 的互斥訪問。
運行過程描述如下:
? 低優先級任務 Task1 執行過程中先獲得互斥資源 printf 的執行。 此時任務 Task2 搶占了任務 Task1
的執行,任務 Task1 被掛起。 任務 Task2 得到執行。
? 任務 Task2 執行過程中也需要調用互斥資源,但是發現任務 Task1 正在訪問,此時任務 Task1 的優
先級會被提升到與 Task2 同一個優先級,也就是優先級 3,這個就是所謂的優先級繼承(Priority
inheritance),這樣就有效地防止了優先級翻轉問題。 任務 Task2 被掛起,任務 Task1 有新的優先
級繼續執行。
? 任務 Task1 執行完畢並釋放互斥資源後,優先級恢復到原來的水平。 由於互斥資源可以使用,任務
Task2 獲得互斥資源後開始執行。
FreeRTOS 中斷方式互斥信號量的實現
互斥信號量僅支持用在 FreeRTOS 的任務中,中斷函數中不可使用。
互斥信號量 API 函數
函數 xSemaphoreCreateMutex
函數原型:
SemaphoreHandle_t xSemaphoreCreateMutex( void )
函數描述:
函數 xSemaphoreCreateMutex 用於創建互斥信號量。
? 返回值,如果創建成功會返回互斥信號量的句柄,如果由於 FreeRTOSConfig.h 文件中 heap 大小不
足,無法為此互斥信號量提供所需的空間會返回 NULL。
使用這個函數要註意以下問題:
1. 此函數是基於函數 xQueueCreateMutex 實現的:
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
函數 xQueueCreateMutex 的實現是基於消息隊列函數 xQueueGenericCreate 實現的。
2. 使用此函數要在 FreeRTOSConfig.h 文件中使能宏定義:
#define configUSE_MUTEXES 1

互斥信號量, xSemaphoreTake 和 xSemaphoreGive 一定要成對的調用
技術分享




FreeRTOS 二值信號量,互斥信號量