freertos 队列集发送接收消息

本文探讨了FreeRTOS队列集的工作原理,比较了两种出队策略:逐个消息接收与一次性取出所有。实验结果显示队列集按发送次数触发事件,一次性获取所有消息避免了消息丢失。讨论了内存限制下可能的问题并以数组发送为例。
摘要由CSDN通过智能技术生成

最近看队列集,看到网上说队列集成员句柄里的消息要一次性全拿出来

我理解成是不是往队列集的同一个成员发送多次消息也只会触发一次事件呢?

还是说队列集和队列一样一次发送就触发一次事件?

动手测试一下

代码如下,两个出队列方法:

//test   消息队列集测试

	//方法1,是每次只从队列集获取一个消息
	printf("\r\n\r\n ********方法1,是每次只从队列集获取一个消息 ********\r\n\r\n" );
	Send_data = 1 ;
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);
	Send_data = 2 ;
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);
	Send_data = 3 ;
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);

	Send_data = 4 ;
	xQueueSend(T_queue2, (void *)&Send_data, (TickType_t)2);
	Send_data = 5 ;
	xQueueSend(T_queue2, (void *)&Send_data, (TickType_t)2);
	Send_data = 6 ;
	xQueueSend(T_queue2, (void *)&Send_data, (TickType_t)2);


	while(1)
	{
		HAL_Delay(100);
			
		ActivatedQueue = xQueueSelectFromSet(T_QueueSet, 0);

		if(ActivatedQueue == T_queue1)
		{
			result = xQueueReceive(T_queue1, &Rev_data, 0);
			if( result == pdPASS ) 
			{
				 printf("\r\n方法1: T_queue1 Receive = %d \r\n", Rev_data ); 
			}
			else
			{ 
				printf("\r\n方法1: xQueueReceive T_queue1 fail !!!  result = %d \r\n",  result  ); 
			}
		}
		else if(ActivatedQueue == T_queue2)
		{
			result = xQueueReceive(T_queue2, &Rev_data, 0);
			if( result == pdPASS ) 
			{ 
				printf("\r\n方法1: T_queue2 Receive = %d \r\n", Rev_data ); 
			}
			else
			{ 
				printf("\r\n方法1: xQueueReceive T_queue2 fail !!!  result = %d \r\n",  result  ); 
			}
		}
		else { break; }
	}

//方法2,是每次从队列集获取到句柄之后,就把该消息队列句柄里的消息全拿出来
	printf("\r\n\r\n ********方法2,是每次从队列集获取到句柄之后,就把该消息队列句柄里的消息全拿出来 ********\r\n\r\n" );
	Send_data = 11 ;
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);
	Send_data = 12 ;
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);
	Send_data = 13 ;
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);

	Send_data = 14 ;
	xQueueSend(T_queue2, (void *)&Send_data, (TickType_t)2);
	Send_data = 15 ;
	xQueueSend(T_queue2, (void *)&Send_data, (TickType_t)2);
	Send_data = 16 ;
	xQueueSend(T_queue2, (void *)&Send_data, (TickType_t)2);
	while(1)
	{
		HAL_Delay(100);
			
		ActivatedQueue = xQueueSelectFromSet(T_QueueSet, 0);

		if(ActivatedQueue == T_queue1)
		{
			while( 1 )
			{
				result = xQueueReceive(T_queue1, &Rev_data, 0);
				if( result == pdPASS ) 
				{ 
					printf("\r\n方法2: T_queue1 Receive = %d \r\n", Rev_data ); 
				}
				else
				{ 
					printf("\r\n方法2: T_queue1 已全部出队列 !!!  result = %d \r\n",  result  );  
					break; 
				}
			}
			
		}
		else if(ActivatedQueue == T_queue2)
		{
			while( 1 )
			{
				result = xQueueReceive(T_queue2, &Rev_data, 0);
				if( result == pdPASS ) 
				{ 
					printf("\r\n方法2: T_queue2 Receive = %d \r\n", Rev_data ); 
				}
				else
				{ 
					printf("\r\n方法2: T_queue2 已全部出队列 !!!  result = %d \r\n",  result  );  
					break; 
				}
			}
		}
		else { break; }
	}

//test   消息队列集测试

最后log结果如下:

********方法1,是每次只从队列集获取一个消息 ********


方法1: T_queue1 Receive = 1 

方法1: T_queue1 Receive = 2 

方法1: T_queue1 Receive = 3 

方法1: T_queue2 Receive = 4 

方法1: T_queue2 Receive = 5 

