freeRtos互斥量的使用

2023-12-15 14:33:22

所以二进制并不能保证是谁上锁谁解锁,引入互斥量本质并没有解决这个问题,还是要程序员去解决。引入互斥量可以去解决优先级翻转的问题。

一.优先级反转和优先级继承

二. 递归上锁

获得了锁之后,再次执行任务获得锁。

三.创建互斥量?

与前面的信号量差不多,只不过前面创建信号量之前需要give一下,这里创建互斥量不需要give

void TaskGenericFunction(void * param)
{
	while (1)
	{
		xSemaphoreTake(xSemUART,portMAX_DELAY);//获得信号量
		printf("%s\r\n", (char *)param);
		xSemaphoreGive(xSemUART);//释放信号量
		vTaskDelay(1);
	}
}


/*-----------------------------------------------------------*/

int main( void )
{
	TaskHandle_t xHandleTask1;
		
#ifdef DEBUG
  debug();
#endif

	prvSetupHardware();

	printf("Hello, world!\r\n");

	xSemCalc=xSemaphoreCreateCounting(10,0);
	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);

	xSemUART=xSemaphoreCreateMutex();
	xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);
	xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	return 0;
}

四.优先级反转和解决优先级反转 (优先级继承)

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");
	
	/* 让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);
	}
}

?高优先级先执行执行Delay(10ms),接着中等优先级执行Delay(30ms),低优先级执行运行获得了LOCK,打印500个字符,高优先级任务想获得锁,没有成功进入阻塞状态,低优先级任务执行30ms到了,中优先级任务就一直执行,没有放弃执行。

修改原来的代码1为下面的代码2

    /* 创建互斥量/二进制信号量 */    
    xLock = xSemaphoreCreateBinary( );
	xSemaphoreGive(xLock);//给一个初值
    /* 创建互斥量/二进制信号量 */
    xLock = xSemaphoreCreateMutex();
int main( void )
{
	prvSetupHardware();
	
    /* 创建互斥量/二进制信号量 */
    xLock = xSemaphoreCreateMutex();


	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;
}

前面一部分跟上面是一样的高优先级先执行,中接着执行,低优先任务最后执行,低优先级任务里面获得了LOCK,10ms执行时间到了高优先级任务想要LOCK,进入阻塞状态同时会优先级继承,最低优先级继承最高优先级,即使到了中优先级该执行的时间了,但是还是低优先级执行,最后UNLOCK,轮到最高优先级执行。

五.互斥量的缺陷和递归锁

递归锁可以实现由谁持有就由谁释放。

void TaskGenericFunction(void * param)
{
	while (1)
	{
		xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);
		printf("%s\r\n", (char *)param);
		xSemaphoreGiveRecursive(xSemUART);
		vTaskDelay(1);
	}
}

void Task5Function(void * param)
{
	vTaskDelay(10);
	while (1)
	{
		while(1)
		{	
			if(xSemaphoreTakeRecursive(xSemUART, 0)!=pdTRUE)
			{
				xSemaphoreGiveRecursive(xSemUART);
			}
			else
			{
				break;
			}
		}
		printf("%s\r\n", (char *)param);		
		vTaskDelay(1);
	}
}

/*-----------------------------------------------------------*/

int main( void )
{
	TaskHandle_t xHandleTask1;
		
#ifdef DEBUG
  debug();
#endif

	prvSetupHardware();

	printf("Hello, world!\r\n");
	xSemCalc = xSemaphoreCreateCounting(10, 0);
	//xSemUART = xSemaphoreCreateBinary();
	//xSemaphoreGive(xSemUART);
	
	xSemUART = xSemaphoreCreateRecursiveMutex();

	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);

	xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);
	xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);
	xTaskCreate(Task5Function, "Task5", 100, "Task 5 is running", 1, NULL);

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	return 0;
}

递归上锁解锁?

void TaskGenericFunction(void * param)
{
	int i;
	while (1)
	{
		xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);
		printf("%s\r\n", (char *)param);
		for(i=0;i<10;i++)
		{
			xSemaphoreTakeRecursive(xSemUART, portMAX_DELAY);
			printf("%s in loop %d\r\n",(char*)param,i);
			xSemaphoreGiveRecursive(xSemUART);
		}
		xSemaphoreGiveRecursive(xSemUART);
		vTaskDelay(1);
	}
}

void Task5Function(void * param)
{
	vTaskDelay(10);
	while (1)
	{
		while(1)
		{	
			if(xSemaphoreTakeRecursive(xSemUART, 0)!=pdTRUE)
			{
				xSemaphoreGiveRecursive(xSemUART);
			}
			else
			{
				break;
			}
		}
		printf("%s\r\n", (char *)param);		
		vTaskDelay(1);
	}
}

/*-----------------------------------------------------------*/

int main( void )
{
	TaskHandle_t xHandleTask1;
		
#ifdef DEBUG
  debug();
#endif

	prvSetupHardware();

	printf("Hello, world!\r\n");
	xSemCalc = xSemaphoreCreateCounting(10, 0);
	//xSemUART = xSemaphoreCreateBinary();
	//xSemaphoreGive(xSemUART);
	
	xSemUART = xSemaphoreCreateRecursiveMutex();

	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);

	xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);
	xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 4 is running", 1, NULL);
	xTaskCreate(Task5Function, "Task5", 100, "Task 5 is running", 1, NULL);

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	return 0;
}

文章来源:https://blog.csdn.net/lovesjj_1011/article/details/134994325
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。