C語言 Freertos的遞歸鎖詳解
1.死鎖的概念
假設(shè)有 2 個(gè)互斥量 M1、 M2, 2 個(gè)任務(wù) A、 B: A 獲得了互斥量 M1 B 獲得了互斥量 M2 A 還要獲得互斥量 M2 才能運(yùn)行,結(jié)果 A 阻塞 B 還要獲得互斥量 M1 才能運(yùn)行,結(jié)果 B 阻塞 A、 B 都阻塞,再無法釋放它們持有的互斥量 死鎖發(fā)生!

2.自我死鎖
任務(wù) A 獲得了互斥鎖 M 它調(diào)用一個(gè)函數(shù) 函數(shù)要去獲取同一個(gè)互斥鎖 M,于是它阻塞:任務(wù) A 休眠,等待任務(wù) A 來釋放互斥鎖! 死鎖發(fā)生!

3.遞歸鎖
1.任務(wù) A 獲得遞歸鎖 M 后,它還可以多次去獲得這個(gè)鎖
2."take"了 N 次,要"give"N 次,這個(gè)鎖才會(huì)被釋放
3.誰上鎖就由誰解鎖。
遞歸鎖的函數(shù)根一般互斥量的函數(shù)名不一樣
| 遞歸鎖 | 一般互斥量 | |
|---|---|---|
| 創(chuàng)建 | xSemaphoreCreateRecursiveMutex | xSemaphoreCreateMutex |
| 獲得 | xSemaphoreTakeRecursive | xSemaphoreTake |
| 釋放 | xSemaphoreGiveRecursive | xSemaphoreGive |
4.代碼
main
/* 遞歸鎖句柄 */
SemaphoreHandle_t xMutex;
int main( void )
{
prvSetupHardware();
/* 創(chuàng)建遞歸鎖 */
xMutex = xSemaphoreCreateRecursiveMutex( );
if( xMutex != NULL )
{
/* 創(chuàng)建2個(gè)任務(wù): 一個(gè)上鎖, 另一個(gè)自己監(jiān)守自盜(開別人的鎖自己用)
xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL );
xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL );
/* 啟動(dòng)調(diào)度器 */
vTaskStartScheduler();
}
else
{
/* 無法創(chuàng)建遞歸鎖 */
}
return 0;
}
任務(wù)1
static void vTakeTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
BaseType_t xStatus;
int i;
/* 無限循環(huán) */
for( ;; )
{
/* 獲得遞歸鎖: 上鎖 */
xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
printf("Task1 take the Mutex in main loop %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
/* 阻塞很長時(shí)間, 讓另一個(gè)任務(wù)執(zhí)行,
* 看看它有無辦法再次獲得遞歸鎖
*/
vTaskDelay(xTicksToWait);
for (i = 0; i < 10; i++)
{
/* 獲得遞歸鎖: 上鎖 */
xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
printf("Task1 take the Mutex in sub loop %s, for time %d\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed", i);
/* 釋放遞歸鎖 */
xSemaphoreGiveRecursive(xMutex);
}
/* 釋放遞歸鎖 */
xSemaphoreGiveRecursive(xMutex);
}
}
任務(wù)2
static void vGiveAndTakeTask( void *pvParameters )
{
const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );
BaseType_t xStatus;
/* 嘗試獲得遞歸鎖: 上鎖 */
xStatus = xSemaphoreTakeRecursive(xMutex, 0);
printf("Task2: at first, take the Mutex %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
/* 如果失敗則監(jiān)守自盜: 開鎖 */
if (xStatus != pdTRUE)
{
/* 無法釋放別人持有的鎖 */
xStatus = xSemaphoreGiveRecursive(xMutex);
printf("Task2: give Mutex %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
}
/* 如果無法獲得, 一直等待 */
xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
printf("Task2: and then, take the Mutex %s\r\n", \
(xStatus == pdTRUE)? "Success" : "Failed");
/* 無限循環(huán) */
for( ;; )
{
/* 什么都不做 */
vTaskDelay(xTicksToWait);
}
}
5.運(yùn)行流程分析
1.任務(wù) 1 優(yōu)先級(jí)最高,先運(yùn)行,獲得遞歸鎖
2.任務(wù) 1 阻塞,讓任務(wù) 2 得以運(yùn)行
3.任務(wù) 2 運(yùn)行,看看能否獲得別人持有的遞歸鎖: 不能
4.任務(wù) 2 故意執(zhí)行"give"操作,看看能否釋放別人持有的遞歸鎖:不能
5.任務(wù) 2 等待遞歸鎖
6.任務(wù) 1 阻塞時(shí)間到后繼續(xù)運(yùn)行,使用循環(huán)多次獲得、釋放遞歸鎖
6.運(yùn)行結(jié)果

總結(jié)
誰持有遞歸鎖,必須由誰釋放。
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
項(xiàng)目之C++如何實(shí)現(xiàn)數(shù)據(jù)庫連接池
這篇文章主要介紹了項(xiàng)目之C++如何實(shí)現(xiàn)數(shù)據(jù)庫連接池問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
C++通過循環(huán)實(shí)現(xiàn)猜數(shù)字小游戲
這篇文章主要為大家詳細(xì)介紹了C++通過循環(huán)實(shí)現(xiàn)猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
C++面向行輸入之get()與getline()實(shí)例詳解
在c++里當(dāng)我們輸入一個(gè)字符串時(shí)習(xí)慣用cin,但是cin只能讀取一段不含空格的字符串,如果我們需要讀取一段包含空格的字符串時(shí),就需要用到getline()或get(),下面這篇文章主要給大家介紹了關(guān)于C++面向行輸入之get()與getline()的相關(guān)資料,需要的朋友可以參考下2021-10-10