方法1: T_queue2 Receive = 6 


 ********方法2,是每次从队列集获取到句柄之后,就把该消息队列句柄里的消息全拿出来 ********


方法2: T_queue1 Receive = 11 

方法2: T_queue1 Receive = 12 

方法2: T_queue1 Receive = 13 

方法2: T_queue1 已全部出队列 !!!  result = 0 

方法2: T_queue1 已全部出队列 !!!  result = 0 

方法2: T_queue1 已全部出队列 !!!  result = 0 

方法2: T_queue2 Receive = 14 

方法2: T_queue2 Receive = 15 

方法2: T_queue2 Receive = 16 

方法2: T_queue2 已全部出队列 !!!  result = 0 

方法2: T_queue2 已全部出队列 !!!  result = 0 

方法2: T_queue2 已全部出队列 !!!  result = 0 

事实证明队列集还是和队列一样,每send一次就会产生一个事件.

而且方法二发现,即使我一次性把三个消息全拿出来,后面还是能再次获取队列句柄,所以是每send一次就会触发一次事件.

实践出真知

那如果只获取句柄并不取消息呢?

在使用了3次之后 xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);

        log只打了3次就没有了, 从而得知,一旦使用了 xQueueSelectFromSet 去获取队列集发生消息事件的队列句柄,就需要去该队列去取一次消息,

        不取也不会再次触发事件了, 无法再得知该队列有消息进来而导致该条消息应用层面的丢失, 这应该就是我在网上看到 " 队列集成员句柄里的消息要一次性全拿出来 "的意思吧吧

        其含义应该是该条消息要一次性全都拿完

 

测到这里,可以结束了, 只是我又想到,freertos的消息队列实际是值的拷贝,

那我们往队列集发送一串数组会怎么样呢?

稍加修改上面的代码

static QueueHandle_t T_queue1 = NULL;
static QueueHandle_t T_queue2 = NULL;
static xQueueSetHandle T_QueueSet = NULL;

void Master_EventCreat(void)
{
	T_queue1 = xQueueCreate(3, sizeof(char)*100);
	if(T_queue1 == NULL){
		Error_Handler(__FILE__, __LINE__);
	}

	T_queue2 = xQueueCreate(3, sizeof(char)*100);
	if(T_queue2 == NULL){
		Error_Handler(__FILE__, __LINE__);
	}

	/* 创建多事件等待集合 */
	T_QueueSet = xQueueCreateSet( 6 );
	if( T_QueueSet == NULL ){
		Error_Handler(__FILE__, __LINE__);
	}

	/* 添加消息队列和信号量到Core_QueueSet, 添加时消息队列和信号量必须是空的 */
	xQueueAddToSet(T_queue1,		T_QueueSet);
	xQueueAddToSet(T_queue2,		T_QueueSet);
	
}



//方法1,是每次只从队列集获取一个消息
	printf("\r\n\r\n ********方法1,是每次只从队列集获取一个消息 ********\r\n\r\n" );

	snprintf( Send_data, 100, " I AM head1"); 
	snprintf( &Send_data[50], 50, " I AM test1"); 
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);

	snprintf( Send_data, 100, " I AM head2"); 	
	snprintf( &Send_data[50], 50, " I AM test2"); 
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);

	snprintf( Send_data, 100, " I AM head3"); 	
	snprintf( &Send_data[50], 50, " I AM test3"); 
	xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);

	while(1)
	{
		HAL_Delay(100);
			
		ActivatedQueue = xQueueSelectFromSet(T_QueueSet, 0);

		if(ActivatedQueue == T_queue1)
		{
			result = xQueueReceive(T_queue1, &Rev_data, 0);
			if( result == pdPASS ) 
			{
				 printf("\r\n方法1: T_queue1 Receive[0]  = %s \r\n", Rev_data ); 
				 printf("\r\n方法1: T_queue1 Receive[50] = %s \r\n\r\n", &Rev_data[50] ); 
			}
			else
			{ 
				printf("\r\n方法1: xQueueReceive T_queue1 fail !!!  result = %d \r\n",  result  ); 
			}
		}
		else { break; }
	}

最后log结果如下:

        所以我想xQueueSend(T_queue1, (void *)&Send_data, (TickType_t)2);是把 Send_data这个变量的 sizeof(char)*100 个字节 (因为T_queue1 = xQueueCreate(3, sizeof(char)*100);) 拷贝到自己的消息区了.

        那么,问题来了,假设我们 xQueueSend 和 xQueueReceive 的变量内存小于创建该该队列单条消息的内存, 因为他是固定复制xQueueCreate时的大小, 那么可能会发生访问非法地址!!! (推测,没有验证过......)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值