资讯专栏INFORMATION COLUMN

七,FreeRTOS之——队列同步与互斥

Yu_Huang / 3301人阅读

摘要:声明本专栏参考韦东山,野火,正点原子以及其他博主的教程,如若侵权请告知,马上删帖致歉,个人总结,如有不对,欢迎指正。

声明:本专栏参考韦东山,野火,正点原子以及其他博主的FreeRTOS教程,如若侵权请告知,马上删帖致歉,个人总结,如有不对,欢迎指正。

转:同步与互斥概念理解link






实验一:同步

还是来看看同步实验怎么做吧

实验代码

/**   FreeRTOS v9.0.0 + STM32 动态创建任务   实验平台:韦东山 STM32F103ZE开发板 **/  #include "FreeRTOS.h"#include "task.h"#include "queue.h"/* 开发板硬件bsp头文件 */#include "bsp_led.h"#include "bsp_usart.h"/* 任务句柄 */static TaskHandle_t AppTaskCreate_Handle = NULL;static TaskHandle_t Task1_Handle = NULL;static TaskHandle_t Task2_Handle = NULL;static TaskHandle_t Task3_Handle = NULL;static xQueueHandle MsgQueue;  /*队列句柄*//* 函数声明 */static void AppTaskCreate(void);/* 用于创建任务 */static void Flag1_Task(void* pvParameters);/* LED1_Task任务实现 */static void Flag2_Task(void* pvParameters);/* LED2_Task任务实现 */static void Flag3_Task(void* pvParameters);/* LED3_Task任务实现 */static void BSP_Init(void);/* 用于初始化板载相关资源 *//*****************************************************************  * @brief  主函数  * @param  无  * @retval 无  * @note   第一步:开发板硬件初始化             第二步:创建APP应用任务            第三步:启动FreeRTOS,开始多任务调度  ****************************************************************/int main(void){	  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */  /* 开发板硬件初始化 */  BSP_Init();  printf("这是一个STM32F103ZE开发板-FreeRTOS-动态创建任务!/r/n");		MsgQueue=xQueueCreate(1,sizeof(int));/*创建队列:参数,队列长度,每个长度大小(字节)*/				   /* 创建AppTaskCreate任务 */  xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */                        (const char*    )"AppTaskCreate",/* 任务名字 */                        (uint16_t       )512,  /* 任务栈大小 */                        (void*          )NULL,/* 任务入口函数参数 */                        (UBaseType_t    )1, /* 任务的优先级 */                        (TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针 */   /* 启动任务调度 */             if(pdPASS == xReturn)    vTaskStartScheduler();   /* 启动任务,开启调度 */  else    return -1;      while(1);   /* 正常不会执行到这里 */    }/***********************************************************************  * @ 函数名  : AppTaskCreate  * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面  * @ 参数    : 无    * @ 返回值  : 无  **********************************************************************/static void AppTaskCreate(void){  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */    taskENTER_CRITICAL();           //进入临界区    /* 创建Flag1_Task任务 */  xReturn = xTaskCreate((TaskFunction_t )Flag1_Task, /* 任务入口函数 */                        (const char*    )"Flag1_Task",/* 任务名字 */                        (uint16_t       )512,   /* 任务栈大小 */                        (void*          )NULL,	/* 任务入口函数参数 */                        (UBaseType_t    )2,	    /* 任务的优先级 */                        (TaskHandle_t*  )&Task1_Handle);/* 任务控制块指针 */  if(pdPASS == xReturn)    printf("创建Flag1_Task任务成功!/r/n");		 /* 创建Flag2_Task任务 */  xReturn = xTaskCreate((TaskFunction_t )Flag2_Task, /* 任务入口函数 */                        (const char*    )"Flag2_Task",/* 任务名字 */                        (uint16_t       )512,   /* 任务栈大小 */                        (void*          )NULL,	/* 任务入口函数参数 */                        (UBaseType_t    )2,	    /* 任务的优先级 */                        (TaskHandle_t*  )&Task2_Handle);/* 任务控制块指针 */  if(pdPASS == xReturn)    printf("创建Flag2_Task任务成功!/r/n");			 /* 创建Flag3_Task任务 */  xReturn = xTaskCreate((TaskFunction_t )Flag3_Task, /* 任务入口函数 */                        (const char*    )"Flag3_Task",/* 任务名字 */                        (uint16_t       )512,   /* 任务栈大小 */                        (void*          )NULL,	/* 任务入口函数参数 */                        (UBaseType_t    )1,	    /* 任务的优先级 */                        (TaskHandle_t*  )&Task3_Handle);/* 任务控制块指针 */  if(pdPASS == xReturn)    printf("创建Flag3_Task任务成功!/r/n");    vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务    taskEXIT_CRITICAL();            //退出临界区}/**********************************************************************  * @ 函数名  : LED_Task  * @ 功能说明: LED_Task任务主体  ********************************************************************/uint8_t flag1;uint8_t flag2;uint8_t flag3;/*优先级2*/static void Flag1_Task(void* parameter){	static int value,i;	 while (1)    {						  for(i=10000;i>1;i--)			  flag1=1;        flag2=0;			  flag3=0;			  /* 向队列中填充内容 */  						  value++;			  printf("Task1 Running! value=%d/r/n",value);			  xQueueSend( MsgQueue, ( void* )&value, queueSEND_TO_BACK);  /*发送队列消息,*/						 // vTaskDelay(10);   /* 延时1个tick */    }}/*优先级2*/static void Flag2_Task(void* parameter){	static int value1;  	while (1)    {		  /*如果读取到队列消息*/			if(xQueueReceive(MsgQueue,(void *)&value1,pdFALSE)==pdPASS)			{			    flag1=0;          flag2=1;			    flag3=0;				  printf("Task2 Running! value=%d/r/n",value1);/*将读取到的数值打印出来*/			}			      //vTaskDelay(10);   /* 延时1个tick */		 		         }}/*优先级2*/static void Flag3_Task(void* parameter){	static int value2;  	while (1)    {		  flag1=0;      flag2=0;			flag3=1;		  printf("Task3 Running! value=%d/r/n",value2);		  vTaskDelay(10);   /* 延时1个tick */		 		         }}/***********************************************************************  * @ 函数名  : BSP_Init  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面  * @ 参数    :     * @ 返回值  : 无  *********************************************************************/static void BSP_Init(void){	/*	 * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15	 * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,	 * 都统一用这个优先级分组,千万不要再分组,切忌。	 */	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );		/* LED 初始化 */	LED_GPIO_Config();	/* 串口初始化	*/	USART_Config();  }/********************************END OF FILE****************************/

