• 正文
  • 相关推荐
申请入驻 产业图谱

简易嵌入式优先级消息队列设计思路!

4小时前
167
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

消息队列是解决任务间通信的经典方案,其核心作用如:

任务解耦 - 让采集、处理、发送模块独立演进

异步通信 - 释放CPU等待时间,提升利用率

流量削峰 - 蓄水池机制应对突发数据

优先级调度 - 让紧急消息插队

数据完整性 - 避免竞态条件导致的脏数据

消息队列的类型大概有如下几种:

    FIFO队列。先进先出队列,典型场景如:日志记录、普通数据流。优先级队列。典型场景如:告警系统、控制指令。环形缓冲区。典型场景如:音视频流、波形采集。邮箱(Mailbox)。典型场景如:简单通知。

本篇文章我们来梳理一个基于FreeRTOS,支持优先级、超时控制、零内存碎片的简易消息队列的实现思路。

1. 静态内存池

MCU上,每次malloc/free都可能产生外部碎片。假设你的队列里轮流存放16B和64B的消息,运行一段时间后,堆内存会变成"千疮百孔"的状态。内存碎片化,虽然总空闲内存足够,但无法分配连续的大块。

使用静态内存池,消灭碎片化隐患。

静态内存池方案

核心思路:启动时一次性分配所有内存,运行时只做节点复用

池大小根据业务峰值评估,宁可多分配10%也不要刚好卡边界;MSG_DATA_SIZE设为最大消息体的字节数,避免截断;某些场景下可以用环形数组代替链表,减少指针操作。

2. 互斥锁+信号量

嵌入式RTOS(如FreeRTOS)下,队列操作涉及三种同步原语,构建线程安全屏障。

互斥锁(Mutex):保护队列结构的head/tail指针,防止并发修改

not_full信号量:队列满时阻塞生产者

not_empty信号量:队列空时阻塞消费者

生产者-消费者的信号量协作流程:

实现片段

注意:

    • 互斥锁不能信号量等待之前,导致生产者拿着锁等待,消费者无法释放空位 → 死锁信号量的初始值很关键:

not_full初始值应为MSG_POOL_SIZEnot_empty初始值为0

3. 固定大小消息

可变vs固定:

方案 优点 缺点 适用场景
可变大小 节省内存 需要额外的长度字段,复制开销不确定 消息体差异大(如1B和1KB混用)
固定大小 实现简单,时间复杂度O(1) 浪费部分内存 消息体大小相近(嵌入式典型场景)

固定大小消息格式设计

注意:消息头部放类型和优先级,方便路由和调度如果28B不够用,考虑引入

消息片段化:大消息拆成多个定长分片

4. 优先级插入

为什么需要优先级?让紧急消息插队。比如:传感器每100ms发送常规数据,突然检测到异常需要立即告警。如果用FIFO队列,告警消息可能排在100条常规消息之后,消息会延迟到达。

实现:有序链表插入

5. 超时机制

超时机制防止系统挂起,不能因为队列一直为空,消费者永久阻塞。

超时返回错误码

经验值:高频任务(如100ms周期):超时设为500ms低频任务(如秒级):超时设为5000ms关键任务需要配合看门狗,超时后及时喂狗

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

本公众号专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,公众号内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!