說明
本文僅作為學習FreeRTOS的記錄文檔,作為初學者肯定很多理解不對甚至錯誤的地方,望網友指正。
FreeRTOS是一個RTOS(實時操作系統)系統,支持搶占式、合作式和時間片調度。適用於微處理器或小型微處理器的實時應用。
本文檔使用的FreeRTOS版本:FreeRTOS Kernel V10.4.1
參考文檔:《FreeRTOS_Reference_Manual_V10.0.0.pdf》《FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf》《STM32F4 FreeRTOS開發手冊_V1.1.pdf》
參考視頻:正點原子FreeRTOS手把手教學-基於STM32_嗶哩嗶哩_bilibili
9 信號量
信號量是操作系統重要的一部分,一般用來進行資源管理和任務同步,FreeRTOS信號量分為二值信號量、計數型信號量、互斥信號量和遞歸型信號量。
9.1 二值信號量
9.1.1 相關說明
二值信號量通常用於互斥訪問或者同步。和互斥信號量的差別:互斥信號量有優先級繼承,二值信號量沒有優先級繼承,所有二值信號量適用於同步,而互斥信號量適用於互斥訪問。
和隊列一樣,信號量API函數允許設置一個阻塞時間,阻塞時間是當任務獲得信號的時候由於信號量無效從而導致任務進行阻塞態的最大時鍾節拍數,當信號量有效時高優先級任務就會解除阻塞狀態。
二值信號量就是只有一個隊列項的隊列,所以這個隊列要么滿的,要么空的。二值信號量的工作過程如下:
(1)二值信號量無效,任務阻塞等待信號量
(2)中斷發生,釋放了信號量
(3)任務獲取信號量成功,從阻塞狀態解除
(4)任務再次進入阻塞態,等待信號量
完整的一次流程如下:
9.1.2 相關函數
(1)動態創建信號量
函數原型:
#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t xSemaphoreCreateBinary( void );
函數描述:創建一個二值信號量,並返回信號量句柄。每一個信號量需要一個內存空間來存放信號量狀態。這個函數的創建的信號量空間由FreeRTOS自動分配。信號量創建之后是空的,任務這時候是無法獲得的。
函數參數:無
返回值:NULL:創建失敗。其他值:創建成功的二值信號量的句柄
(2)靜態創建信號量
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );
函數描述:創建一個二值信號量,並返回信號量句柄。每一個信號量需要一個內存空間來存放信號量狀態。這個函數的創建的信號量空間由用戶指定。信號量創建之后是空的,任務這時候是無法獲得的。
函數參數:pxSemaphoreBuffer:指向StaticSemaphore_t類型的變量,這個變量用來保存信號量的狀態。
返回值:NULL:創建失敗。其他值:創建成功的二值信號量的句柄
(3)任務級釋放信號量
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
函數描述:釋放信號量之前,信號量必須已經被創建了。
函數參數:xSemaphore:要釋放的信號量句柄
返回值:pdPASS:信號量釋放成功。pdFAIL:信號量釋放失敗。
(4)中斷級釋放信號量
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken );
函數描述:中斷級釋放信號量函數,在中斷處理函數中使用。
函數參數:xSemaphore:要釋放的信號量句柄;
pxHigherPriorityTaskWoken:標記退出此函數是否進行任務切換,此值為pdTRUE的時候在退出中斷函數之前要進行一次任務切換。
返回值:pdPASS:信號量釋放成功。errQUEUE_FULL:信號量釋放失敗,信號量已經被釋放了。
(5)任務級獲取信號量
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait );
函數描述:獲取信號量之前,信號量必須已經被創建了。
函數參數:xSemaphore:要獲取的信號量句柄;
xTicksToWait:當任務無法獲取到信號量,任務最大的保持阻塞的時間。如果為0,任務無法獲得信號量時將立即返回。阻塞時間指的時時鍾滴答數,所以阻塞的時間大小取決於系統頻率,可以使用pdMS_TO_TICKS() 宏來指定阻塞多少毫秒。如果為portMAX_DELAY,任務將一直等待。
返回值:pdPASS:信號量獲取成功。pdFAIL:信號量獲取失敗。
(6)中斷級獲取信號量
函數原型:
#include “FreeRTOS.h”
#include “queue.h”
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
signed BaseType_t *pxHigherPriorityTaskWoken );
函數描述:在中斷服務函數中獲取信號量。
函數參數:xSemaphore:要獲取的信號量句柄;
pxHigherPriorityTaskWoken:標記退出此函數后是否進行任務切換,此值為pdTRUE的時候在退出中斷函數之前要進行一次任務切換。
返回值:pdPASS:信號量獲取成功。pdFAIL:信號量獲取失敗。
9.1.3 操作實驗
實驗目的:使用二值信號量完成任務間的同步
實驗設計:任務task00定時釋放二值信號量,任務task01獲取二值信號量,接收到信號量就進行相應的動作。
測試代碼:
/* task00 info */
configSTACK_DEPTH_TYPE Task00_STACK_SIZE = 5;
UBaseType_t Task00_Priority = 1;
TaskHandle_t Task00_xHandle;
/* task01 info */
configSTACK_DEPTH_TYPE Task01_STACK_SIZE = 5;
UBaseType_t Task01_Priority = 2;
TaskHandle_t Task01_xHandle;
//二值信號量
SemaphoreHandle_t BinarySemaphore;
void vTask00_Code(void *para)
{
static unsigned int cnt = 0;
BaseType_t err = pdTRUE;
for (;;)
{
PRINT(" task00 cnt %u...", cnt++);
err = xSemaphoreGive(BinarySemaphore);
if (err != pdTRUE)
PRINT("BinarySemaphore give failed!\n");
vTaskDelay(2000);
}
}
void vTask01_Code(void *para)
{
static unsigned int cnt = 0;
BaseType_t err = pdTRUE;
for (;;)
{
xSemaphoreTake(BinarySemaphore, portMAX_DELAY);
PRINT(" task01 cnt %u...", cnt++);
vTaskDelay(500);
}
}
void test_BinarySemaphore()
{
BinarySemaphore = xSemaphoreCreateBinary();
if (xTaskCreate(vTask00_Code, "task00 task",
Task00_STACK_SIZE, NULL, Task00_Priority,
&Task00_xHandle) != pdPASS)
{
PRINT("creat task00 failed!\n");
}
if (xTaskCreate(vTask01_Code, "task01 task",
Task01_STACK_SIZE, NULL, Task01_Priority,
&Task01_xHandle) != pdPASS)
{
PRINT("creat task01 failed!\n");
}
}
void creat_task(void)
{
test_BinarySemaphore();
// test_queue();
}
編譯,運行:
$ ./build/freertos-simulator
task00 cnt 0...
task01 cnt 0...
task00 cnt 1...
task01 cnt 1...
task00 cnt 2...
task01 cnt 2...
可以看出,任務task01等到了信號量之后才會執行。
接着,將獲取信號量函數xSemaphoreTake的阻塞時間改為0,也就是沒獲取到信號量,立即返回。
void vTask01_Code(void *para)
{
static unsigned int cnt = 0;
BaseType_t err = pdTRUE;
for (;;)
{
xSemaphoreTake(BinarySemaphore, 0);
PRINT(" task01 cnt %u...", cnt++);
vTaskDelay(500);
}
}
編譯,運行:
$ ./build/freertos-simulator
task01 cnt 0...
task00 cnt 0...
task01 cnt 1...
task01 cnt 2...
task01 cnt 3...
task01 cnt 4...
task00 cnt 1...
可以看出,任務task01不會等待信號量,而是繼續執行。
9.1.4 優先級反轉
使用二值信號量會出現優先級反轉的問題,優先級反轉在可剝奪內核中是常見的,但在實時系統中不允許出現這種現象。
上述圖中,高任務H會晚於低優先級任務M執行,這就發生了優先級反轉。
優先級反轉實驗設計:
實驗設計:創建三個任務,高優先級任務獲取二值信號量,獲取成功后進行相應的處理,處理完之后釋放信號量;中優先級任務簡單運行;低優先級任務和高優先級任務一樣,會獲取二值信號量,獲取成功后進行相應處理。
測試代碼:
configSTACK_DEPTH_TYPE TaskLow_STACK_SIZE = 5;
UBaseType_t TaskLow_Priority = 2;
TaskHandle_t TaskLow_xHandle;
configSTACK_DEPTH_TYPE TaskMiddle_STACK_SIZE = 5;
UBaseType_t TaskMiddle_Priority = 3;
TaskHandle_t TaskMiddle_xHandle;
configSTACK_DEPTH_TYPE TaskHigh_STACK_SIZE = 5;
UBaseType_t TaskHigh_Priority = 4;
TaskHandle_t TaskHigh_xHandle;
//二值信號量
SemaphoreHandle_t BinarySemaphore;
void vTaskLow_Code(void *para)
{
static unsigned int times = 0;
BaseType_t err = pdTRUE;
for (;;)
{
xSemaphoreTake(BinarySemaphore, portMAX_DELAY);
PRINT(" low task running");
for (times = 0; times < 20000000; times++)
taskYIELD();
err = xSemaphoreGive(BinarySemaphore);
if (err != pdTRUE)
PRINT("BinarySemaphore give failed!");
vTaskDelay(1000);
}
}
void vTaskMiddle_Code(void *para)
{
for (;;)
{
PRINT(" task middle running");
vTaskDelay(1000);
}
}
void vTaskHigh_Code(void *para)
{
for (;;)
{
vTaskDelay(500);
PRINT(" task high Pend Sem");
xSemaphoreTake(BinarySemaphore, portMAX_DELAY);
PRINT(" task high running!");
xSemaphoreGive(BinarySemaphore);
vTaskDelay(500);
}
}
void test_BinarySemaphore()
{
taskENTER_CRITICAL();
BinarySemaphore = xSemaphoreCreateBinary();
if (BinarySemaphore != NULL)
xSemaphoreGive(BinarySemaphore);
if (xTaskCreate(vTaskLow_Code, "taskLow task",
TaskLow_STACK_SIZE, NULL, TaskLow_Priority,
&TaskLow_xHandle) != pdPASS)
{
PRINT("creat taskLow failed!\n");
}
if (xTaskCreate(vTaskMiddle_Code, "taskMiddle task",
TaskMiddle_STACK_SIZE, NULL, TaskMiddle_Priority,
&TaskMiddle_xHandle) != pdPASS)
{
PRINT("creat taskMiddle failed!\n");
}
if (xTaskCreate(vTaskHigh_Code, "taskHigh task",
TaskHigh_STACK_SIZE, NULL, TaskHigh_Priority,
&TaskHigh_xHandle) != pdPASS)
{
PRINT("creat taskHigh failed!\n");
}
taskEXIT_CRITICAL();
}
void creat_task(void)
{
test_BinarySemaphore();
}
編譯、運行:
$ ./build/freertos-simulator
task middle running
low task running
task high Pend Sem
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task middle running
task high running!
task middle running
task high Pend Sem
task high running!
low task running
task middle running
可以看出了優先級反轉,中優先級任務比高優先級任務先執行。
9.2 計數型信號量
計數型信號量也叫數值型信號量,其實質是長度大於1的隊列。
主要用於兩個場景:
1、事件計數:在這個場景中,每次事件發生時就在事件處理函數中釋放信號量,其他任務獲取信號量來處理事件。這種場合計數型信號量初始計數值為0。
2、資源管理:在這個場景中,信號量代表當前可用的資源數量。一個任務想要獲取資源的使用權,必須先獲得信號量,信號量獲取成功信號量就會減1,當信號量為0時就沒有信號量了。當一個任務使用完信號量之后要釋放信號量。這個場景中,信號量的初始值就是資源的數量。
9.2.1 相關函數
(1)動態創建函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount );
函數描述:創建一個計數型信號量,返回信號量的句柄。信號量的內存空間由系統指定。
函數參數:uxMaxCount:計數信號量的最大計數值,當信號量值等於這個值的時候釋放信號量就會失敗。
uxInitialCount:計數信號量初始值。
返回值:NULL:計數信號量創建失敗;其他值:計數信號量創建成功,返回計數信號量句柄。
(2)靜態創建函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t pxSempahoreBuffer );
函數描述:創建一個計數型信號量,返回信號量的句柄。信號量的內存空間由用戶指定。
函數參數:uxMaxCount:計數信號量的最大計數值,當信號量值等於這個值的時候釋放信號量就會失敗。
uxInitialCount:計數信號量初始值。
pxSempahoreBuffer:指向StaticSemaphore_t類型的變量,用於保存信號量結構體。
返回值:NULL:計數信號量創建失敗;其他值:計數信號量創建成功,返回計數信號量句柄。
(2)釋放和獲取函數
釋放和獲取函數和二值信號量的一樣,參見9.1.2小節。
9.2.2 操作實驗
實驗目的:學習計數型信號量的使用方法。
實驗設計:主函數中創建一個計數型信號量,計數值為10,初始化計數值為0,然后創建兩個任務,任務task00釋放信號量,任務task01獲取信號量。
測試代碼:
/* task00 info */
configSTACK_DEPTH_TYPE Task00_STACK_SIZE = 5;
UBaseType_t Task00_Priority = 1;
TaskHandle_t Task00_xHandle;
/* task01 info */
configSTACK_DEPTH_TYPE Task01_STACK_SIZE = 5;
UBaseType_t Task01_Priority = 3;
TaskHandle_t Task01_xHandle;
//計數型信號量
SemaphoreHandle_t CountSemaphore;
void vTask00_Code(void *para)
{
static unsigned int cnt = 0;
BaseType_t err = pdTRUE;
for (;;)
{
PRINT(" task00 cnt %u...", cnt++);
err = xSemaphoreGive(CountSemaphore);
if (err != pdTRUE)
PRINT("BinarySemaphore give failed!\n");
vTaskDelay(200);
if (cnt == 4)
vTaskDelete(Task00_xHandle);
}
}
void vTask01_Code(void *para)
{
static unsigned int cnt = 0;
BaseType_t err = pdTRUE;
for (;;)
{
xSemaphoreTake(CountSemaphore, portMAX_DELAY);
PRINT(" task01 cnt %u...", cnt++);
vTaskDelay(1000);
}
}
void test_CountSemaphore()
{
CountSemaphore = xSemaphoreCreateCounting(10, 0);
if (xTaskCreate(vTask00_Code, "task00 task",
Task00_STACK_SIZE, NULL, Task00_Priority,
&Task00_xHandle) != pdPASS)
{
PRINT("creat task00 failed!\n");
}
if (xTaskCreate(vTask01_Code, "task01 task",
Task01_STACK_SIZE, NULL, Task01_Priority,
&Task01_xHandle) != pdPASS)
{
PRINT("creat task01 failed!\n");
}
}
void creat_task(void)
{
test_CountSemaphore();
}
編譯、運行:
$ ./build/freertos-simulator
task00 cnt 0...
task01 cnt 0...
task00 cnt 1...
task00 cnt 2...
task00 cnt 3...
task01 cnt 1...
task01 cnt 2...
task01 cnt 3...
可以看出,共釋放了4個信號量,任務task1執行了4次。
9.3 互斥信號量
9.3.1 相關說明
互斥信號量其實就是一個擁有優先級繼承的二值信號量,在同步任務應用中二值信號量最合適,互斥信號量適用於那些需要互斥訪問的應用中。
互斥信號量和二值信號量使用相同的API函數,所以互斥信號量也可以設置阻塞時間,不同於二值信號量的是互斥信號量具有優先級繼承關系。當一個互斥信號量正在被低優先級的任務使用,而此時有個高優先級的任務也嘗試獲取這個信號量的話就會被阻塞。不過高優先級的任務會將低優先級的任務的優先級提升到與自己相同的優先級,這個過程就是優先級繼承。優先級繼承盡可能的降低了高優先級任務處於阻塞態的時間,並且將“優先級翻轉”的影響降低到了最低。
優先級繼承並不能完全的消除優先級翻轉,只是盡可能降低了優先級翻轉帶來的影響。
互斥信號量不能用於中斷服務函數中,原因如下:
1、互斥信號量有優先級繼承的機制,所以只能用在任務中,不能用於中斷服務函數;
2、中斷服務函數中不能因為要等待互斥信號量而設置阻塞時間進入阻塞態。
9.3.2 相關函數
(1)動態創建函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateMutex( void );
函數描述:創建一個互斥型信號量,返回信號量的句柄。信號量的內存空間由系統指定。
函數參數:無
返回值:NULL:信號量創建失敗;其他值:信號量創建成功,返回信號量句柄。
(2)靜態創建函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateMutexStatic(
StaticSemaphore_t *pxMutexBuffer );
函數描述:創建一個互斥型信號量,返回信號量的句柄。信號量的內存空間由用戶指定。
函數參數:pxMutexBuffer:指向StaticSemaphore_t類型的變量,用於保存信號量結構體。
返回值:NULL:信號量創建失敗;其他值:信號量創建成功,返回信號量句柄。
(3)釋放和獲取函數
釋放和獲取函數和二值信號量的一樣,參見9.1.2小節。
9.3.3 操作實驗
實驗目的:學習互斥型信號量的使用方法。
實驗設計:本實驗在“9.1.4 優先級反轉”的基礎上完成,只是將其中二值信號量更換為互斥信號量。
測試代碼:
configSTACK_DEPTH_TYPE TaskLow_STACK_SIZE = 5;
UBaseType_t TaskLow_Priority = 2;
TaskHandle_t TaskLow_xHandle;
configSTACK_DEPTH_TYPE TaskMiddle_STACK_SIZE = 5;
UBaseType_t TaskMiddle_Priority = 3;
TaskHandle_t TaskMiddle_xHandle;
configSTACK_DEPTH_TYPE TaskHigh_STACK_SIZE = 5;
UBaseType_t TaskHigh_Priority = 4;
TaskHandle_t TaskHigh_xHandle;
SemaphoreHandle_t MutexSemaphore;
void vTaskLow_Code(void *para)
{
static unsigned int times = 0;
BaseType_t err = pdTRUE;
for (;;)
{
xSemaphoreTake(MutexSemaphore, portMAX_DELAY);
PRINT(" low task running");
for (times = 0; times < 20000000; times++)
taskYIELD();
err = xSemaphoreGive(MutexSemaphore);
if (err != pdTRUE)
PRINT("BinarySemaphore give failed!");
vTaskDelay(1000);
}
}
void vTaskMiddle_Code(void *para)
{
for (;;)
{
PRINT(" task middle running");
vTaskDelay(1000);
}
}
void vTaskHigh_Code(void *para)
{
for (;;)
{
vTaskDelay(500);
PRINT(" task high Pend Sem");
xSemaphoreTake(MutexSemaphore, portMAX_DELAY);
PRINT(" task high running!");
xSemaphoreGive(MutexSemaphore);
vTaskDelay(500);
}
}
void test_MutexSemaphore()
{
taskENTER_CRITICAL();
MutexSemaphore = xSemaphoreCreateMutex();
if (MutexSemaphore != NULL)
xSemaphoreGive(MutexSemaphore);
if (xTaskCreate(vTaskLow_Code, "taskLow task",
TaskLow_STACK_SIZE, NULL, TaskLow_Priority,
&TaskLow_xHandle) != pdPASS)
{
PRINT("creat taskLow failed!\n");
}
if (xTaskCreate(vTaskMiddle_Code, "taskMiddle task",
TaskMiddle_STACK_SIZE, NULL, TaskMiddle_Priority,
&TaskMiddle_xHandle) != pdPASS)
{
PRINT("creat taskMiddle failed!\n");
}
if (xTaskCreate(vTaskHigh_Code, "taskHigh task",
TaskHigh_STACK_SIZE, NULL, TaskHigh_Priority,
&TaskHigh_xHandle) != pdPASS)
{
PRINT("creat taskHigh failed!\n");
}
taskEXIT_CRITICAL();
}
void creat_task(void)
{
test_MutexSemaphore();
}
編譯,運行,測試結果如下:
$ ./build/freertos-simulator
task middle running
low task running
task high Pend Sem //此時信號量被任務low_task占用,會一直等待任務low_task釋放信號量。
task high running! //高優先級任務等待一段時間才運行,但中優先級任務不會運行。
task middle running
task high Pend Sem
task high running!
task middle running
low task running
task high Pend Sem
9.4 遞歸互斥信號量
9.4.1 相關說明
遞歸互斥信號量可以看作是一個特殊的互斥信號量,已經獲取了互斥信號量的任務就不能再次獲取這個信號量,但是遞歸信號量不同,已經獲取了遞歸互斥信號量的任務可以再次獲取這個信號量,而且次數不限。任務獲取了多少次遞歸信號量就要釋放多少次。
遞歸互斥信號量也有優先級繼承機制,所以當任務使用完遞歸信號量之后一定要釋放。
同互斥信號量一樣,遞歸信號量也不能用在中斷服務函數中:
1、由於優先級繼承的存在,就限定了遞歸互斥信號量只能用在任務中,不能用在中斷函數中。
2、中斷服務函數不能設置阻塞時間。
9.4.2 相關函數
(1)動態創建函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );
函數描述:創建一個遞歸互斥信號量,返回信號量的句柄。信號量的內存空間由系統指定。
函數參數:無
返回值:NULL:信號量創建失敗;其他值:信號量創建成功,返回信號量句柄。
(2)靜態創建函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(
StaticSemaphore_t pxMutexBuffer );
函數描述:創建一個遞歸互斥信號量,返回信號量的句柄。信號量的內存空間由用戶指定。
函數參數:pxMutexBuffer:指向StaticSemaphore_t類型的變量,用於保存信號量結構體。
返回值:NULL:信號量創建失敗;其他值:信號量創建成功,返回信號量句柄。
(3)釋放遞歸型互斥信號量函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex );
函數描述:釋放遞歸互斥信號量。
函數參數:xMutex:信號量句柄。
返回值:pdPASS:釋放信號量成功;pdFAIL:釋放信號量失敗。
(4)獲取遞歸型互斥信號量函數
函數原型:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,
TickType_t xTicksToWait );
函數描述:獲取遞歸互斥信號量。
函數參數:xMutex:信號量句柄。xTicksToWait:阻塞時間。
返回值:pdPASS:獲取信號量成功;pdFAIL:獲取信號量失敗。
9.4.3 操作實驗
實驗目的:學習遞歸互斥型信號量的使用方法。
實驗設計:創建一個任務,任務處理函數中每次獲取遞歸互斥信號量三次,釋放信號量三次。
測試代碼:
configSTACK_DEPTH_TYPE Task0_STACK_SIZE = 5;
UBaseType_t Task0_Priority = 2;
TaskHandle_t Task0_xHandle;
SemaphoreHandle_t RecursiveMutexSemaphore;
void vTask0_Code(void *para)
{
for (;;)
{
if (xSemaphoreTakeRecursive(RecursiveMutexSemaphore, 10) == pdTRUE) {
xSemaphoreTakeRecursive(RecursiveMutexSemaphore, 10);
xSemaphoreTakeRecursive(RecursiveMutexSemaphore, 10);
PRINT("RecursiveMutexSemaphore take!");
xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
PRINT("RecursiveMutexSemaphore give!");
}
vTaskDelay(1000);
}
}
void test_RecursiveMutexSemaphore()
{
taskENTER_CRITICAL();
RecursiveMutexSemaphore = xSemaphoreCreateRecursiveMutex();
if (RecursiveMutexSemaphore != NULL) {
xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
}
if (xTaskCreate(vTask0_Code, "taskLow task",
Task0_STACK_SIZE, NULL, Task0_Priority,
&Task0_xHandle) != pdPASS)
{
PRINT("creat taskLow failed!\n");
}
taskEXIT_CRITICAL();
}
void creat_task(void)
{
test_RecursiveMutexSemaphore();
}
編譯、運行,結果如下:
$ ./build/freertos-simulator
RecursiveMutexSemaphore take!
RecursiveMutexSemaphore give!
RecursiveMutexSemaphore take!
RecursiveMutexSemaphore give!