uC/OS-III 队列(Queue)操作
队列(Queue)是 uC/OS-III 中用于任务间、任务与中断间数据传递的核心组件,支持异步通信与数据缓冲。本文基于 uC/OS-III 官方规范及工程实践,整理队列的标准操作流程,包括初始化、发送、接收、查询及异常处理,附完整代码示例与最佳实践。
一、队列核心概念与特性
uC/OS-III 的队列是线程安全的 FIFO(先进先出)缓冲区,支持以下关键特性:
- 多任务访问:多个任务可同时向队列发送数据,多个任务可等待接收数据(按优先级唤醒)。
- 中断安全:支持从中断服务程序(ISR)中发送数据(需用
FromISR
接口)。 - 灵活的数据单元:队列中可存储任意类型数据(以指针形式传递,支持固定 / 可变长度)。
- 阻塞机制:任务接收数据时可阻塞等待(带超时),无数据时不占用 CPU。
二、队列操作函数与标准写法
1. 队列初始化(创建队列)
功能:在系统启动阶段创建队列,分配内存并初始化元数据(如队列长度、名称)。函数:OSQCreate()
标准代码:
#include "os.h"// 定义队列参数
#define QUEUE_NAME "DATA_QUEUE" // 队列名称(调试用)
#define QUEUE_LEN 10 // 队列最大容量(可存储10条消息)
#define MSG_SIZE sizeof(void *)// 消息大小(以指针为单位,适配任意数据类型)// 全局队列对象(需在初始化后使用)
OS_Q data_queue;/*** @brief 初始化队列* @return OS_ERR:错误码(OS_ERR_NONE表示成功)*/
OS_ERR queue_init(void) {OS_ERR err;// 创建队列:名称、长度、错误码输出OSQCreate((OS_Q *)&data_queue,(CPU_CHAR *)QUEUE_NAME,(OS_MSG_QTY)QUEUE_LEN,(OS_ERR *)&err);// 初始化失败处理(工程中需记录日志或断言)if (err != OS_ERR_NONE) {APP_TRACE_ERROR(("Queue create failed! err: %d\n", err));}return err;
}
关键参数:
OS_MSG_QTY
:队列可容纳的最大消息数(超过则发送失败)。- 队列需在
OSStart()
前初始化,确保任务启动时可用。
2. 发送消息到队列(任务中)
功能:任务向队列发送数据,支持阻塞 / 非阻塞模式,发送成功后消息进入队列尾部。函数:OSQPost()
标准代码:
// 定义待发送的数据结构(示例)
typedef struct {uint8_t type; // 数据类型uint32_t value; // 数据值
} DataMsg_t;/*** @brief 任务中向队列发送消息(非阻塞模式)* @param msg:待发送的数据指针* @return OS_ERR:错误码(OS_ERR_NONE表示成功)*/
OS_ERR queue_send(DataMsg_t *msg) {OS_ERR err;if (msg == NULL) {return OS_ERR_INV_PTR; // 无效指针检查}// 发送消息:队列、消息指针、消息大小、FIFO模式、错误码OSQPost((OS_Q *)&data_queue,(void *)msg,(OS_MSG_SIZE)sizeof(DataMsg_t), // 实际数据大小(OS_OPT )OS_OPT_POST_FIFO, // FIFO顺序(先到先处理)(OS_ERR *)&err);// 处理发送结果if (err == OS_ERR_Q_FULL) {APP_TRACE_WARN(("Queue is full! Drop msg type: %d\n", msg->type));} else if (err != OS_ERR_NONE) {APP_TRACE_ERROR(("Send failed! err: %d\n", err));}return err;
}
关键选项:
OS_OPT_POST_FIFO
:按发送顺序排队(默认);OS_OPT_POST_LIFO
:后发消息优先处理(慎用,可能导致数据无序)。- 非阻塞模式下,队列满时返回
OS_ERR_Q_FULL
,需根据业务决定是否重试或丢弃。
3. 从队列接收消息(任务中)
功能:任务从队列获取消息,支持阻塞等待(带超时),获取成功后消息从队列中移除。函数:OSQPend()
标准代码:
/*** @brief 从队列接收消息(阻塞模式,永久等待)* @param msg:输出参数,接收消息的指针* @param timeout:超时时间(0表示永久等待,单位:系统时钟节拍)* @return OS_ERR:错误码(OS_ERR_NONE表示成功)*/
OS_ERR queue_receive(DataMsg_t **msg, OS_TICK timeout) {OS_ERR err;OS_MSG_SIZE msg_size; // 接收消息的实际大小(可选)*msg = (DataMsg_t *)OSQPend((OS_Q *)&data_queue,(OS_TICK )timeout,(OS_OPT )OS_OPT_PEND_BLOCKING, // 阻塞模式(OS_MSG_SIZE *)&msg_size,(CPU_TS )NULL, // 不记录时间戳(OS_ERR *)&err);// 处理接收结果if (err == OS_ERR_TIMEOUT) {APP_TRACE_INFO(("Receive timeout!\n"));*msg = NULL; // 超时返回空指针} else if (err != OS_ERR_NONE) {APP_TRACE_ERROR(("Receive failed! err: %d\n", err));*msg = NULL;} else {// 验证消息大小(可选,确保数据完整性)if (msg_size != sizeof(DataMsg_t)) {APP_TRACE_WARN(("Invalid msg size! Expect: %d, Got: %d\n", sizeof(DataMsg_t), msg_size));}}return err;
}
关键说明:
- 阻塞模式(
OS_OPT_PEND_BLOCKING
)下,无消息时任务进入阻塞态,不占用 CPU;超时后返回OS_ERR_TIMEOUT
。 - 消息接收后会从队列中删除,确保不会被重复处理(核心特性)。
4. 中断中发送消息
功能:中断服务程序(ISR)向队列发送消息,需使用中断安全的专用接口。函数:OSQPostFromISR()
标准代码:
/*** @brief 中断中向队列发送消息(ISR专用)* @param msg:待发送的数据指针(需确保在ISR外有效,如全局变量)*/
void queue_send_from_isr(DataMsg_t *msg) {OS_ERR err;if (msg == NULL) return;// 中断中发送消息:接口与任务版类似,但需用FromISROSQPostFromISR((OS_Q *)&data_queue,(void *)msg,(OS_MSG_SIZE)sizeof(DataMsg_t),(OS_OPT )OS_OPT_POST_FIFO,(OS_ERR *)&err);// 错误处理(ISR中避免复杂操作,仅记录关键错误)if (err == OS_ERR_Q_FULL) {// 队列满:可触发任务处理或丢弃(根据实时性需求)}// 触发任务调度(可选,确保高优先级任务立即执行)OSIntExit();
}
关键注意:
- ISR 中禁止使用阻塞操作,必须用
FromISR
版本接口(OSQPostFromISR
)。 - 消息缓冲区需为全局 / 静态变量(ISR 中栈内存不可靠)。
5. 队列状态查询
功能:查询队列当前消息数量、剩余容量等状态,用于监控或优化处理逻辑。函数:OSQEntries()
(消息数量)、OSQQuery()
(详细状态)标准代码:
/*** @brief 查询队列当前消息数量* @return 消息数量(0表示空队列)*/
OS_MSG_QTY queue_get_count(void) {OS_ERR err;OS_MSG_QTY count = OSQEntries((OS_Q *)&data_queue, (OS_ERR *)&err);if (err != OS_ERR_NONE) {APP_TRACE_ERROR(("Query count failed! err: %d\n", err));return 0;}return count;
}/*** @brief 查询队列详细状态(如最大容量、当前消息数)*/
void queue_query_details(void) {OS_ERR err;OS_Q_DATA q_data; // 队列详细信息结构体OSQQuery((OS_Q *)&data_queue,(OS_Q_DATA *)&q_data,(OS_ERR *)&err);if (err == OS_ERR_NONE) {APP_TRACE_INFO(("Queue details: Name=%s, Max len=%d, Current entries=%d\n",q_data.NamePtr, q_data.MaxEntries, q_data.NbrEntries));}
}
应用场景:
- 批量处理优化:接收任务唤醒后,通过
queue_get_count()
一次性处理所有消息。 - 系统监控:若队列消息数持续增长,可能预示消费者处理速度不足(需优化任务优先级或处理逻辑)。
6. 队列删除
功能:不再使用队列时释放资源(需确保无任务等待该队列)。函数:OSQDel()
标准代码:
/*** @brief 删除队列(谨慎使用,需确保无任务依赖)* @return OS_ERR:错误码*/
OS_ERR queue_delete(void) {OS_ERR err;// 删除队列:选项为强制删除(即使有任务等待)OSQDel((OS_Q *)&data_queue,(OS_OPT )OS_OPT_DEL_ALWAYS,(OS_ERR *)&err);if (err != OS_ERR_NONE) {APP_TRACE_ERROR(("Delete queue failed! err: %d\n", err));}return err;
}
注意:
- 队列删除后不可再使用,需确保所有依赖任务已停止。
- 嵌入式系统中队列通常伴随系统生命周期,较少需要动态删除。