核心接口
消息队列通过初始化、发送、接收和清理接口管理数据。 以下为本页对应的接口声明;实际参数、类型定义及返回值语义应与项目当前版本的头文件保持一致。
void os_msgq_init(os_msgq_t *q, u8 *buf, u8 size); char os_msgq_send(os_msgq_t *q, u8 obj, u8 data, char nonblock); char os_msgq_recv(os_msgq_t *q, u8 obj, u8 *data, char nonblock); void os_msgq_clear(os_msgq_t *q);
os_msgq_init():初始化队列对象,并关联调用方提供的缓冲区。os_msgq_send():尝试向队列写入一个字节的数据。os_msgq_recv():尝试从队列读取一个字节的数据。os_msgq_clear():清理队列状态,具体重置范围以实现为准。
obj 的具体用途、nonblock 的取值约定、失败返回值及等待机制,
均应以当前版本的头文件和源码为准。不要仅凭函数名称推断行为。
数据结构与缓冲区
环形缓冲区是 FIFO 队列常见的实现方式。读写位置沿缓冲区循环移动, 可以在固定存储空间内持续复用已有位置,避免每次读取后整体搬移数据。
缓冲区:[ A ][ B ][ C ][ ][ ]
↑读 ↑写
读取一个单元 → 读位置向前移动
写入一个单元 → 写位置向前移动
到达末尾 → 按环形规则回到起始位置
环形队列通常需要维护缓冲区地址、容量以及读写位置等状态。
上面的示意图用于解释基本原理,不代表 os_msgq_t 的真实字段布局。
- 缓冲区地址:指向实际存储数据的内存区域。
- 队列容量:决定最多能够暂存多少数据单元。
- 读写状态:用于确定下一次读取或写入的位置。
- 队列状态:实现可能通过计数或其他状态表示空队列与满队列。
发送流程
发送操作的核心是检查队列是否具备写入条件。 如果队列有可用空间,数据可以写入缓冲区;如果队列已满,则需要根据接口约定处理本次操作。
判断当前是否存在可用写入空间。
有空间则写入;无空间时按调用模式处理。
按实现更新队列状态,并向调用方返回结果。
发送请求
│
▼
判断是否有可用空间
├─ 有空间 → 写入数据 → 更新队列状态
└─ 无空间 → 按接口约定返回或处理等待
当消费者因队列暂时为空而等待时,生产者写入数据可能与消费者的后续运行产生关联。 实际唤醒条件和调度行为,应根据 HRTOS 当前的队列实现与内核等待机制确认。
接收流程
接收操作需要判断队列中是否存在可读取的数据。 队列非空时,读取一个数据单元并更新相关状态;队列为空时,则依据接口约定处理当前请求。
判断当前是否有数据可供读取。
存在数据时取出一个字节。
按实现更新队列状态,并报告操作结果。
接收请求
│
▼
判断是否存在可读取数据
├─ 有数据 → 读取数据 → 更新队列状态
└─ 无数据 → 按接口约定返回或处理等待
消费者取走数据后,队列可能重新具备写入条件。 如果有发送方正在等待队列空间,其后续处理取决于具体实现。
阻塞与非阻塞机制
阻塞与非阻塞描述的是操作暂时无法完成时的处理方式。 非阻塞调用通常不等待条件满足;阻塞调用则可能让当前任务等待,之后再由内核机制安排继续执行。
非阻塞调用
适用于调用方需要及时获得操作结果、不能在当前路径等待的场景。 调用方应检查返回值,并自行决定失败后的处理策略。
阻塞调用
适用于允许任务等待数据或空间的场景。 是否进入等待、如何恢复运行以及失败条件,均由接口与内核实现决定。
nonblock = 1 → 非阻塞调用(按现有接口说明) nonblock = 0 → 阻塞调用(按现有接口说明)
返回值与错误处理
发送和接收接口返回 char 类型的状态值。
应用程序应依据当前版本定义判断操作是否成功,不应假设每次调用都能完成数据传递。
1 成功 0 操作未成功或未完成 -1 等待失败
char 是否为有符号类型,以及 -1 是否是实际支持的返回值。
建议调用方为发送失败、接收暂不可用和等待失败分别设计处理策略, 并避免在错误发生时无条件重复调用,以免形成高频轮询或影响其他任务的执行。
设计特性与使用边界
- FIFO 数据组织:适用于需要按顺序处理数据的任务协作场景。
- 固定容量缓存:队列可暂存的数据量受缓冲区容量限制,应结合生产速率和消费速率设计。
- 任务解耦:生产者不必直接调用消费者的业务逻辑,双方可通过队列交换数据。
- 数据单位明确:当前接口以单个
u8为传递单位,复杂消息需要应用层协议。 - 并发访问约束:多个任务共同访问队列时,应遵守接口规定的同步与调用约束。
典型应用场景
生产者与消费者
采集任务负责产生数据,处理任务按顺序读取并完成后续业务。
驱动与应用解耦
将驱动侧获得的数据交给应用任务处理,降低执行流程之间的直接依赖。
后台数据处理
将待处理的字节数据暂存在队列中,由后台任务分批读取。
异步数据缓冲
在数据产生与处理速度不一致时提供有限缓冲,但不能替代容量规划。
队列容量设计应考虑数据突发量、消费者处理速度、允许的积压时间以及队列满时的业务策略。 如果生产速度长期高于消费速度,单纯增加缓冲区只能延缓队列耗尽,不能消除持续积压。
消息队列与其他 IPC 机制
不同 IPC 机制解决的问题并不相同。选择时应优先考虑应用需要传递的是数据、状态、同步信号,还是对共享资源的访问权。
- 消息队列:用于按队列规则缓存和传递数据。
- 邮箱(Mailbox):用于邮箱接口所定义的消息传递方式,具体容量和覆盖规则以实现为准。
- 事件(Event):用于表达事件或条件状态,适合任务根据事件进行协作。
- 信号量(Semaphore):通常用于同步或资源计数,具体语义由实现决定。
- 互斥量(Mutex):用于协调对共享资源的互斥访问,具体所有权与等待规则取决于实现。