对于FreeRTOS来说,队列集提供了一种机制,允许 RTOS 任务同时在多个 RTOS 队列或信号量上 阻塞(挂起),等待读取操作,队列集可以用于将多个队列、信号量绑定在同一个接口进行监听,从而实现统一管理;队列集是对传统线程交互接口的补充,用于Task中需要监视多个信号的场景。

队列集就好像我们在火锅店吃火锅时候的摆台,我们点完餐以后,服务员会将菜品放到摆台上,供我们顾客去取用,羊肉、牛肉这些菜品就好像队列和信号量,菜品准备好了以后,直接放到摆台这里,也就是将队列放到队列集,顾客在检查队列集(摆台)的时候, 知道哪个队列里面有数据了,或者信号量被释放了,信号量释放一般也代表数据准备好了
队列集处理接口
1. 任务集处理接口
对于任务集的处理接口如下所示。
|-------------------------------------------------|-------------|
| xQueueCreateSet/ xQueueCreateSetStatic | 创建队列集 |
| xQueueAddToSet | 添加队列/信号到队列集 |
| xQueueRemoveFromSet | 从队列集中移除数据 |
| xQueueSelectFromSet/ xQueueSelectFromSetFromISR | 任务监听和处理 |
对于上述接口,比较核心的API如下所示。
cpp
/// @brief 创建队列集
/// @param uxEventQueueLength 用于指定队列集中一次最多可以排队的事件数量
/// @return QueueSetHandle_t 返回创建的队列集
QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength)
/// @brief 创建队列集
/// @param uxEventQueueLength 用于指定队列集中一次最多可以排队的事件数量
/// @param pucQueueStorage 指向容纳uxEventQueueLength事件的uint8_t数组
/// @param pxStaticQueue 存储队列的数据结构
/// @return QueueSetHandle_t 返回创建的队列集
QueueSetHandle_t xQueueCreateSetStatic( const UBaseType_t uxEventQueueLength, uint8_t * pucQueueStorage,StaticQueue_t * pxStaticQueue )
/// @brief 将队列或者信号量添加到队列集
/// @param xQueueOrSemaphore 添加到队列集的队列或信号量的句柄
/// @param xQueueSet 队列或信号量被添加到的队列集合的句柄
/// @return BaseType_t 加入队列集的结果
BaseType_t xQueueAddToSet(QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet)
/// @brief 从队列集中移除队列或者信号量
/// @param xQueueOrSemaphore 队列或信号量的句柄从队列集中移除
/// @param xQueueSet 包含队列或信号量的队列集合的句柄
/// @return BaseType_t 移除的结果,成功返回pdPASS
BaseType_t xQueueRemoveFromSet(QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet);
/// @brief 从队列集的成员中选择队列或信号量(存在信号)
/// @param xQueueSet 任务可能被阻塞的队列集合
/// @param xTicksToWait 调用任务保持阻塞状态的最长时间
/// @return QueueSetMemberHandle_t 返回队列的句柄
QueueSetMemberHandle_t xQueueSelectFromSet(QueueSetHandle_t xQueueSet,const TickType_t xTicksToWait)
在系统中支持的队列集需要的宏命令如下所示。
cpp
// 定义支持队列集功能
#define configUSE_QUEUE_SETS 1
队列集接口应用
1. 任务集应用接口
对于队列集来说,这里以队列和信号量共同组成的应用如下所示。
cpp
static TaskHandle_t xQsrHandle = NULL;
static TaskHandle_t xQswHandle = NULL;
static QueueHandle_t xQueue1 = NULL;
static QueueHandle_t xQueue2 = NULL;
static SemaphoreHandle_t xSemaphore1 = NULL;
static QueueSetHandle_t xQueueSet = NULL;
#define QUEUE1_LENGTH 10
#define QUEUE2_LENGTH 10
#define BINARY_SEMAPHORE_LENGTH 1
#define QUEUE_SET_COMBIAND_LENGTH (QUEUE1_LENGTH + QUEUE2_LENGTH + BINARY_SEMAPHORE_LENGTH)
//队列集,分别往队列里面添加数据,释放信号量
static void queueset_writer_task(void *argument)
{
uint32_t value = 0;
while(1)
{
xQueueSend(xQueue1, &value, portMAX_DELAY);
value++;
xQueueSend(xQueue2, &value, portMAX_DELAY);
value++;
//xSemaphoreGive(xSemaphore1)是 FreeRTOS 中用于释放信号量的核心 API 函数。调用该函数会将信号量 xSemaphore1 的计数器加 1,从而允许其他等待该信号量的任务解除阻塞并继续执行。
xSemaphoreGive(xSemaphore1);
vTaskDelay(1000);
}
}
static void queueset_reader_task(void *argument)
{
QueueSetMemberHandle_t xActivatedMember;
while(1)
{
//检查队列集中的队列或者信号量,也就是阻塞并监听多个队列或信号量
xActivatedMember = xQueueSelectFromSet(xQueueSet, portMAX_DELAY);
//检测到xQueue1有数据了
if (xActivatedMember == xQueue1)
{
int value;
xQueueReceive(xQueue1, &value, portMAX_DELAY);
PRINT_LOG(LOG_INFO, 0, "queueset_reader_task: xQueue1: %d", value);
}
else if (xActivatedMember == xQueue2)
{
int value;
xQueueReceive(xQueue2, &value, portMAX_DELAY);
PRINT_LOG(LOG_INFO, 0, "queueset_reader_task: xQueue2: %d", value);
}
else if (xActivatedMember == xSemaphore1)
{
xSemaphoreTake(xSemaphore1, portMAX_DELAY);
PRINT_LOG(LOG_INFO, 0, "queueset_reader_task: xSemaphore1");
}
else
{
PRINT_LOG(LOG_INFO, 0, "queueset_reader_task: xQueueSet: %d", xActivatedMember);
}
}
}
GlobalType_t app_queueset_init(void)
{
BaseType_t xReturned;
// task reader create
xReturned = xTaskCreate(queueset_reader_task,
"queueset_reader_task",
256,
NULL,
tskIDLE_PRIORITY + 2,
&xQsrHandle);
xReturned &= xTaskCreate(queueset_writer_task,
"queueset_writer_task",
256,
NULL,
tskIDLE_PRIORITY + 2,
&xQswHandle);
// queue create
xQueue1 = xQueueCreate(10, sizeof(int));
xQueue2 = xQueueCreate(10, sizeof(int));
vQueueAddToRegistry(xQueue1, "testQueue1");
vQueueAddToRegistry(xQueue2, "testQueue2");
xSemaphore1 = xSemaphoreCreateBinary();
// queue set create
xQueueSet = xQueueCreateSet(QUEUE_SET_COMBIAND_LENGTH);
xReturned &= xQueueAddToSet(xQueue1, xQueueSet); //队列集添加队列xQueue1
xReturned &= xQueueAddToSet(xQueue2, xQueueSet); //队列集添加队列xQueue2
xReturned &= xQueueAddToSet(xSemaphore1, xQueueSet); //队列集添加信号量xSemaphore1
//检测队列集、队列、信号量是否创建成功
if (xReturned != pdPASS
|| xQueue1 == NULL
|| xQueue2 == NULL
|| xSemaphore1 == NULL
|| xQueueSet == NULL)
{
return RT_FAIL;
}
return RT_OK;
}
可以看到,队列集可以实现类似Linux平台的select的功能,通过一个接口实现队列、信号量的统一管理;这样可以扩展队列间通讯方法,构建更加复杂的应用。