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

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

3.遞歸鎖
1.任務(wù) A 獲得遞歸鎖 M 后,它還可以多次去獲得這個鎖
2."take"了 N 次,要"give"N 次,這個鎖才會被釋放
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個任務(wù): 一個上鎖, 另一個自己監(jiān)守自盜(開別人的鎖自己用)
xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL );
xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL );
/* 啟動調(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");
/* 阻塞很長時間, 讓另一個任務(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.運行流程分析
1.任務(wù) 1 優(yōu)先級最高,先運行,獲得遞歸鎖
2.任務(wù) 1 阻塞,讓任務(wù) 2 得以運行
3.任務(wù) 2 運行,看看能否獲得別人持有的遞歸鎖: 不能
4.任務(wù) 2 故意執(zhí)行"give"操作,看看能否釋放別人持有的遞歸鎖:不能
5.任務(wù) 2 等待遞歸鎖
6.任務(wù) 1 阻塞時間到后繼續(xù)運行,使用循環(huán)多次獲得、釋放遞歸鎖
6.運行結(jié)果

總結(jié)
誰持有遞歸鎖,必須由誰釋放。
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
詳解C語言內(nèi)核中的鏈表與結(jié)構(gòu)體
Windows內(nèi)核中是無法使用vector容器等數(shù)據(jù)結(jié)構(gòu)的,當我們需要保存一個結(jié)構(gòu)體數(shù)組時,就需要使用內(nèi)核中提供的專用鏈表結(jié)構(gòu)。本文分享了幾個內(nèi)核中使用鏈表存儲多個結(jié)構(gòu)體的通用案例,希望對你有所幫助2022-09-09
基于Qt實現(xiàn)C/C++調(diào)用Matlab函數(shù)全過程
這篇文章給大家詳細介紹了基于Qt平臺實現(xiàn)C/C++調(diào)用Matlab函數(shù)全流程,文中通過圖文和代碼示例給大家講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-01-01
VC中CWinThread類以及和createthread API的區(qū)別分析
這篇文章主要介紹了VC中CWinThread類以及和createthread API的區(qū)別分析,較為詳細的講述了CWinThread類的原理,并以實例形式對AfxBeginThread函數(shù)的內(nèi)部實現(xiàn)進行了解釋說明,需要的朋友可以參考下2014-10-10
C++ STL 內(nèi) std::{bind/tuple/function} 簡單實現(xiàn)
這篇文章主要介紹了C++ STL 內(nèi) std::{bind/tuple/function} 簡單實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-02-02
這篇文章主要介紹了C++強制轉(zhuǎn)換與智能指針示例,智能指針(Smart Pointer)是一種抽象的數(shù)據(jù)類型。在程序設(shè)計中,它通常是經(jīng)由類模板來實現(xiàn),借由模板來達成泛型,借由類別的析構(gòu)函數(shù)來達成自動釋放指針所指向的存儲器或?qū)ο?/div> 2022-11-11最新評論

