一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

韋東山freeRTOS系列教程之互斥量(mutex)(7)

嵌入式Linux那些事 ? 2021-12-13 14:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

文章目錄

  • 系列教程總目錄
  • 概述
  • 7.1 互斥量的使用場(chǎng)合
  • 7.2 互斥量函數(shù)
    • 7.2.1 創(chuàng)建
    • 7.2.2 其他函數(shù)
  • 7.3 示例15: 互斥量基本使用
  • 7.4 示例16: 誰(shuí)上鎖就由誰(shuí)解鎖?
  • 7.5 示例17: 優(yōu)先級(jí)反轉(zhuǎn)
  • 7.6 示例18: 優(yōu)先級(jí)繼承
  • 7.7 遞歸鎖
    • 7.7.1 死鎖的概念
    • 7.7.2 自我死鎖
    • 7.7.3 函數(shù)
    • 7.7.4 示例19: 遞歸鎖
  • 7.8 常見(jiàn)問(wèn)題

需要獲取更好閱讀體驗(yàn)的同學(xué),請(qǐng)?jiān)L問(wèn)我專(zhuān)門(mén)設(shè)立的站點(diǎn)查看,地址:http://rtos.100ask.net/

系列教程總目錄

本教程連載中,篇章會(huì)比較多,為方便同學(xué)們閱讀,點(diǎn)擊這里可以查看文章的 目錄列表,目錄列表頁(yè)面地址:https://blog.csdn.net/thisway_diy/article/details/121399484

概述

怎么獨(dú)享廁所?自己開(kāi)門(mén)上鎖,完事了自己開(kāi)鎖。

你當(dāng)然可以進(jìn)去后,讓別人幫你把門(mén):但是,命運(yùn)就掌握在別人手上了。

使用隊(duì)列、信號(hào)量,都可以實(shí)現(xiàn)互斥訪問(wèn),以信號(hào)量為例:

  • 信號(hào)量初始值為1
  • 任務(wù)A想上廁所,"take"信號(hào)量成功,它進(jìn)入廁所
  • 任務(wù)B也想上廁所,"take"信號(hào)量不成功,等待
  • 任務(wù)A用完廁所,"give"信號(hào)量;輪到任務(wù)B使用

這需要有2個(gè)前提:

  • 任務(wù)B很老實(shí),不撬門(mén)(一開(kāi)始不"give"信號(hào)量)
  • 沒(méi)有壞人:別的任務(wù)不會(huì)"give"信號(hào)量

可以看到,使用信號(hào)量確實(shí)也可以實(shí)現(xiàn)互斥訪問(wèn),但是不完美。

使用互斥量可以解決這個(gè)問(wèn)題,互斥量的名字取得很好:

  • 量:值為0、1
  • 互斥:用來(lái)實(shí)現(xiàn)互斥訪問(wèn)

它的核心在于:誰(shuí)上鎖,就只能由誰(shuí)開(kāi)鎖。

很奇怪的是,FreeRTOS的互斥鎖,并沒(méi)有在代碼上實(shí)現(xiàn)這點(diǎn):

  • 即使任務(wù)A獲得了互斥鎖,任務(wù)B竟然也可以釋放互斥鎖。
  • 誰(shuí)上鎖、誰(shuí)釋放:只是約定。

本章涉及如下內(nèi)容:

為什么要實(shí)現(xiàn)互斥操作

怎么使用互斥量

互斥量導(dǎo)致的優(yōu)先級(jí)反轉(zhuǎn)、優(yōu)先級(jí)繼承

7.1 互斥量的使用場(chǎng)合

在多任務(wù)系統(tǒng)中,任務(wù)A正在使用某個(gè)資源,還沒(méi)用完的情況下任務(wù)B也來(lái)使用的話,就可能導(dǎo)致問(wèn)題。

比如對(duì)于串口,任務(wù)A正使用它來(lái)打印,在打印過(guò)程中任務(wù)B也來(lái)打印,客戶看到的結(jié)果就是A、B的信息混雜在一起。

這種現(xiàn)象很常見(jiàn):

訪問(wèn)外設(shè):剛舉的串口例子

