FreeRTOS 學習五:訊號量和互斥鎖
阿新 • • 發佈:2018-12-31
1. 簡介:
- 此篇文章中涉及的函式除特殊說明,包含的標頭檔案都是 semphr.h
- 二值訊號量同linux中的原子量,我們可以看成像是一個鎖,在使用的時候,需要能拿到鎖才能執行程式,嘗試拿不到鎖,不能執行。
- 二值訊號量和互斥鎖功能很相似,但是也有一些微妙的不同,互斥鎖包括一個優先順序整合機制,二值訊號量沒有。因此,任務和任務、任務和中斷之間的同步的時候,二值訊號量是一個更好的選擇。簡單的排斥情況使用互斥鎖
2. 函式
2.1 二值訊號量建立:
typedef void * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;
SemaphoreHandle_t xSemaphoreCreateBinary( void );
- 返回值:
- 非NULL,返回的是一個二值訊號量的指標又叫控制代碼
- NULL,因記憶體不足,建立不成功
- 說明:
- 1.在FreeRTOS的這個函式的介面上有一個重要的提示,在大多數情況下,直接使用任務的notification會比直接使用這個二值訊號量要對記憶體使用高效,此函式依然
- 2.這個函式的使用需要配置巨集 configSUPPORT_DYNAMIC_ALLOCATION = 1,不過這個值預設就是1
- 3.每個二值訊號量都需要一點ram空間來儲存訊號量的狀態
- 4.此函式也有一個xSemaphoreCreateBinaryStatic()函式,用於在編譯的時候就確定在ram中的位置
- 5.vSemaphoreCreateBinary函式是之前版本的函式,現版本使用的是xSemaphore…
2.2 訊號量建立:
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
- 引數:
- uxMaxCount,最大計數量
- uxInitialCount ,訊號量的初始值,當此訊號量用於資源管理,值應該為0,當用於資源管理時,應該設為uxMaxCount
- 返回值:
- 非NULL,訊號量的控制代碼
- NULL,因記憶體空間不足,建立失敗
- 說明:
- 1.這個函式的使用需要配置巨集 configSUPPORT_DYNAMIC_ALLOCATION = 1,不過這個值預設就是1
- 2.此函式也有一個static字尾的函式:xSemaphoreCreateCountingStatic,在是編譯的時候分配固定的地址
2.3 互斥量建立:
SemaphoreHandle_t xSemaphoreCreateMutex( void );
- 返回值:
- 非NULL,訊號量的控制代碼
- NULL,因記憶體空間不足,建立失敗
- 說明:
- 1.這個函式的使用需要配置巨集 configSUPPORT_DYNAMIC_ALLOCATION = 1,不過這個值預設就是1
- 2.此函式也有一個static字尾的函式:xSemaphoreCreateMutexStatic,在是編譯的時候分配固定的地址
2.4 遞迴互斥鎖建立:
遞迴互斥鎖的使用是為了部分情況下解決死鎖的問題,死鎖出現的情況如下程式碼:
// 不加鎖版本
void foo_nolock()
{
// do something
}
// 加鎖版本
void fun()
{
mutex.lock();
foo_nolock();
mutex.unlock();
}
言歸正傳:
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );
- 返回值:
- 非NULL,訊號量的控制代碼
- NULL,因記憶體空間不足,建立失敗
- 說明:
- 1.此函式需要配置 configSUPPORT_DYNAMIC_ALLOCATION = 1 和 configUSE_RECURSIVE_MUTEXES = 1,預設值,兩個都是1
- 2.有一個static字尾的函式,此處不多說,需要配置configSUPPORT_DYNAMIC_ALLOCATION = 0
2.5 刪除訊號量:
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
- 引數:
- xSemaphore,要操作的訊號量的控制代碼
- 說明:
- 能刪除遞迴訊號量和非遞迴的訊號量
- 不要刪除阻塞任務的訊號量
2.6 獲取訊號量:
xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
/* 中斷中使用 */
xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken );
/* 遞迴互斥量時獲取 */
xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex, TickType_t xTicksToWait );
- 引數:
- xSemaphore,訊號量的控制代碼
- xMutex,互斥鎖的控制代碼
- xTicksToWait,阻塞等待時間,portTICK_PERIOD_MS用於將ms單位轉換成tick,如果 INCLUDE_vTaskSuspend = 1,這個值設成portMAX_DELAY,則會限阻塞等待
- pxHigherPriorityTaskWoken,如果中斷中呼叫中斷的這個函式引起一個任務從阻塞態變成非阻塞狀態,並且變成非阻塞狀態的優先順序高於目前的任務,這個指標指向的變數的值變成pdTRUE
- xSemaphoreTake和xSemaphoreTakeRecursive返回值:
- pdTRUE,獲取成功
- pdFALSE,時間超時後,還沒得到訊號量
- xSemaphoreTakeFromISR返回值:
- pdTRUE,獲取成功
- pdFALSE,獲取不成功
2.7 歸還/釋放訊號量:
xSemaphoreGive( SemaphoreHandle_t xSemaphore );
/* 中斷中使用 */
xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken );
/* 遞迴互斥量時使用 */
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex);
- 引數:
- xSemaphore,訊號量的控制代碼
- xMutex,互斥鎖的控制代碼
- xTicksToWait,阻塞等待時間,portTICK_PERIOD_MS用於將ms單位轉換成tick,如果 INCLUDE_vTaskSuspend = 1,這個值設成portMAX_DELAY,則會限阻塞等待
- pxHigherPriorityTaskWoken,如果中斷中呼叫中斷的這個函式引起一個任務從阻塞態變成非阻塞狀態,並且變成非阻塞狀態的優先順序高於目前的任務,這個指標指向的變數的值變成pdTRUE,之後應該有一個任務上線文的切換
- xSemaphoreGive返回值:
- pdTRUE,釋放成功
- pdFALSE,釋放出現錯誤
- xSemaphoreGiveFromISR返回值:
- pdTRUE,釋放成功
- errQUEUE_FULL,釋放出現錯誤
- xSemaphoreGiveRecursive返回值:
- pdTRUE,釋放成功
2.8 其他對訊號量的操作:
/* 查詢訊號量的數目 */
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
/* 查詢擁有互斥鎖的任務控制代碼 */
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
- uxSemaphoreGetCount返回值:
- 返回訊號量的數目
- xSemaphoreGetMutexHolder返回值:
- 非NULL,任務持有互斥訊號量的任務控制代碼
- NULL,xMutex不是一個互斥訊號量或者訊號量沒有被任務持有
- xSemaphoreGetMutexHolder需要注意:
- 需要配置configUSE_MUTEXES = INCLUDE_xSemaphoreGetMutexHolder = 1