FreeRTOS系统操作
一.简介
我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。目前使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ,我们后面会一一对比这些消息队列。
另外,我们知道队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。比如生产者发送消息1,2,3…对于消费者就会按照1,2,3…的顺序来消费。但是偶尔也会出现消息被消费的顺序不对的情况,比如某个消息消费失败又或者一个 queue 多个consumer 也会导致消息被消费的顺序不对,我们一定要保证消息被消费的顺序正确。
除了上面说的消息消费顺序的问题,使用消息队列,我们还要考虑如何保证消息不被重复消费?如何保证消息的可靠性传输(如何处理消息丢失的问题)?…等等问题。所以说使用消息队列也不是十全十美的,使用它也会让系统可用性降低、复杂度提高,另外需要我们保障一致性等问题。
二.测试准备
我们需要一个按键任务,和两个普通的任务,按键操作发出一个消息,来观察其他两个普通任务收到消息的情况,来很好的理解消息队列
三.代码部分
1.按键KEY
void StartDefaultTask_KEY(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask_KEY */
/* Infinite loop */
uint16_t ProducerValue = 0;
for(;;)
{
if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == 1)
{
osDelay(10);
if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == 1)
{
//生产者 按键按下后发送消息
if(osMessagePut(myQueue01Handle,ProducerValue,0) != osOK)
{
osThreadSuspendAll();
printf("发送失败\n");
osThreadResumeAll();
}
else
{
++ProducerValue;
osThreadSuspendAll();
printf("发送成功\n");
osThreadResumeAll();
}
while(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == 1)
{
osDelay(10);
}
}
}
osDelay(1);
}
/* USER CODE END StartDefaultTask_KEY */
}
注意
uint16_t ProducerValue = 0;
添加消息的时候 写的是 uint16_t ,所有这里也要定义
默认的数据类型是 uint32_t 没有这句代码 可以到软件修改
产生消息
osMessagePut(myQueue01Handle,ProducerValue,0)
这个参数 myQueue01Handle 是 操作消息队列的句柄
2.任务1
void StartTask01(void const * argument)
{
/* USER CODE BEGIN StartTask01 */
/* Infinite loop */
osEvent event;
for(;;)
{
event = osMessageGet(myQueue01Handle,osWaitForever);
if(event.status == osEventMessage)
{
printf("任务一接收的数据:%d",event.value.v);
}
osDelay(1);
}
/* USER CODE END StartTask01 */
}
3.任务2
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
osEvent event;
for(;;)
{
event = osMessageGet(myQueue01Handle,osWaitForever);
if(event.status == osEventMessage)
{
printf("任务二接收的数据:%d",event.value.v);
}
osDelay(1);
}
/* USER CODE END StartTask02 */
}
四.测试结果
这里我添加的两个任务的优先级都是一样的,所以一会是任务一得到消息,一会又是任务二
如果将任务一的优先级调到,比任务二的优先级高,则只能是任务一收的消息,因为任务一收到消息之后就将消息删除了,所以任务二是永远收不到消息的
如果将 osMessageGet()函数得到数据后删除消息 改为osMessagePeek()函数 得到后不删除消,则会显示任务一和任务二都能得到消息