Coze AI平台:低代码工作流与智能体开发实战
2026/7/17 8:05:04
入队(Enqueue):向队列中添加数据(发送消息)出队(Dequeue):从队列中获取数据(接收消息)
FreeRTOS队列采用FIFO(先进先出)机制,是任务间通信的核心方式。队列存储的是数据的拷贝,而非指针,确保了数据安全。
队列的核心结构体Queue_t包含以下关键成员:
typedef struct QueueDefinition { int8_t *pcHead; // 指向队列存储区开始地址 int8_t *pcWriteTo; // 指向存储区中下一个空闲位置 union { QueuePointers_t xQueue; // 队列相关数据 SemaphoreData_t xSemaphore; // 信号量相关数据 } u; List_t xTasksWaitingToSend; // 等待发送任务列表(按优先级排序) List_t xTasksWaitingToReceive; // 等待接收任务列表(按优先级排序) volatile UBaseType_t uxMessagesWaiting; // 当前队列中消息数量 UBaseType_t uxLength; // 队列长度(最大可存储消息数) UBaseType_t uxItemSize; // 每个消息的大小 volatile int8_t cRxLock; // 接收锁 } Queue_t;pcWriteTo == pcReadFrompcWriteTo + itemSize == pcReadFrom(考虑回绕)// 向队列尾部入队(默认方式) BaseType_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait); // 向队列头部入队 BaseType_t xQueueSendToFront(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait); // 覆写入队(仅当队列长度为1时有效) BaseType_t xQueueOverwrite(QueueHandle_t xQueue, const void *pvItemToQueue);检查队列状态:
数据拷贝:
prvCopyDataToQueue将数据从源地址拷贝到队列存储区uxMessagesWaiting(消息数量)+1任务唤醒:
xTasksWaitingToReceive非空)vTaskMissedYield()进行任务切换队列满处理:
errQUEUE_FULL| 阻塞时间 | 行为 |
|---|---|
| 0 | 立即返回,不等待 |
| 0 ~ portMAX_DELAY | 等待指定时间,超时后返回 |
| portMAX_DELAY | 无限等待,直到队列有空闲位置 |
// 从队列接收数据(出队并删除数据) BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); // 从队列读取数据(出队但不删除数据) BaseType_t xQueuePeek(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);检查队列状态:
数据拷贝:
uxMessagesWaiting(消息数量)-1任务唤醒:
xTasksWaitingToSend非空)vTaskMissedYield()进行任务切换队列空处理:
errQUEUE_EMPTY| 阻塞时间 | 行为 |
|---|---|
| 0 | 立即返回,不等待 |
| 0 ~ portMAX_DELAY | 等待指定时间,超时后返回 |
| portMAX_DELAY | 无限等待,直到队列有消息 |
| 特性 | 入队 | 出队 |
|---|---|---|
| 数据传递方式 | 值传递(拷贝数据) | 值传递(拷贝数据) |
| 队列满处理 | 阻塞等待或返回错误 | 队列满不影响入队 |
| 队列空处理 | 队列空不影响出队 | 阻塞等待或返回错误 |
| 阻塞优先级 | 优先级最高的任务先被唤醒 | 优先级最高的任务先被唤醒 |
| 消息顺序 | FIFO(先进先出) | FIFO(先进先出) |
// 创建队列 QueueHandle_t xQueue = xQueueCreate(5, sizeof(uint32_t)); // 任务中发送消息 void SenderTask(void *pvParameters) { uint32_t data = 0; while(1) { data++; // 向队列尾部发送数据,阻塞等待10个tick if(xQueueSendToBack(xQueue, &data, 10) != pdPASS) { // 队列满,处理错误 } } }// 任务中接收消息 void ReceiverTask(void *pvParameters) { uint32_t data; while(1) { // 从队列头部接收数据,永久阻塞 if(xQueueReceive(xQueue, &data, portMAX_DELAY) == pdPASS) { // 处理接收到的数据 } } }数据拷贝:队列存储的是数据的拷贝,不是指针。传递大结构体时,建议使用指针传递(传递结构体地址),但需确保指针指向的数据在队列处理期间有效。
队列长度:合理设置队列长度,过小会导致频繁阻塞,过大则浪费内存。
阻塞时间:根据应用需求设置合适的阻塞时间,避免任务长时间阻塞。
中断安全:在中断中操作队列,必须使用xQueueSendFromISR和xQueueReceiveFromISR。
队列空/满检测:使用uxQueueMessagesWaiting()和uxQueueSpacesAvailable()查询队列状态,避免数据丢失。
任务A(发送) 队列 任务B(接收) | | | | 入队操作 | | |----------------->| | | | | | | | | | 入队成功 | | |--------------->| | | | | | | | | | | | 出队操作 | | |<---------------| | | | | | |入队和出队操作确保了任务间的解耦,使系统设计更加清晰、灵活,是FreeRTOS中实现任务间通信的关键机制。