讀、修改、寫(xiě)操作導(dǎo)致的問(wèn)題
對(duì)于同一個(gè)變量,比如int a,如果有兩個(gè)任務(wù)同時(shí)寫(xiě)它就有可能導(dǎo)致問(wèn)題。
對(duì)于變量的修改,C代碼只有一條語(yǔ)句,比如:a=a+8;,它的內(nèi)部實(shí)現(xiàn)分為3步:讀出原值、修改、寫(xiě)入。

在這里插入圖片描述

我們想讓任務(wù)A、B都執(zhí)行add_a函數(shù),a的最終結(jié)果是1+8+8=17。
假設(shè)任務(wù)A運(yùn)行完代碼①,在執(zhí)行代碼②之前被任務(wù)B搶占了:現(xiàn)在任務(wù)A的R0等于1。
任務(wù)B執(zhí)行完add_a函數(shù),a等于9。
任務(wù)A繼續(xù)運(yùn)行,在代碼②處R0仍然是被搶占前的數(shù)值1,執(zhí)行完②③的代碼,a等于9,這跟預(yù)期的17不符合。

對(duì)變量的非原子化訪問(wèn)
修改變量、設(shè)置結(jié)構(gòu)體、在16位的機(jī)器上寫(xiě)32位的變量,這些操作都是非原子的。也就是它們的操作過(guò)程都可能被打斷,如果被打斷的過(guò)程有其他任務(wù)來(lái)操作這些變量,就可能導(dǎo)致沖突。

函數(shù)重入
“可重入的函數(shù)"是指:多個(gè)任務(wù)同時(shí)調(diào)用它、任務(wù)和中斷同時(shí)調(diào)用它,函數(shù)的運(yùn)行也是安全的??芍厝氲暮瘮?shù)也被稱為"線程安全”(thread safe)。
每個(gè)任務(wù)都維持自己的棧、自己的CPU寄存器,如果一個(gè)函數(shù)只使用局部變量,那么它就是線程安全的。
函數(shù)中一旦使用了全局變量、靜態(tài)變量、其他外設(shè),它就不是"可重入的",如果改函數(shù)正在被調(diào)用,就必須阻止其他任務(wù)、中斷再次調(diào)用它。

上述問(wèn)題的解決方法是:任務(wù)A訪問(wèn)這些全局變量、函數(shù)代碼時(shí),獨(dú)占它,就是上個(gè)鎖。這些全局變量、函數(shù)代碼必須被獨(dú)占地使用,它們被稱為臨界資源。

互斥量也被稱為互斥鎖,使用過(guò)程如下:

  • 互斥量初始值為1
  • 任務(wù)A想訪問(wèn)臨界資源,先獲得并占有互斥量,然后開(kāi)始訪問(wèn)
  • 任務(wù)B也想訪問(wèn)臨界資源,也要先獲得互斥量:被別人占有了,于是阻塞
  • 任務(wù)A使用完畢,釋放互斥量;任務(wù)B被喚醒、得到并占有互斥量,然后開(kāi)始訪問(wèn)臨界資源
  • 任務(wù)B使用完畢,釋放互斥量

正常來(lái)說(shuō):在任務(wù)A占有互斥量的過(guò)程中,任務(wù)B、任務(wù)C等等,都無(wú)法釋放互斥量。

但是FreeRTOS未實(shí)現(xiàn)這點(diǎn):任務(wù)A占有互斥量的情況下,任務(wù)B也可釋放互斥量。

7.2 互斥量函數(shù)

7.2.1 創(chuàng)建

互斥量是一種特殊的二進(jìn)制信號(hào)量。

使用互斥量時(shí),先創(chuàng)建、然后去獲得、釋放它。使用句柄來(lái)表示一個(gè)互斥量。

創(chuàng)建互斥量的函數(shù)有2種:動(dòng)態(tài)分配內(nèi)存,靜態(tài)分配內(nèi)存,函數(shù)原型如下:

