【FreeRTOS学习 - 互斥量学习 (盗锁)】

跟着韦东山老师FreeRTOS教学资料的学习记录

FreeRTOS全部项目代码链接(更新中)

https://gitee.com/chenshao777/free-rtos_-study


了解互斥量的使用场景

例如多个任务对同一个数组或者变量进行操作时,往往会发生冲突,可能任务A访问arr数组的过程中被任务B打断,任务B恰好也对arr数组进行了操作,当任务A继续执行时,此时的arr数组已经不是当时的arr数组了,这就造成了访问冲突。

即非原子化访问,也就是操作的过程可能被打断

为了避免此问题,可以在访问变量前,上锁,访问之后,开锁

  • 即A使用变量前上个锁
  • A使用完再开锁
  • 再此期间B必须等A开锁后才能使用该变量,这样就不会产生访问冲突了
  • 但实际上FreeRTOS的代码并没有实现谁上的锁只能由谁来开
  • 所以A上锁后,B实际上也是可以自己开锁的
  • 所以谁上锁,谁才能开锁需要由程序员自己约定了
  • 这个锁就是我们说的互斥量,互斥量是一种特殊的二进制信号量。

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

#define   configUSE_MUTEXES   1

一、创建互斥量

二、互斥量的操作函数(获取、释放、删除)

三、互斥量使用实例

四、盗锁


一、创建互斥量

QueueHandle_t xSemaphoreMutex;  //互斥量句柄

/* 创建互斥量,返回它的句柄 */
xSemaphoreMutex = xSemaphoreCreateMutex();

二、互斥量的操作函数(获取、释放、删除)

/*
 * xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量
 */
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
                   );


三、互斥量使用实例

创建两个任务

  • 任务1一直发送0~99数字
  • 任务2一直发送100~199数字

1. 不使用互斥量的情况(USE_Mutex_Flag 置0)

实验结果,发送数据混乱在一起:

在这里插入图片描述
2. 使用互斥量的情况(USE_Mutex_Flag 置1)

实验结果,发送数据不产生错乱了:

在这里插入图片描述
代码如下:

void systemInit(void);   //各模块初始化

QueueHandle_t xSemaphoreMutex;  //互斥量句柄

void systemInit(void);   //各模块初始化

QueueHandle_t xSemaphoreMutex;  //互斥量句柄

/* 使用互斥量标志 */
#define     USE_Mutex_Flag 	   0   

/*
 * 任务1一直发送0~99数字
*/
void vSemphrMutex_Task1(void *pvParameters)
{
	const TickType_t xDelay = 50 / portTICK_PERIOD_MS;
	
	BaseType_t result;
	
	for(;;)
	{
		#if (USE_Mutex_Flag == 1)
			/* 上锁 */
			xSemaphoreTake(xSemaphoreMutex, portMAX_DELAY);
		#endif
		
		/* 打印 0 ~ 99 */
		for(int i=0; i < 100 ; i++){
			printf("%d ", i);
		}
		printf("\r\n");
		
		#if (USE_Mutex_Flag == 1)
			/* 开锁 */
			xSemaphoreGive(xSemaphoreMutex);
		#endif
		
		vTaskDelay(xDelay);
	}
}

/*
 * 任务2一直发送100~199数字
*/
void vSemphrMutex_Task2(void *pvParameters)
{
	const TickType_t xDelay = 50 / portTICK_PERIOD_MS;
	
	BaseType_t result;  //获取信号量结果变量
	
	for(;;)
	{
		#if (USE_Mutex_Flag == 1)
			/* 上锁 */
			xSemaphoreTake(xSemaphoreMutex, portMAX_DELAY);
		#endif
		
		/* 打印 100 ~ 199 */
		for(int i=100; i < 200 ; i++){
			printf("%d ", i);
		}
		printf("\r\n");
		
		#if (USE_Mutex_Flag == 1)
			/* 开锁 */
			xSemaphoreGive(xSemaphoreMutex);
		#endif
		
		vTaskDelay(xDelay);
	}
}

int main()
{
	systemInit();   //初始化各个模块

	// 互斥量任务一
	xTaskCreate(vSemphrMutex_Task1, "vSemphrMutex_Task1", 200, NULL, 2, NULL);
	
	// 互斥量任务二
	xTaskCreate(vSemphrMutex_Task2, "vSemphrMutex_Task2", 200, NULL, 2, NULL);
	
	vTaskStartScheduler();          //开启任务调度
}

/*
 * 初始化各个模块
*/
void systemInit(void)
{
	SysTick_Init(72);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	USART1_Init(115200);
	printf("串口初始化成功!\r\n");

	/* 创建互斥量 */
	xSemaphoreMutex = xSemaphoreCreateMutex();
}

四、盗锁

  • 任务2上锁后,开始打印

  • 任务1来上锁(Take),发现失败,不等待

  • 任务1直接开锁(Give),简称盗锁(因为本来约定谁上的锁只能由谁开)

  • 任务1开锁(Give)成功,开始打印

  • 由于优先级相同,任务1和2交替打印

  1. 任务1盗锁代码如下:

在这里插入图片描述

  1. 盗锁结果:

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值