FreeRTOS ~(七)互斥量 ~ (2/3)互斥量解决优先级反转问题

前情提要
FreeRTOS ~(四)同步互斥与通信 ~ (2/3)互斥的缺陷
FreeRTOS ~(五)队列的常规使用 ~ (2/5)队列解决互斥缺陷
FreeRTOS ~(六)信号量 ~ (2/3)信号量解决互斥缺陷
FreeRTOS ~(七)互斥量 ~ (1/3)互斥量解决互斥缺陷
互斥量解决优先级反转问题

上述的几篇文章说明了互斥的缺陷及一些解决方法,但是却没有解决一个问题:
互斥的两个任务的优先级反转问题.
为了说明说明是优先级反转,这里设置一个例子来实际操作一下;
举例说明:
创建三个任务,优先级不同,
如:
高优先级的优先级是3;
中优先级的优先级是2;
低优先级的优先级是1;
高优先级与低优先级都要使用到信号量,而中优先级不使用信号量,这里使用二值信号量来解决互斥问题;
高优先级执行后主动让自己Dealy 10ms,然后去获取信号量(take)
中优先级执行后主动让自己Delay 30ms,
低优先级任务则先获取信号量(take),然后执行一段较为耗时的打印工作,执行完成后,释放信号量(give)
通过设置相应的标志位(Flag),利用逻辑分析仪来观察Task执行情况.
代码如下:
static volatile uint8_t flagLPTaskRun = 0;	/* 低优先级任务执行标志位 */
static volatile uint8_t flagMPTaskRun = 0;	/* 中优先级任务执行标志位 */
static volatile uint8_t flagHPTaskRun = 0;	/* 高优先级任务执行标志位 */
static void vLPTask( void *pvParameters );	/* 低优先级任务声明 */
static void vMPTask( void *pvParameters );	/* 中优先级任务声明 */
static void vHPTask( void *pvParameters );	/* 高优先级任务声明 */
/*-----------------------------------------------------------*/
/* 互斥量/二进制信号量句柄 */
SemaphoreHandle_t  xLock;
/*-----------------------------------------------------------*/
int main( void )
{
	prvSetupHardware();
    /* 创建互斥量/二进制信号量 */
    xLock = xSemaphoreCreateBinary();
	xSemaphoreGive(xLock);
	
	if( xLock != NULL )
	{
		/* 创建3个任务: LP,MP,HP(低/中/高优先级任务) */
		xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );
		xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );
		xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );
		/* 启动调度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 无法创建互斥量/二进制信号量 */
	}
	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}
/*-----------------------------------------------------------*/
static void vLPTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );	
	uint32_t i;
	char c = 'A';
	printf("LPTask start\r\n");
	/* 无限循环 */
	for( ;; )
	{	
		/* 标志位表明正在执行的任务是低优先级任务 */
		flagLPTaskRun = 1;
		flagMPTaskRun = 0;
		flagHPTaskRun = 0;
		/* 获得互斥量/二进制信号量 */
		xSemaphoreTake(xLock, portMAX_DELAY);
		/* 耗时很久 */
		printf("LPTask take the Lock for long time");
		for (i = 0; i < 500; i++) 
		{
			flagLPTaskRun = 1;
			flagMPTaskRun = 0;
			flagHPTaskRun = 0;
			printf("%c", c + i);
		}
		printf("\r\n");
		/* 释放互斥量/二进制信号量 */
		xSemaphoreGive(xLock);
		vTaskDelay(xTicksToWait);
	}
}
/*-----------------------------------------------------------*/
static void vMPTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 30UL );	

	flagLPTaskRun = 0;
	flagMPTaskRun = 1;
	flagHPTaskRun = 0;
	printf("MPTask start\r\n");
	/* 让LPTask、HPTask先运行 */	
	vTaskDelay(xTicksToWait);
	/* 无限循环 */
	for( ;; )
	{	
		/* 标志位表明正在执行的任务是中优先级任务 */
		flagLPTaskRun = 0;
		flagMPTaskRun = 1;
		flagHPTaskRun = 0;
	}
}
/*-----------------------------------------------------------*/
static void vHPTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 10UL );	
	/* 标志位表明正在执行的任务是高优先级任务 */
	flagLPTaskRun = 0;
	flagMPTaskRun = 0;
	flagHPTaskRun = 1;
	printf("HPTask start\r\n");
	/* 主动进入阻塞态,10ms,让LPTask先运行 */	
	vTaskDelay(xTicksToWait);
	/* 无限循环 */
	for( ;; )
	{	
		flagLPTaskRun = 0;
		flagMPTaskRun = 0;
		flagHPTaskRun = 1;
		printf("HPTask wait for Lock\r\n");
		/* 获得互斥量/二进制信号量 */
		xSemaphoreTake(xLock, portMAX_DELAY);
		flagLPTaskRun = 0;
		flagMPTaskRun = 0;
		flagHPTaskRun = 1;
		/* 释放互斥量/二进制信号量 */
		xSemaphoreGive(xLock);
	}
}
/*-----------------------------------------------------------*/

优先级反转说明

如何解决优先级反转这个问题呢?
抛弃二值信号量,使用互斥量,下面简单修改一下代码即可,因为互斥量也是特殊的信号量,使用的一些API函数是一致的,
这里只需要将信号量的创建由二进制信号量,更换为互斥量即可.
int main( void )
{
	prvSetupHardware();
    /* 创建互斥量/二进制信号量 */
    #if  0
	    xLock = xSemaphoreCreateBinary();
		xSemaphoreGive(xLock);
	#else
		xLock = xSemaphoreCreateMutex();
	#endif
	
	if( xLock != NULL )
	{
		/* 创建3个任务: LP,MP,HP(低/中/高优先级任务) */
		xTaskCreate( vLPTask, "LPTask", 1000, NULL, 1, NULL );
		xTaskCreate( vMPTask, "MPTask", 1000, NULL, 2, NULL );
		xTaskCreate( vHPTask, "HPTask", 1000, NULL, 3, NULL );
		/* 启动调度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 无法创建互斥量/二进制信号量 */
	}
	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

优先级继承

解决优先级反转的问题,互斥量使用的方法使优先级继承.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值