/* 創(chuàng)建一個(gè)互斥量,返回它的句柄。
 * 此函數(shù)內(nèi)部會(huì)分配互斥量結(jié)構(gòu)體 
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateMutex( void );

/* 創(chuàng)建一個(gè)互斥量,返回它的句柄。
 * 此函數(shù)無(wú)需動(dòng)態(tài)分配內(nèi)存,所以需要先有一個(gè)StaticSemaphore_t結(jié)構(gòu)體,并傳入它的指針
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer );

要想使用互斥量,需要在配置文件FreeRTOSConfig.h中定義:

#define configUSE_MUTEXES 1

7.2.2 其他函數(shù)

要注意的是,互斥量不能在ISR中使用。

各類(lèi)操作函數(shù),比如刪除、give/take,跟一般是信號(hào)量是一樣的。

/*
 * xSemaphore: 信號(hào)量句柄,你要?jiǎng)h除哪個(gè)信號(hào)量, 互斥量也是一種信號(hào)量
 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

/* 釋放 */
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

/* 釋放(ISR版本) */
BaseType_t xSemaphoreGiveFromISR(
                       SemaphoreHandle_t xSemaphore,
                       BaseType_t *pxHigherPriorityTaskWoken
                   );

/* 獲得 */
BaseType_t xSemaphoreTake(
                   SemaphoreHandle_t xSemaphore,
                   TickType_t xTicksToWait
               );
/* 獲得(ISR版本) */
xSemaphoreGiveFromISR(
                       SemaphoreHandle_t xSemaphore,
                       BaseType_t *pxHigherPriorityTaskWoken
                   );

7.3 示例15: 互斥量基本使用

本節(jié)代碼為: FreeRTOS_15_mutex 。

使用互斥量時(shí)有如下特點(diǎn):

  • 剛創(chuàng)建的互斥量可以被成功"take"
  • “take"互斥量成功的任務(wù),被稱為"holder”,只能由它"give"互斥量;別的任務(wù)"give"不成功
  • 在ISR中不能使用互斥量

本程序創(chuàng)建2個(gè)發(fā)送任務(wù):故意發(fā)送大量的字符??梢宰?個(gè)實(shí)驗(yàn):

  • 使用互斥量:可以看到任務(wù)1、任務(wù)2打印的字符串沒(méi)有混雜在一起
  • 不使用互斥量:任務(wù)1、任務(wù)2打印的字符串混雜在一起

main函數(shù)代碼如下:

/* 互斥量句柄 */
SemaphoreHandle_t xMutex;

int main( void )
{
	prvSetupHardware();
	
    /* 創(chuàng)建互斥量 */
    xMutex = xSemaphoreCreateMutex( );


	if( xMutex != NULL )
	{
		/* 創(chuàng)建2個(gè)任務(wù): 都是打印
		 * 優(yōu)先級(jí)相同
		 */
		xTaskCreate( vSenderTask, "Sender1", 1000, (void *)1, 1, NULL );
		xTaskCreate( vSenderTask, "Sender2", 1000, (void *)2, 1, NULL );

		/* 啟動(dòng)調(diào)度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無(wú)法創(chuàng)建互斥量 */
	}

	/* 如果程序運(yùn)行到了這里就表示出錯(cuò)了, 一般是內(nèi)存不足 */
	return 0;
}

發(fā)送任務(wù)的函數(shù)如下:

static void vSenderTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );	
	int cnt = 0;
	int task = (int)pvParameters;
	int i;
	char c;
	
	/* 無(wú)限循環(huán) */
	for( ;; )
	{	
		/* 獲得互斥量: 上鎖 */
		xSemaphoreTake(xMutex, portMAX_DELAY);
		
		printf("Task %d use UART count: %d, ", task, cnt++);
		c = (task == 1 ) ? 'a' : 'A';
		for (i = 0; i < 26; i++)
			printf("%c", c + i);
		printf("rn");
		
		/* 釋放互斥量: 開(kāi)鎖 */
		xSemaphoreGive(xMutex);
		
		vTaskDelay(xTicksToWait);
	}
}

可以做兩個(gè)實(shí)驗(yàn):vSenderTask函數(shù)的for循環(huán)中xSemaphoreTake和xSemaphoreGive這2句代碼保留、不保留

  • 保留:實(shí)驗(yàn)現(xiàn)象如下圖左邊,任務(wù)1、任務(wù)2的打印信息沒(méi)有混在一起
  • 不保留:實(shí)驗(yàn)現(xiàn)象如下圖右邊,打印信息混雜在一起

程序運(yùn)行結(jié)果如下圖所示:

在這里插入圖片描述

7.4 示例16: 誰(shuí)上鎖就由誰(shuí)解鎖?

互斥量、互斥鎖,本來(lái)的概念確實(shí)是:誰(shuí)上鎖就得由誰(shuí)解鎖。

但是FreeRTOS并沒(méi)有實(shí)現(xiàn)這點(diǎn),只是要求程序員按照這樣的慣例寫(xiě)代碼。

本節(jié)代碼為: FreeRTOS_16_mutex_who_give 。

main函數(shù)創(chuàng)建了2個(gè)任務(wù):

  • 任務(wù)1:高優(yōu)先級(jí),一開(kāi)始就獲得互斥鎖,永遠(yuǎn)不釋放。
  • 任務(wù)2:任務(wù)1阻塞時(shí)它開(kāi)始執(zhí)行,它先嘗試獲得互斥量,失敗的話就監(jiān)守自盜(釋放互斥量、開(kāi)鎖),然后再上鎖

代碼如下:

int main( void )
{
	prvSetupHardware();
	
    /* 創(chuàng)建互斥量 */
    xMutex = xSemaphoreCreateMutex( );

	if( xMutex != NULL )
	{
		/* 創(chuàng)建2個(gè)任務(wù): 一個(gè)上鎖, 另一個(gè)自己監(jiān)守自盜(開(kāi)別人的鎖自己用)
		 */
		xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL );
		xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL );

		/* 啟動(dòng)調(diào)度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無(wú)法創(chuàng)建互斥量 */
	}

	/* 如果程序運(yùn)行到了這里就表示出錯(cuò)了, 一般是內(nèi)存不足 */
	return 0;
}

兩個(gè)任務(wù)的代碼和執(zhí)行流程如下圖所示:

  • A:任務(wù)1的優(yōu)先級(jí)高,先運(yùn)行,立刻上鎖
  • B:任務(wù)1阻塞
  • C:任務(wù)2開(kāi)始執(zhí)行,嘗試獲得互斥量(上鎖),超時(shí)時(shí)間設(shè)為0。根據(jù)返回值打印出:上鎖失敗
  • D:任務(wù)2監(jiān)守自盜,開(kāi)鎖,成功!
  • E:任務(wù)2成功獲得互斥量
  • F:任務(wù)2阻塞

可見(jiàn),任務(wù)1上的鎖,被任務(wù)2解開(kāi)了。所以,F(xiàn)reeRTOS并沒(méi)有實(shí)現(xiàn)"誰(shuí)上鎖就得由誰(shuí)開(kāi)鎖"的功能。

在這里插入圖片描述

程序運(yùn)行結(jié)果如下圖所示:

在這里插入圖片描述

7.5 示例17: 優(yōu)先級(jí)反轉(zhuǎn)

假設(shè)任務(wù)A、B都想使用串口,A優(yōu)先級(jí)比較低:

  • 任務(wù)A獲得了串口的互斥量
  • 任務(wù)B也想使用串口,它將會(huì)阻塞、等待A釋放互斥量
  • 高優(yōu)先級(jí)的任務(wù),被低優(yōu)先級(jí)的任務(wù)延遲,這被稱為"優(yōu)先級(jí)反轉(zhuǎn)"(priority inversion)

如果涉及3個(gè)任務(wù),可以讓"優(yōu)先級(jí)反轉(zhuǎn)"的后果更加惡劣。

本節(jié)代碼為: FreeRTOS_17_mutex_inversion 。

互斥量可以通過(guò)"優(yōu)先級(jí)繼承",可以很大程度解決"優(yōu)先級(jí)反轉(zhuǎn)"的問(wèn)題,這也是FreeRTOS中互斥量和二級(jí)制信號(hào)量的差別。

本節(jié)程序使用二級(jí)制信號(hào)量來(lái)演示"優(yōu)先級(jí)反轉(zhuǎn)"的惡劣后果。

main函數(shù)創(chuàng)建了3個(gè)任務(wù):LPTask/MPTask/HPTask(低/中/高優(yōu)先級(jí)任務(wù)),代碼如下:

/* 互斥量/二進(jìn)制信號(hào)量句柄 */
SemaphoreHandle_t xLock;

