队列集
在使用队列进行任务之间的“沟通交流”时,一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。 FreeRTOS提供的队列集功能可以对多个队列进行“监听”,只要被监听的队列中有一个队列有有效的消息,那么队列集的读取任务都可以读取到消息,如果读取任务因读取队列集而被阻塞,那么队列集将解除读取任务的阻塞。使用队列集的好处在于,队列集可以读取多个队列中的消息,而无需遍历所有待读取的队列,以确定具体读取哪一个队列。使用队列集功能,需要在 FreeRTOSConfig.h 文件中将配置项 configUSE_QUEUE_SETS 配置为 1,来启用队列集功能。
队列集相关 API 函数
函数 | 描述 |
xQueueCreateSet() | 创建队列集 |
xQueueAddToSet() | 队列添加到队列集中 |
xQueueRemoveFromSet() | 从队列集中移除队列 |
xQueueSelectFromSet() | 获取队列集中有有效消息的队列 |
xQueueSelectFromSetFromISR() | 在中断中获取队列集中有有效消息的队列 |
函数 xQueueCreateSet()
此函数用于创建队列集,该函数在 queue.c 文件中有定义, 函数的原型如下所示:
QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength )
{
QueueSetHandle_t pxQueue;
traceENTER_xQueueCreateSet( uxEventQueueLength );
pxQueue = xQueueGenericCreate( uxEventQueueLength, ( UBaseType_t ) sizeof( Queue_t * ), queueQUEUE_TYPE_SET );
traceRETURN_xQueueCreateSet( pxQueue );
return pxQueue;
}
形参 | 描述 |
uxEventQueueLength | 队列集可容纳的队列数量 |
返回值 | 描述 |
NULL | 队列集创建失败 |
其他值 | 队列集创建成功,返回队列集 |
函数 xQueueAddToSet()
此函数用于往队列集中添加队列,要注意的时,队列在被添加到队列集之前,队列中不能有有效的消息,该函数在 queue.c 文件中有定义,函数的原型如下所示:
BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet )
{
BaseType_t xReturn;
traceENTER_xQueueAddToSet( xQueueOrSemaphore, xQueueSet );
taskENTER_CRITICAL();
{
if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL )
{
/* Cannot add a queue/semaphore to more than one queue set. */
xReturn = pdFAIL;
}
else if( ( ( Queue_t * ) xQueueOrSemaphore )->uxMessagesWaiting != ( UBaseType_t ) 0 )
{
/* Cannot add a queue/semaphore to a queue set if there are already
* items in the queue/semaphore. */
xReturn = pdFAIL;
}
else
{
( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet;
xReturn = pdPASS;
}
}
taskEXIT_CRITICAL();
traceRETURN_xQueueAddToSet( xReturn );
return xReturn;
}
形参 | 描述 |
xQueueOrSemaphore | 待添加的队列 |
xQueueSet | 队列集 |
返回值 | 描述 |
pdPASS | 队列集添加队列成功 |
pdFAIL | 队列集添加队列失败 |
函数 xQueueRemoveFromSet()
此函数用于从队列集中移除队列, 要注意的时,队列在从队列集移除之前,必须没有有效的消息, 该函数在 queue.c 文件中有定义,函数的原型如下所示:
BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet )
{
BaseType_t xReturn;
Queue_t * const pxQueueOrSemaphore = ( Queue_t * ) xQueueOrSemaphore;
traceENTER_xQueueRemoveFromSet( xQueueOrSemaphore, xQueueSet );
if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet )
{
/* The queue was not a member of the set. */
xReturn = pdFAIL;
}
else if( pxQueueOrSemaphore->uxMessagesWaiting != ( UBaseType_t ) 0 )
{
/* It is dangerous to remove a queue from a set when the queue is
* not empty because the queue set will still hold pending events for
* the queue. */
xReturn = pdFAIL;
}
else
{
taskENTER_CRITICAL();
{
/* The queue is no longer contained in the set. */
pxQueueOrSemaphore->pxQueueSetContainer = NULL;
}
taskEXIT_CRITICAL();
xReturn = pdPASS;
}
traceRETURN_xQueueRemoveFromSet( xReturn );
return xReturn;
}
形参 | 描述 |
xQueueOrSemaphore | 待移除的队列 |
xQueueSet | 队列集 |
返回值 | 描述 |
pdPASS | 队列集移除队列成功 |
pdFAIL | 队列集移除队列失败 |
函数 xQueueSelectFromSet()
此函数用于在任务中获取队列集中有有效消息的队列,该函数在 queue.c 文件中有定义,函数的原型如下所示:
QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
TickType_t const xTicksToWait )
{
QueueSetMemberHandle_t xReturn = NULL;
traceENTER_xQueueSelectFromSet( xQueueSet, xTicksToWait );
( void ) xQueueReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait );
traceRETURN_xQueueSelectFromSet( xReturn );
return xReturn;
}
形参 | 描述 |
xQueueSet | 队列集 |
xTicksToWait | 阻塞超时时间 |
返回值 | 描述 |
NULL | 获取消息失败 |
其他值 | 获取到消息的队列 |
函数 xQueueSelectFromSetFromISR()
此函数用于在中断中获取队列集中有有效消息的队列,该函数在 queue.c 文件中有定义,函数的原型如下所示:
QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet )
{
QueueSetMemberHandle_t xReturn = NULL;
traceENTER_xQueueSelectFromSetFromISR( xQueueSet );
( void ) xQueueReceiveFromISR( ( QueueHandle_t ) xQueueSet, &xReturn, NULL );
traceRETURN_xQueueSelectFromSetFromISR( xReturn );
return xReturn;
}
返回值 | 描述 |
NULL | 获取消息失败 |
其他值 | 获取到消息的队列 |
队列集操作实验
TaskHandle_t xTaskHandle_1;
TaskHandle_t xTaskHandle_2;
void vTaskFunction_1(void *pvParameters);
void vTaskFunction_2(void *pvParameters);
QueueSetHandle_t xQueueSet;
QueueHandle_t xQueue1;
QueueHandle_t xQueue2;
//init
//队列集长度 ≥ 绑定的队列数量 × 每个队列可能产生的事件数
xQueueSet = xQueueCreateSet(4);
xQueue1 = xQueueCreate(2, sizeof(int));
xQueue2 = xQueueCreate(2, sizeof(int));
xQueueAddToSet(xQueue1, xQueueSet);
xQueueAddToSet(xQueue2, xQueueSet);
xTaskCreate(vTaskFunction_1, "Task1", 8192, NULL, 1, &xTaskHandle_1 );
xTaskCreate(vTaskFunction_2, "Task2", 8192, NULL, 1, &xTaskHandle_2 );
void vTaskFunction_1(void *pvParameters)
{
int i=0;
while(1) {
if(i%2 == 0) {
xQueueSend(xQueue1, &i, portMAX_DELAY);
} else {
xQueueSend(xQueue2, &i, portMAX_DELAY);
}
i++;
vTaskDelay(200);
}
}
void vTaskFunction_2(void *pvParameters)
{
int queue_recv = 0;
QueueSetMemberHandle_t activate_member;
while(1) {
activate_member = xQueueSelectFromSet(xQueueSet, portMAX_DELAY);
if (activate_member == xQueue1) {
xQueueReceive(activate_member, &queue_recv, portMAX_DELAY);
printf("接收到来自 xQueue1 的消息: %d\r\n", queue_recv);
}
else if (activate_member == xQueue2) {
xQueueReceive(activate_member, &queue_recv, portMAX_DELAY);
printf("接收到来自 xQueue2 的消息: %d\r\n", queue_recv);
}
vTaskDelay(200);
}
}
测试结果:
接收到来自 xQueue1 的消息: 0
接收到来自 xQueue2 的消息: 1
接收到来自 xQueue1 的消息: 2
接收到来自 xQueue2 的消息: 3
接收到来自 xQueue1 的消息: 4
接收到来自 xQueue2 的消息: 5
接收到来自 xQueue1 的消息: 6
接收到来自 xQueue2 的消息: 7
接收到来自 xQueue1 的消息: 8
接收到来自 xQueue2 的消息: 9
接收到来自 xQueue1 的消息: 10