划重点

创建三个任务,优先级为321,

创建队列任务句柄,在这之前得要加入队列头文件

创建队列函数

xQueueCreate();

各任务处理事件

flag1Task

flag2Task

flag3Task

根据以上信息可以猜想任务运行过程是怎样的???

任务一和任务二在执行过程中都没有进入到阻塞状态,任务3的优先级是要比任务一和任务二要低的,所以任务三肯定不会运行,那么任务一和任务二相同优先级要如何运行呢??

直接仿真看看

神奇的是串口居然不乱了,任务一先运行,接着任务二打印了信息,这就是通过队列传递信息来实现任务同步

再来做个实验看看任务互斥

实验二:互斥

实验代码

/**   FreeRTOS v9.0.0 + STM32 动态创建任务   实验平台:韦东山 STM32F103ZE开发板 **/  #include "FreeRTOS.h"#include "task.h"#include "queue.h"/* 开发板硬件bsp头文件 */#include "bsp_led.h"#include "bsp_usart.h"/* 任务句柄 */static TaskHandle_t AppTaskCreate_Handle = NULL;static TaskHandle_t Task1_Handle = NULL;static TaskHandle_t Task2_Handle = NULL;//static TaskHandle_t Task3_Handle = NULL;//static QueueHandle_t xQueueCalcHandle;static QueueHandle_t xQueueUARTcHandle;/* 函数声明 */static void AppTaskCreate(void);/* 用于创建任务 */static void Flag1_Task(void* pvParameters);/* LED1_Task任务实现 */static void Flag2_Task(void* pvParameters);/* LED2_Task任务实现 *///static void Flag3_Task(void* pvParameters);/* LED3_Task任务实现 */static void BSP_Init(void);/* 用于初始化板载相关资源 *//*创建队列*/int InitUARTLock(void){		int val;	xQueueUARTcHandle = xQueueCreate(1, sizeof(int));/*创建队列*/	if (xQueueUARTcHandle == NULL)	{		printf("can not create queue/r/n");		return -1;/*创建失败*/	}	xQueueSend(xQueueUARTcHandle, &val, portMAX_DELAY);/*死等*/	return 0;/*创建成功*/}/*接收队列消息*/void GetUARTLock(void){		int val;	xQueueReceive(xQueueUARTcHandle, &val, portMAX_DELAY);}/*发送队列消息*/void PutUARTLock(void){		int val;	xQueueSend(xQueueUARTcHandle, &val, portMAX_DELAY);}/*****************************************************************  * @brief  主函数  * @param  无  * @retval 无  * @note   第一步:开发板硬件初始化             第二步:创建APP应用任务            第三步:启动FreeRTOS,开始多任务调度  ****************************************************************/int main(void){	  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */  /* 开发板硬件初始化 */  BSP_Init();  printf("这是一个STM32F103ZE开发板-FreeRTOS-动态创建任务!/r/n");		InitUARTLock();/*调用创建队列函数*/					   /* 创建AppTaskCreate任务 */  xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */                        (const char*    )"AppTaskCreate",/* 任务名字 */                        (uint16_t       )512,  /* 任务栈大小 */                        (void*          )NULL,/* 任务入口函数参数 */                        (UBaseType_t    )1, /* 任务的优先级 */                        (TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针 */   /* 启动任务调度 */             if(pdPASS == xReturn)    vTaskStartScheduler();   /* 启动任务,开启调度 */  else    return -1;      while(1);   /* 正常不会执行到这里 */    }/***********************************************************************  * @ 函数名  : AppTaskCreate  * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面  * @ 参数    : 无    * @ 返回值  : 无  **********************************************************************/static void AppTaskCreate(void){  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */    taskENTER_CRITICAL();           //进入临界区    /* 创建Flag1_Task任务 */  xReturn = xTaskCreate((TaskFunction_t )Flag1_Task, /* 任务入口函数 */                        (const char*    )"Flag1_Task",/* 任务名字 */                        (uint16_t       )512,   /* 任务栈大小 */                        (void*          )NULL,	/* 任务入口函数参数 */                        (UBaseType_t    )2,	    /* 任务的优先级 */                        (TaskHandle_t*  )&Task1_Handle);/* 任务控制块指针 */  if(pdPASS == xReturn)    printf("创建Flag1_Task任务成功!/r/n");		 /* 创建Flag2_Task任务 */  xReturn = xTaskCreate((TaskFunction_t )Flag2_Task, /* 任务入口函数 */                        (const char*    )"Flag2_Task",/* 任务名字 */                        (uint16_t       )512,   /* 任务栈大小 */                        (void*          )NULL,	/* 任务入口函数参数 */                        (UBaseType_t    )2,	    /* 任务的优先级 */                        (TaskHandle_t*  )&Task2_Handle);/* 任务控制块指针 */  if(pdPASS == xReturn)    printf("创建Flag2_Task任务成功!/r/n");			 /* 创建Flag3_Task任务 *///  xReturn = xTaskCreate((TaskFunction_t )Flag3_Task, /* 任务入口函数 *///                        (const char*    )"Flag3_Task",/* 任务名字 *///                        (uint16_t       )512,   /* 任务栈大小 *///                        (void*          )NULL,	/* 任务入口函数参数 *///                        (UBaseType_t    )1,	    /* 任务的优先级 *///                        (TaskHandle_t*  )&Task3_Handle);/* 任务控制块指针 *///  if(pdPASS == xReturn)//    printf("创建Flag3_Task任务成功!/r/n");    vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务    taskEXIT_CRITICAL();            //退出临界区}/**********************************************************************  * @ 函数名  : LED_Task  * @ 功能说明: LED_Task任务主体  ********************************************************************/uint8_t flag1;uint8_t flag2;uint8_t flag3;/*优先级2*/static void Flag1_Task(void* parameter){	 while (1)    {			GetUARTLock();/*调用接收消息函数获得使用权*/  						printf("Task1 Running!/r/n");						PutUARTLock();/*调用发送消息函数释放使用权*/			  					vTaskDelay(1);   /* 延时1个tick */		 		    }}/*优先级2*/static void Flag2_Task(void* parameter){  	while (1)    {      GetUARTLock();/*调用接收消息函数获得使用权*/						printf("Task2 Running!/r/n");						PutUARTLock();/*调用发送消息函数释放使用权*/			      vTaskDelay(1);   /* 延时1个tick */		 		         }}/*优先级1*///static void Flag3_Task(void* parameter)//{//	static int value2;//  	while (1)//    {//		  flag1=0;//      flag2=0;//			flag3=1;//		  printf("Task3 Running! value=%d/r/n",value2);//		  vTaskDelay(10);   /* 延时1个tick */		 		//     //    }//}/***********************************************************************  * @ 函数名  : BSP_Init  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面  * @ 参数    :     * @ 返回值  : 无  *********************************************************************/static void BSP_Init(void){	/*	 * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15	 * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,	 * 都统一用这个优先级分组,千万不要再分组,切忌。	 */	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );		/* LED 初始化 */	LED_GPIO_Config();	/* 串口初始化	*/	USART_Config();  }/********************************END OF FILE****************************/