int main( void )
{
	prvSetupHardware();
	
    /* 創(chuàng)建互斥量/二進(jìn)制信號(hào)量 */
    xLock = xSemaphoreCreateBinary( );


	if( xLock != NULL )
	{
		/* 創(chuàng)建3個(gè)任務(wù): LP,MP,HP(低/中/高優(yōu)先級(jí)任務(wù))
		 */
		xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );
		xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );
		xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );

		/* 啟動(dòng)調(diào)度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無(wú)法創(chuàng)建互斥量/二進(jìn)制信號(hào)量 */
	}

	/* 如果程序運(yùn)行到了這里就表示出錯(cuò)了, 一般是內(nèi)存不足 */
	return 0;
}

LPTask/MPTask/HPTask三個(gè)任務(wù)的代碼和運(yùn)行過(guò)程如下圖所示:

  • A:HPTask優(yōu)先級(jí)最高,它最先運(yùn)行。在這里故意打印,這樣才可以觀察到flagHPTaskRun的脈沖。
  • HP Delay:HPTask阻塞
  • B:MPTask開(kāi)始運(yùn)行。在這里故意打印,這樣才可以觀察到flagMPTaskRun的脈沖。
  • MP Delay:MPTask阻塞
  • C:LPTask開(kāi)始運(yùn)行,獲得二進(jìn)制信號(hào)量,然后故意打印很多字符
  • D:HP Delay時(shí)間到,HPTask恢復(fù)運(yùn)行,它無(wú)法獲得二進(jìn)制信號(hào)量,一直阻塞等待
  • E:MP Delay時(shí)間到,MPTask恢復(fù)運(yùn)行,它比LPTask優(yōu)先級(jí)高,一直運(yùn)行。導(dǎo)致LPTask無(wú)法運(yùn)行,自然無(wú)法釋放二進(jìn)制信號(hào)量,于是HPTask用于無(wú)法運(yùn)行。

總結(jié):

  • LPTask先持有二進(jìn)制信號(hào)量,
  • 但是MPTask搶占LPTask,是的LPTask一直無(wú)法運(yùn)行也就無(wú)法釋放信號(hào)量,
  • 導(dǎo)致HPTask任務(wù)無(wú)法運(yùn)行
  • 優(yōu)先級(jí)最高的HPTask竟然一直無(wú)法運(yùn)行!
在這里插入圖片描述

程序運(yùn)行的時(shí)序圖如下:

在這里插入圖片描述

7.6 示例18: 優(yōu)先級(jí)繼承

本節(jié)代碼為: FreeRTOS_18_mutex_inheritance 。

示例17的問(wèn)題在于,LPTask低優(yōu)先級(jí)任務(wù)獲得了鎖,但是它優(yōu)先級(jí)太低而無(wú)法運(yùn)行。

如果能提升LPTask任務(wù)的優(yōu)先級(jí),讓它能盡快運(yùn)行、釋放鎖,"優(yōu)先級(jí)反轉(zhuǎn)"的問(wèn)題不就解決了嗎?

把LPTask任務(wù)的優(yōu)先級(jí)提升到什么水平?

優(yōu)先級(jí)繼承:

  • 假設(shè)持有互斥鎖的是任務(wù)A,如果更高優(yōu)先級(jí)的任務(wù)B也嘗試獲得這個(gè)鎖
  • 任務(wù)B說(shuō):你既然持有寶劍,又不給我,那就繼承我的愿望吧
  • 于是任務(wù)A就繼承了任務(wù)B的優(yōu)先級(jí)
  • 這就叫:優(yōu)先級(jí)繼承
  • 等任務(wù)A釋放互斥鎖時(shí),它就恢復(fù)為原來(lái)的優(yōu)先級(jí)
  • 互斥鎖內(nèi)部就實(shí)現(xiàn)了優(yōu)先級(jí)的提升、恢復(fù)

本節(jié)源碼是在FreeRTOS_17_mutex_inversion 的代碼上做了一些簡(jiǎn)單修改:

