日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C語言?Freertos的遞歸鎖詳解_C 語言

作者:小陽先生的寶庫 ? 更新時間: 2022-05-12 編程語言

1.死鎖的概念

假設有 2 個互斥量 M1、 M2, 2 個任務 A、 B:
A 獲得了互斥量 M1
B 獲得了互斥量 M2
A 還要獲得互斥量 M2 才能運行,結果 A 阻塞
B 還要獲得互斥量 M1 才能運行,結果 B 阻塞
A、 B 都阻塞,再無法釋放它們持有的互斥量
死鎖發生!

在這里插入圖片描述

2.自我死鎖

任務 A 獲得了互斥鎖 M
它調用一個函數
函數要去獲取同一個互斥鎖 M,于是它阻塞:任務 A 休眠,等待任務 A
來釋放互斥鎖!
死鎖發生!

在這里插入圖片描述

3.遞歸鎖

1.任務 A 獲得遞歸鎖 M 后,它還可以多次去獲得這個鎖

2."take"了 N 次,要"give"N 次,這個鎖才會被釋放

3.誰上鎖就由誰解鎖。

遞歸鎖的函數根一般互斥量的函數名不一樣

? 遞歸鎖 一般互斥量
創建 xSemaphoreCreateRecursiveMutex xSemaphoreCreateMutex
獲得 xSemaphoreTakeRecursive xSemaphoreTake
釋放 xSemaphoreGiveRecursive xSemaphoreGive

4.代碼

main

/* 遞歸鎖句柄 */
SemaphoreHandle_t xMutex;
int main( void )
{
	prvSetupHardware();
    /* 創建遞歸鎖 */
    xMutex = xSemaphoreCreateRecursiveMutex( );
	if( xMutex != NULL )
	{
		/* 創建2個任務: 一個上鎖, 另一個自己監守自盜(開別人的鎖自己用)
		xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL );
		xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL );
		/* 啟動調度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無法創建遞歸鎖 */
	}
	return 0;
}

任務1

static void vTakeTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );	
	BaseType_t xStatus;
	int i;
	
	/* 無限循環 */
	for( ;; )
	{	
		/* 獲得遞歸鎖: 上鎖 */
		xStatus = xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
		printf("Task1 take the Mutex in main loop %s\r\n", \
			(xStatus == pdTRUE)? "Success" : "Failed");
		/* 阻塞很長時間, 讓另一個任務執行, 
		 * 看看它有無辦法再次獲得遞歸鎖 
		 */
		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);
	}
}

任務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");
	/* 如果失敗則監守自盜: 開鎖 */
	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");
	/* 無限循環 */
	for( ;; )
	{	
		/* 什么都不做 */
		vTaskDelay(xTicksToWait);
	}
}

5.運行流程分析

1.任務 1 優先級最高,先運行,獲得遞歸鎖

2.任務 1 阻塞,讓任務 2 得以運行

3.任務 2 運行,看看能否獲得別人持有的遞歸鎖: 不能

4.任務 2 故意執行"give"操作,看看能否釋放別人持有的遞歸鎖:不能

5.任務 2 等待遞歸鎖

6.任務 1 阻塞時間到后繼續運行,使用循環多次獲得、釋放遞歸鎖

6.運行結果

在這里插入圖片描述

總結

誰持有遞歸鎖,必須由誰釋放。

原文鏈接:https://blog.csdn.net/qq_49864684/article/details/123356999

欄目分類
最近更新