划重点

这次实验创建了两个任务,任务优先级相同都为2


创建这几个函数

在任务处理事件中,像临界保护一样进行首先调用接收消息的函数获得使用权,再调用发送消息函数释放使用权。(队列里面有数据表示别人可以读这个队列)

仿真来看看实验效果

git仓库源码地址:https://gitee.com/he-dejiang/free-rtos.git

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121365.html

相关文章

  • Java 并发学习笔记(二)

    摘要:请参看前一篇文章并发学习笔记一原子性可见性有序性问题六等待通知机制什么是等待通知机制当线程不满足某个条件,则进入等待状态如果线程满足要求的某个条件后,则通知等待的线程重新执行。经极客时间并发编程实战专栏内容学习整理 请参看前一篇文章:Java 并发学习笔记(一)——原子性、可见性、有序性问题 六、等待—通知机制 什么是等待通知—机制?当线程不满足某个条件,则进入等待状态;如果线程满足要...

    zgbgx 评论0 收藏0
  • 常见物联网操作系统介绍

    摘要:相比之下,物联网操作系统领域的碎片化问题则非常严重,并没有哪几个操作系统占据绝对优势,正处于百花齐放百家争鸣的阶段。在年被公司正式收购,将自己的服务内嵌到系统中,并于年推出了集成无线连接安全等功能的物联网操作系统。 物联网操作系统是运行在物联网设备上的提供物物相连能力的操作系统,其核心在于...

    AdolphLWQ 评论0 收藏0
  • PHP进程通信

    摘要:一进程间通信理解间进程通信机制,先了解下进程间有哪些通讯机制历史发展按照历史来源主要有两大块的管道,,信号的消息队列,共享内存,信号灯。信号量主要作为进程间,以及进程内部线程之间的通讯手段。主要依赖,兼容扩展实现方式的进程间通信之消息队列。 PHP间进程如何通信,PHP相关的服务的IPC是实现方式,IPC的思想如何用到项目中。 一、linux进程间通信 理解php间进程通信机制,先了解...

    haobowd 评论0 收藏0
  • setTimeoutsetInterval

    摘要:工作线程执行异步任务,执行完成后把对应额回调函数封装成一条消息放到消息队列中主线程不断地从消息队列中取消息并执行。当消息队列为空时,主线程阻塞,直到消息队列再次非空。取决于何时被主线程的事件循环取到,并执行。 转自:http://palmer.arkstack.cn/201...一:平时简单使用 1.setTimeout延迟一段时间执行一次(only one) setTimeout(f...

    Tangpj 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<