reeRTOS队列提供:
- 任务间数据传递;
- 按值复制数据;
- 多条消息缓存;
- 队列为空时阻塞接收任务;
- 队列满时阻塞发送任务;
- 自动处理并发访问。
创建
static QueueHandle_t xSensorQueue = null;
xSensorQueue = xQueueCreate(3, sizeof(SensorMessage_t));
生产的消息类型
typedef struct
{
uint32_t ulSequence;
int32_t lValue;
} SensorMessage_t;
生产者
static void vProducerTask(void *pvParameters)
{
SensorMessage_t xMessage;
(void)pvParameters;
xMessage.ulSequence = 0;
xMessage.lValue = 100;
for (;;)
{
if (xQueueSend(xSensorQueue, &xMessage, portMAX_DELAY) == pdPASS) //消息发送成功返回
{
printf("生产消息\n");
}
xMessage.ulSequence++;
xMessage.lValue += 10;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
消费者
static void vConsumerTask(void *pvParameters)
{
SensorMessage_t xReceived; //接收消息的对象
(void)pvParameters;
for (;;)
{
if (xQueueReceive(xSensorQueue, &xReceived, portMAX_DELAY) == pdPASS) //队列是否为空判断
{
printf("处理消息\n");
}
}
}
创建两个任务
xTaskCreate(vConsumerTask,"Consumer",configMINIMAL_STACK_SIZE,NULL,2,NULL); //高优先级
xTaskCreate(vProducerTask,"Producer",configMINIMAL_STACK_SIZE,NULL,1,NULL);
启动之后流程
-
调度器首先运行Consumer。但此时队列为空。
Consumer:Running → Blocked -
portMAX_DELAY在当前配置下表示持续等待,直到有消息到达。 -
Consumer阻塞以后,Producer才开始运行。
-
队列会把消息内容复制到自己的内部存储区:
Producer的xMessage ↓ 复制 Queue内部消息槽 队列保存的不是:&xMessage指针,而是整个:SensorMessage_t结构体的副本。 -
Producer把消息写入队列
-
Consumer等待的条件满足:队列不再为空
Consumer:Blocked → Ready Consumer优先级2 > Producer优先级1 所以: Producer:Running → Ready Consumer:Ready → Running -
消费信息,队列又空了,consumer再次阻塞。
-
Producer才恢复执行。
Producer进入xQueueSend()
→ 消息复制进队列
→ Consumer被唤醒
→ Consumer抢占Producer
→ Consumer取走并打印消息
→ Consumer再次阻塞
→ Producer从xQueueSend()中恢复
→ Producer打印sent
- Queue用于在任务之间安全传递数据。
- xQueueSend默认复制消息内容。
- 队列为空时,接收任务可以进入Blocked。
- 消息到来后,接收任务自动恢复Ready。
- 如果被唤醒任务优先级更高,发送API内部就可能发生抢占。
- 队列让任务等待数据,而不是持续轮询数据。