队列集适用于多个发送者、多种数据(信号)类型向同一个接收者发送数据(信号)的情况。
队列集中可以包含队列和一些信号量。通过队列集,可以实现一个任务监听多个通信组件,从多个通信组件获取信号和数据的功能。
如图所示,队列集可以同时等待前述 queue、Semaphores、ringbuf 上的信号和数据,当其中一个组件有信号时,通过队列集返回的句柄可以从对应的组件上获取信号。
主要的 API 包括:
/*
* 创建队列集
*/
QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength // 指定一次可以排队的最大事件数。要绝对确定事件不会丢失 uxEventQueue长度应设置为添加到集合中的队列长度的总和,其中二进制信号量和互斥体的长度为 1,计数信号量的长度由其最大计数值设置(如最大计数为 5 的计数信号量,长度为5)。
);
/*
* 添加对象到队列集,注意将队列和信号量添加到队列集时,它们必须为空。
*/
BaseType_t xQueueAddToSet(
QueueSetMemberHandle_t xQueueOrSemaphore, // 要添加到队列集的队列或信号量的句柄
QueueSetHandle_t xQueueSet // 队列集的句柄
);
/*
* 从队列集中移除对象,注意将队列和信号量移除队列集时,它们必须为空。
*/
BaseType_t xQueueRemoveFromSet(QueueSetMemberHandle_txQueueOrSemaphore, // 要移除队列集的队列或信号量的句柄
QueueSetHandle_txQueueSet)// 队列集的句柄
/*
* 从队列集的成员中选择一个有效的队列或信号量,没有有效的成员时,将持续等待至最长时间后返回
*/
QueueSetMemberHandle_t xQueueSelectFromSet(QueueSetHandle_txQueueSet, // 队列集
const TickType_t xTicksToWait) // 获取操作的最长时间
通常,队列集使用的并不多,因为总是可以找到功能类似的通信组件来代替它。比如创建一个下述的结构体:
typedef struct IP_TASK_COMMANDS
{
eIPEvent_t eEventType; /* 标识事件类型 */
void *pvData; /* 指向与事件对应的数据. */
} xIPStackEvent_t;
然后通过队列来处理不同的消息。但是如果你的确有这种监听多种通信组件的需求,你仍然可以尝试使用队列集来完成这项功能。
示例创建了多个队列,并将这些队列加入到队列集中。任务1、任务2 分别向不同的队列发送数据,任务3 通过队列集同时监听任务1、任务2发送的数据并打印。
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 294408 bytes
TASK1: send=0
TASK2: send=0
TASK3: recv queue1 and value=0
TASK3: recv queue2 and value=0
TASK1: send=1
TASK2: send=1
TASK3: recv queue1 and value=1
TASK3: recv queue2 and value=1
TASK1: send=2
TASK2: send=2
TASK3: recv queue1 and value=2
TASK3: recv queue2 and value=2
允许将队列、信号量、ringbuf加入到队列集,但为什么没有提到将 streambuf、messagebuf 加入到队列集呢?
答案你可以在过去讲述 streambuf、messagebuf 的章节找到答案,欢迎读者留言公布答案。
1)允许将队列、信号量、ringbuf加入到队列集,通过队列集实现同时从多个通信组件接收信号或数据的目的。
1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)
3)下一篇:FreeRTOS 任务任务同步与数据传递总结