int main( void )
{
	prvSetupHardware();
	
    /* 創(chuàng)建互斥量/二進(jìn)制信號(hào)量 */
    //xLock = xSemaphoreCreateBinary( );
	xLock = xSemaphoreCreateMutex( );

運(yùn)行時(shí)序圖如下圖所示:

  • A:HPTask執(zhí)行xSemaphoreTake(xLock, portMAX_DELAY);,它的優(yōu)先級(jí)被LPTask繼承
  • B:LPTask搶占MPTask,運(yùn)行
  • C:LPTask執(zhí)行xSemaphoreGive(xLock);,它的優(yōu)先級(jí)恢復(fù)為原來(lái)值
  • D:HPTask得到互斥鎖,開(kāi)始運(yùn)行
  • 互斥鎖的"優(yōu)先級(jí)繼承",可以減小"優(yōu)先級(jí)反轉(zhuǎn)"的影響
在這里插入圖片描述

7.7 遞歸鎖

7.7.1 死鎖的概念

日常生活的死鎖:我們只招有工作經(jīng)驗(yàn)的人!我沒(méi)有工作經(jīng)驗(yàn)怎么辦?那你就去找工作??!

假設(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都阻塞,再無(wú)法釋放它們持有的互斥量
  • 死鎖發(fā)生!

7.7.2 自我死鎖

假設(shè)這樣的場(chǎng)景:

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

7.7.3 函數(shù)

怎么解決這類(lèi)問(wèn)題?可以使用遞歸鎖(Recursive Mutexes),它的特性如下:

  • 任務(wù)A獲得遞歸鎖M后,它還可以多次去獲得這個(gè)鎖
  • "take"了N次,要"give"N次,這個(gè)鎖才會(huì)被釋放

遞歸鎖的函數(shù)根一般互斥量的函數(shù)名不一樣,參數(shù)類(lèi)型一樣,列表如下:

遞歸鎖 一般互斥量
創(chuàng)建 xSemaphoreCreateRecursiveMutex xSemaphoreCreateMutex
獲得 xSemaphoreTakeRecursive xSemaphoreTake
釋放 xSemaphoreGiveRecursive xSemaphoreGive

函數(shù)原型如下:

/* 創(chuàng)建一個(gè)遞歸鎖,返回它的句柄。
 * 此函數(shù)內(nèi)部會(huì)分配互斥量結(jié)構(gòu)體 
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );


/* 釋放 */
BaseType_t xSemaphoreGiveRecursive( SemaphoreHandle_t xSemaphore );

/* 獲得 */
BaseType_t xSemaphoreTakeRecursive(
                   SemaphoreHandle_t xSemaphore,
                   TickType_t xTicksToWait
               );

7.7.4 示例19: 遞歸鎖

本節(jié)代碼為: FreeRTOS_19_mutex_recursive

遞歸鎖實(shí)現(xiàn)了:誰(shuí)上鎖就由誰(shuí)解鎖。

本程序從FreeRTOS_16_mutex_who_give修改得來(lái),它的main函數(shù)里創(chuàng)建了2個(gè)任務(wù)

  • 任務(wù)1:高優(yōu)先級(jí),一開(kāi)始就獲得遞歸鎖,然后故意等待很長(zhǎng)時(shí)間,讓任務(wù)2運(yùn)行
  • 任務(wù)2:低優(yōu)先級(jí),看看能否操作別人持有的鎖

main函數(shù)代碼如下:

/* 遞歸鎖句柄 */
SemaphoreHandle_t xMutex;

int main( void )
{
	prvSetupHardware();
	
    /* 創(chuàng)建遞歸鎖 */
    xMutex = xSemaphoreCreateRecursiveMutex( );

	if( xMutex != NULL )
	{
		/* 創(chuàng)建2個(gè)任務(wù): 一個(gè)上鎖, 另一個(gè)自己監(jiān)守自盜(看看能否開(kāi)別人的鎖自己用)
		 */
		xTaskCreate( vTakeTask, "Task1", 1000, NULL, 2, NULL );
		xTaskCreate( vGiveAndTakeTask, "Task2", 1000, NULL, 1, NULL );

		/* 啟動(dòng)調(diào)度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無(wú)法創(chuàng)建遞歸鎖 */
	}

	/* 如果程序運(yùn)行到了這里就表示出錯(cuò)了, 一般是內(nèi)存不足 */
	return 0;
}

兩個(gè)任務(wù)經(jīng)過(guò)精細(xì)設(shè)計(jì),代碼和運(yùn)行流程如下圖所示:

A:任務(wù)1優(yōu)先級(jí)最高,先運(yùn)行,獲得遞歸鎖

B:任務(wù)1阻塞,讓任務(wù)2得以運(yùn)行

C:任務(wù)2運(yùn)行,看看能否獲得別人持有的遞歸鎖:不能

D:任務(wù)2故意執(zhí)行"give"操作,看看能否釋放別人持有的遞歸鎖:不能

E:任務(wù)2等待遞歸鎖

F:任務(wù)1阻塞時(shí)間到后繼續(xù)運(yùn)行,使用循環(huán)多次獲得、釋放遞歸鎖

遞歸鎖在代碼上實(shí)現(xiàn)了:誰(shuí)持有遞歸鎖,必須由誰(shuí)釋放。

在這里插入圖片描述

程序運(yùn)行結(jié)果如下圖所示:

在這里插入圖片描述

7.8 常見(jiàn)問(wèn)題

使用互斥量的兩個(gè)任務(wù)是相同優(yōu)先級(jí)時(shí)的注意事項(xiàng)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5152

    文章

    19675

    瀏覽量

    317606
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11511

    瀏覽量

    213824
  • RTOS
    +關(guān)注

    關(guān)注

    24

    文章

    851

    瀏覽量

    121177
  • FreeRTOS
    +關(guān)注

    關(guān)注

    12

    文章

    493

    瀏覽量

    64358
  • 韋東山
    +關(guān)注

    關(guān)注

    14

    文章

    6

    瀏覽量

    13616
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    東山freeRTOS系列程之同步互斥與通信(4)

    文章目錄 系列教程總目錄 概述 4.1 同步與互斥的概念 4.2 同步與互斥并不簡(jiǎn)單 4.3 各類(lèi)方法的對(duì)比 ? 需要獲取更好閱讀體驗(yàn)的同學(xué),請(qǐng)?jiān)L問(wèn)我專(zhuān)門(mén)設(shè)立的站點(diǎn)查看,地址:http
    的頭像 發(fā)表于 12-13 14:31 ?4778次閱讀
    <b class='flag-5'>韋</b><b class='flag-5'>東山</b><b class='flag-5'>freeRTOS</b><b class='flag-5'>系列</b>教<b class='flag-5'>程之</b>同步<b class='flag-5'>互斥</b>與通信(4)

    東山freeRTOS系列程之信號(hào)(6)

    文章目錄 系列教程總目錄 概述 6.1 信號(hào)的特性 6.1.1 信號(hào)的常規(guī)操作 6.1.2 信號(hào)跟隊(duì)列的對(duì)比 6.1.3 兩種信號(hào)
    的頭像 發(fā)表于 12-13 14:35 ?5626次閱讀
    <b class='flag-5'>韋</b><b class='flag-5'>東山</b><b class='flag-5'>freeRTOS</b><b class='flag-5'>系列</b>教<b class='flag-5'>程之</b>信號(hào)<b class='flag-5'>量</b>(6)

    RT-thread內(nèi)核之互斥

    、互斥相關(guān)接口:在src/ipc.c中創(chuàng)建互斥:rt_mutex_t rt_mutex_cr
    發(fā)表于 03-06 17:23

    轉(zhuǎn):第23章 FreeRTOS互斥信號(hào)

    本章節(jié)講解FreeRTOS重要的資源共享機(jī)制---互斥信號(hào)Mutex,即MutualExclusion的縮寫(xiě))。注意,建議初學(xué)者學(xué)習(xí)完前兩個(gè)章節(jié)的信號(hào)
    發(fā)表于 09-06 14:58

    例程使用互斥信號(hào)初始化如何設(shè)置?

    OS_MUTEXTEST_MUTEX; //定義一個(gè)互斥信號(hào)//創(chuàng)建一個(gè)互斥信號(hào)OSMutexCreate((OS_
    發(fā)表于 06-02 16:22

    互斥源碼分析測(cè)試

    文章目錄互斥源碼分析測(cè)試參考資料:RTT官網(wǎng)文檔關(guān)鍵字:分析RT-Thread源碼、stm32、RTOS、互斥。互斥
    發(fā)表于 08-24 06:01

    互斥Mutex相關(guān)資料推薦

    這里寫(xiě)目錄標(biāo)題概述API二級(jí)目錄三級(jí)目錄概述APItx_mutex_createtx_mutex_deletetx_mutex_gettx_mutex_put二級(jí)目錄三級(jí)目錄
    發(fā)表于 02-22 07:40

    互斥的地址怎么突變了

    互斥:error_code = rt_mutex_take(&(mcm->mcm_mutex), RT_WAITING_FOREVER);收到回復(fù)時(shí),再釋放
    發(fā)表于 11-23 10:37

    Linux多線程同步互斥Mutex詳解

    嵌入式linux中文站向各位愛(ài)好者介紹linux常見(jiàn)同步方式互斥Mutex的使用方法1. 初始化:在Linux下, 線程的互斥
    發(fā)表于 04-02 14:45 ?384次閱讀

    Linux 多線程互斥互斥

    情況是指可以允許多個(gè)訪問(wèn)者同時(shí)訪問(wèn)資源互斥Mutex:本質(zhì)上說(shuō)就是一把鎖,提供對(duì)資源的獨(dú)占訪問(wèn),所以Mutex主要的作用是用于互斥。
    發(fā)表于 04-02 14:47 ?349次閱讀

    詳談Linux操作系統(tǒng)編程的互斥mutex

    前文提到,系統(tǒng)中如果存在資源共享,線程間存在競(jìng)爭(zhēng),并且沒(méi)有合理的同步機(jī)制的話,會(huì)出現(xiàn)數(shù)據(jù)混亂的現(xiàn)象。為了實(shí)現(xiàn)同步機(jī)制,Linux中提供了多種方式,其中一種方式為互斥mutex(也稱之為互斥
    的頭像 發(fā)表于 09-28 15:09 ?2725次閱讀
    詳談Linux操作系統(tǒng)編程的<b class='flag-5'>互斥</b><b class='flag-5'>量</b><b class='flag-5'>mutex</b>

    東山freeRTOS程之FreeRTOS概述與體驗(yàn)(1)

    文章目錄 教程目錄 1.1 FreeRTOS目錄結(jié)構(gòu) 1.1 FreeRTOS目錄結(jié)構(gòu) 1.2 核心文件 1.3 移植時(shí)涉及的文件 1.4 頭文件相關(guān) 1.4.1 頭文件目錄 1.4.2 頭文件
    發(fā)表于 11-29 16:56 ?2452次閱讀
    <b class='flag-5'>韋</b><b class='flag-5'>東山</b><b class='flag-5'>freeRTOS</b>教<b class='flag-5'>程之</b><b class='flag-5'>FreeRTOS</b>概述與體驗(yàn)(1)

    FreeRTOS 隊(duì)列 信號(hào) 互斥

    文章目錄前言Queue 隊(duì)列semaphore 信號(hào)Mutex 互斥微信公眾號(hào)前言FreeRTOS STM32CubeMX配置 內(nèi)存管理
    發(fā)表于 12-09 09:51 ?0次下載
    <b class='flag-5'>FreeRTOS</b> 隊(duì)列 信號(hào)<b class='flag-5'>量</b> <b class='flag-5'>互斥</b><b class='flag-5'>量</b>

    ThreadX(七)------互斥Mutex

    這里寫(xiě)目錄標(biāo)題概述API二級(jí)目錄三級(jí)目錄概述APItx_mutex_createtx_mutex_deletetx_mutex_gettx_mutex_put二級(jí)目錄三級(jí)目錄
    發(fā)表于 12-28 19:29 ?8次下載
    ThreadX(七)------<b class='flag-5'>互斥</b><b class='flag-5'>量</b><b class='flag-5'>Mutex</b>

    FreeRTOS系列第20篇---FreeRTOS信號(hào)API函數(shù)

    FreeRTOS的信號(hào)包括二進(jìn)制信號(hào)、計(jì)數(shù)信號(hào)、互斥信號(hào)(以后簡(jiǎn)稱
    發(fā)表于 01-26 17:44 ?4次下載
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>系列</b>第20篇---<b class='flag-5'>FreeRTOS</b>信號(hào)<b class='flag-5'>量</b>API函數(shù)