利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(3.0) —— 同步与互斥的缺陷

前言

(1)FreeRTOS是我一天过完的,由此回忆并且记录一下。个人认为,如果只是入门,利用STM32CubeMX是一个非常好的选择。学习完本系列课程之后,再去学习网上的一些其他课程也许会简单很多。
(2)本系列课程是使用的keil软件仿真平台,所以对于没有开发板的同学也可也进行学习。
(3)叠甲,再次强调,本系列课程仅仅用于入门。学习完之后建议还要再去寻找其他课程加深理解。
(4)本系列博客对应代码仓库:gitee仓库

具体问题

(1)在RTOS开发过程中,因为实时操作系统是通过时间片轮转的方式切换任务的,那么就容易出现一些问题需要考虑。接下来我将会直接上实例代码进行讲解。
(2)这里我们先复制1.1章节的代码进行测试

利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(3.0) —— 同步与互斥的缺陷_第1张图片

同步

理论

(1)在进行多任务执行的时候,可能会存在一个任务依赖于另外一个任务的执行。因为FreeRTOS是不知道这些任务之间的依赖关系的,当出现了StartCubemxTask()没执行完,StartKeilTask()将会一直卡死在while(g_flag != 1);,这样任务执行效率会变低。
(2)以下图为例,因为Task2是依赖与TASK1的,当TASK1没有执行完成,TASK2依旧会占用CPU资源,进行死等。毫无疑问,这是非常低效的。

利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(3.0) —— 同步与互斥的缺陷_第2张图片

代码

(1)接下来我将以代码的形式展现这个实例,例如下面,StartCubemxTask()负责计算数值,StartKeilTask()负责打印数据。当StartCubemxTask()没有计算完成的时候,StartKeilTask()将只能死等。我们使用xTaskGetTickCount()函数计算进行一次计算要花费的时间。(按Ctrl+F搜索StartCubemxTask即可找到任务函数)

/* USER CODE END Header_StartCubemxTask */
static uint32_t g_num = 0;
static volatile uint8_t g_flag = 0;
static TickType_t g_preTime;
void StartCubemxTask(void *argument)
{
  /* USER CODE BEGIN StartCubemxTask */
	char *CubemxTaskPrintf = (char *)argument;
  /* Infinite loop */
  for(;;)
  {
		//同步
		g_preTime = xTaskGetTickCount();
		uint32_t i;
		for(i = 0 ; i < 0xffffff ;i++)
		{
			g_num +=i;
		}
		g_preTime = xTaskGetTickCount() - g_preTime;
		g_flag = 1;
		vTaskDelete(NULL);
  }
  /* USER CODE END StartCubemxTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
int fputc(int ch, FILE *f)
{
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return ch;
}
void StartKeilTask(void *argument)
{
	while(1)
	{
		//同步
		while(g_flag != 1);
		printf("g_num = %u \r\n",g_num);
		printf("preTime = %u ms\r\n",g_preTime/portTICK_PERIOD_MS);
		vTaskDelete(NULL);
	}
}
/* USER CODE END Application */

实操

(1)使用keil的调试功能,我们能够看到这次计算花费了2836ms。

利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(3.0) —— 同步与互斥的缺陷_第3张图片

代码(增加延时函数)

(1)既然我们知道了,StartKeilTask()StartCubemxTask()没有执行完成的时候,是进行无效的死循环。那么我们是否可以将StartKeilTask()先使用延时函数,让他进入阻塞态,等StartCubemxTask()执行完成之后再让StartKeilTask()恢复呢?
(2)既然有了这个想法,于是我们可以先在StartKeilTask()中加入一个3000ms的延时试试。(按Ctrl+F搜索StartKeilTask即可找到任务函数)
(3)其实从上面的讲解来看,我们很明显可以发现增加延时不是一种合适的处理办法。但是因为将会涉及到后面的内容,因此现在只能用增加延时函数做暂时的处理。
(4)不理解为什么需要增加延时函数的同学,需要重新补充延时函数部分的相关知识。

void StartKeilTask(void *argument)
{
	while(1)
	{
		//同步
		vTaskDelay(3000);
		while(g_flag != 1);
		printf("g_num = %u \r\n",g_num);
		printf("preTime = %u ms\r\n",g_preTime/portTICK_PERIOD_MS);
		vTaskDelete(NULL);
	}
}

实操

(1)打开仿真调试,我们能够发现,计算时间明显缩短了。从2836ms变成了1418ms,刚好缩短一半的时间。

利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(3.0) —— 同步与互斥的缺陷_第4张图片

互斥

理论

(1)如上例子中,任务2和任务1对同一个资源进行争抢的时候,任务2会很自觉的谦让,但又会占着CPU不做事。
(2)那么假设,任务2硬气了,不管任务1是否在使用这个资源,我都要和你抢。那样就会出现无法预料的问题,我们将这种对相同资源的争抢称之为互斥。

代码

(1)这里我们需要补充一个知识点,printf函数在使用的时候使用输出缓冲区来提高性能。在多线程环境中,不同线程的 printf 可能会共享同一个输出缓冲区,从而导致输出的不一致性。一个线程可能正在写入缓冲区,而另一个线程同时尝试写入,导致混淆。
(2)那么下面我将展示一个printf打印混淆的例子。

/* USER CODE END Header_StartCubemxTask */
static uint32_t g_num = 0;
static volatile uint8_t g_flag = 0;
static TickType_t g_preTime;
void StartCubemxTask(void *argument)
{
  /* USER CODE BEGIN StartCubemxTask */
	char *CubemxTaskPrintf = (char *)argument;
  /* Infinite loop */
  for(;;)
  {
		//互斥
		printf("StartCubemxTask\r\n");		
  }
  /* USER CODE END StartCubemxTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
int fputc(int ch, FILE *f)
{
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return ch;
}
void StartKeilTask(void *argument)
{
	while(1)
	{
		//互斥
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
		printf("StartKeilTask\r\n");
		HAL_Delay(100);
	}
}
/* USER CODE END Application */

实操

(1)通过上面的代码,我们知道,PC13引脚变化的几次,那么就应该打印几次StartKeilTask的字符串。但是,从仿真结果上来看,我们很明显发现,一直打印的是StartCubemxTask
(2)这个就很好的说明了printf函数存在线程之间的互斥问题。因此,当我们使用多线程任务调度的时候,一定要切记printf的保护。

利用STM32CubeMX和keil模拟器,3天入门FreeRTOS(3.0) —— 同步与互斥的缺陷_第5张图片

参考

(1)B站韦东山:FreeRTOS入门与工程实践

你可能感兴趣的:(FreeRTOS,stm32,嵌入式硬件,单片机)