当前位置: 首页 > news >正文

柔性数组与队列杂记

柔性数组

柔性数组是 C 语言(C99 标准及之后)中的一个特性,指结构体的最后一个成员是一个未知大小的数组,用于在结构体中动态分配连续的内存空间,以高效存储变长数据。

它有三个关键点:①结构体最后一个成员是大小未知的数组;

②结构体内必须包含其他成员;

③柔性数组不占结构体用空间本身的内存;

④实际使用时需要动态分配内存。

队列

在嵌入式开发中,队列(Queue) 是一种核心的数据结构,遵循 “先进先出(FIFO,First-In-First-Out)” 原则,主要用于解决任务间通信、数据缓冲、时序解耦等关键问题。由于嵌入式系统通常存在多任务(如 RTOS 环境)、资源受限、实时性要求高的特点,队列的作用尤为突出,具体可从以下 6 个核心场景展开:

1. 多任务 / 中断间的安全通信

嵌入式系统(尤其是带 RTOS 的系统,如 FreeRTOS、RT-Thread)中,任务与任务、任务与中断服务函数(ISR) 之间无法直接传递数据(易导致数据竞争、内存溢出),而队列是实现 “线程安全通信” 的标准方案。

  • 任务间通信:例如 “传感器采集任务” 采集到温湿度数据后,无需直接调用 “数据处理任务”,只需将数据放入队列,处理任务从队列中读取数据即可。这种方式避免了任务间的直接耦合,符合 RTOS 的 “任务解耦” 设计原则。

  • 中断与任务通信:中断服务函数(ISR)的执行时间必须极短(避免阻塞其他中断),因此 ISR 不能直接处理复杂数据(如解析串口数据、处理传感器协议)。此时 ISR 可将 “待处理数据” 快速放入队列,再由后台任务从队列中取出并处理(RTOS 通常提供xQueueSendFromISR等专用接口,确保中断上下文的安全性)。

示例:串口接收中断收到 1 字节数据后,立即将数据放入 “串口接收队列”,后台 “串口数据解析任务” 循环从队列中读取数据,拼接成完整的协议帧后再处理。

2. 数据缓冲与流量削峰

嵌入式系统中,数据产生速度与处理速度往往不匹配(如高速传感器、串口 / USB 等外设的数据流),若直接传递数据会导致 “数据丢失” 或 “处理任务过载”,队列可作为 “缓冲池” 平衡两者速度差。

  • 外设数据缓冲:例如 SPI 接口的加速度传感器每秒产生 1000 组数据(每组 4 字节),而 MCU 的 “数据存储任务” 因需写入 Flash,每秒仅能处理 200 组数据。此时用队列缓存传感器数据,可避免数据因处理不及时而丢失(队列深度需根据速度差设计,如设为 800,防止缓冲溢出)。

  • 突发流量处理:当外设(如以太网、CAN 总线)突发发送大量数据时,队列可临时 “囤积” 数据,让处理任务按自身节奏逐步处理,避免系统因瞬时高负载而崩溃(即 “削峰” 作用)。

3. 任务同步与时序解耦

嵌入式系统中,多个任务的执行时序可能存在依赖(如 “初始化任务” 完成后,“业务任务” 才能启动),或需避免 “快任务等待慢任务” 的低效场景,队列可实现灵活的任务同步。

  • 信号同步:队列可传递 “空数据”(仅作为同步信号),例如 “按键扫描任务” 检测到按键按下后,向队列发送一个 “触发信号”,“LED 控制任务” 从队列读取到信号后,执行 LED 闪烁操作(无需传递具体数据,仅需同步事件)。

  • 时序解耦:例如 “ADC 采样任务” 需每 10ms 采样一次,而 “数据上传任务” 需每 1 秒上传一次采样结果。若两者直接耦合,采样任务需等待上传任务完成,会破坏 10ms 的采样周期;用队列缓存每次采样结果,上传任务每秒从队列中读取 100 个数据批量上传,可完全解耦两者的时序。

4. 资源共享与冲突避免

嵌入式系统中的共享资源(如串口、Flash、LCD)若被多个任务同时访问,会导致 “资源竞争”(如串口数据错乱、Flash 写入错误)。队列可作为 “资源请求队列”,实现资源的有序分配。

示例:系统中有 “日志打印任务”“参数上传任务” 两个任务需使用串口。设计一个 “串口请求队列”,两个任务需使用串口时,将 “数据 + 操作类型” 放入队列;再创建一个 “串口管理任务”,独占串口资源,循环从队列中读取请求,按顺序处理(先处理日志打印,再处理参数上传),彻底避免资源冲突。

5. 中断服务函数的轻量化处理

中断服务函数(ISR)的核心要求是 “快进快出”,若在 ISR 中执行复杂逻辑(如数据解析、CRC 校验),会延长中断响应时间,甚至阻塞更高优先级的中断。队列可将 “复杂处理” 转移到后台任务。

示例:CAN 总线中断收到一帧数据后,ISR 仅需完成 “数据拷贝”(将 CAN 数据寄存器的值存入缓冲区),再将 “缓冲区地址” 放入队列,随后立即退出;后台 “CAN 数据解析任务” 从队列中取出地址,执行 CRC 校验、协议解析、业务逻辑处理等耗时操作,既保证了 ISR 的轻量化,又不影响数据处理的完整性。

6. 实时性保障与优先级支持

主流 RTOS(如 FreeRTOS、RTX)的队列均支持优先级继承优先级排序,可保障高优先级任务的实时性需求。

  • 优先级读取:当多个任务同时从一个队列读取数据时,RTOS 会优先调度 “高优先级任务”。例如 “紧急故障处理任务”(高优先级)和 “普通数据处理任务”(低优先级)都监听同一个队列,当队列中收到 “故障数据” 时,高优先级的故障任务会优先读取数据并处理,满足实时性要求。

  • 优先级发送:部分 RTOS 的队列支持 “按优先级插入数据”(如 FreeRTOS 的xQueueSendToFront),例如 “紧急报警数据” 可插入队列头部,优先被处理,而 “普通状态数据” 插入队列尾部,确保紧急事件的响应速度。

嵌入式队列的关键特性(与通用队列的区别)

由于嵌入式系统的资源受限性,嵌入式场景中的队列通常具备以下适配特性:

  1. 固定大小:队列创建时需指定 “队列深度”(最大数据个数)和 “每个数据的大小”,避免动态内存分配(减少内存碎片)。

  2. 阻塞机制:任务从空队列读取数据时,可设置 “阻塞时间”(如等待 100ms),期间任务进入阻塞态,不占用 CPU 资源;队列有数据后,任务自动唤醒,提升系统效率。

  3. 中断安全:提供 ISR 专用接口(如 FreeRTOS 的xQueueSendFromISR、RT-Thread 的rt_queue_send_from_isr),确保在中断上下文操作队列时不会破坏数据结构。

总结

队列是嵌入式开发中的 “通信与缓冲核心”,其本质是通过FIFO 规则实现 “数据 / 事件的有序传递”,解决了多任务 / 中断间的通信、数据缓冲、时序解耦、资源冲突等核心痛点。在 RTOS 驱动开发、外设管理、业务逻辑设计中,队列几乎是不可或缺的工具,直接影响嵌入式系统的稳定性、实时性和可维护性。

代码实例:

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <windows.h> typedef int qDataType;typedef struct queueNode {int data;struct queueNode *next;
}qNode;typedef struct {qNode *head;qNode *tail;int size;
}queue;void queueInit(queue *q)
{q->head = NULL;q->tail = NULL;q->size = 0;
}bool queueEmpty(queue *q)
{if (q->size == 0){return true;}else {return false;}
}void queueDestroy(queue *q)
{while (q->size != 0){qNode* tmp = q->head;q->head->next = q->head;free(tmp);q->size--;}
}int getQueueSize(queue *q)
{assert(q);return q->size;
}qDataType getQueueHead(queue *q)
{assert(q);assert(!queueEmpty(q));return q->head->data;
}qDataType getQueueTail(queue *q)
{assert(q);assert(!queueEmpty(q));return q->tail->data;
}void queuePush(queue *q, qDataType iData)
{assert(q);qNode* newNode = (qNode*)malloc(sizeof(qNode));if (newNode==NULL){printf("malloc failed\n");return;}else {newNode->data = iData;newNode->next = NULL;if (queueEmpty(q)){q->head = newNode;q->tail = newNode;}else {q->tail->next = newNode;q->tail = q->tail->next;}q->size++;}
}void queuePop(queue *q)
{assert(q);assert(!queueEmpty(q));if (q->size=1&&(q->head)==(q->tail)){qNode* tmp = q->head;q->head = NULL;q->tail = NULL;free(tmp);}else {qNode* tmp = q->head;q->head = q->head->next;free(tmp);}q->size--;
}
void qPrintFromHead(queue *q)
{if (q == NULL || q->head == NULL) {printf("队列是空的,无数据可输出\n");return;}qNode* current = q->head;  printf("队列从头至尾的输出:");while (current != NULL) {printf("%d ", current->data);  current = current->next;      }printf("\n");  
}int main()
{queue* qPTR = (queue*)malloc(sizeof(queue));queueInit(qPTR);for (int i = 0; i < 5; i++) {queuePush(qPTR, i);}qPrintFromHead(qPTR);Sleep(1000);queuePop(qPTR);qPrintFromHead(qPTR);return 0;
}


文章转载自:

http://5TcSD3f4.mszLs.cn
http://CXoGF4Ag.mszLs.cn
http://mwcAYxjJ.mszLs.cn
http://1NAcKo4B.mszLs.cn
http://ldFUKfyP.mszLs.cn
http://hqGjriW7.mszLs.cn
http://HsKqgQYW.mszLs.cn
http://iIW7aiIC.mszLs.cn
http://AesmDquR.mszLs.cn
http://un4OShGj.mszLs.cn
http://3hoIUDA2.mszLs.cn
http://xnAJanzc.mszLs.cn
http://KFDWDMdq.mszLs.cn
http://9KlKnZnQ.mszLs.cn
http://mAgSJwWk.mszLs.cn
http://9q55vSAv.mszLs.cn
http://Qyk132NN.mszLs.cn
http://kuLUJzQU.mszLs.cn
http://n7H7CtGG.mszLs.cn
http://SjQsGWZa.mszLs.cn
http://2Ir5IgC1.mszLs.cn
http://3nDhNZvR.mszLs.cn
http://mx2K96Ew.mszLs.cn
http://OhOZwiGd.mszLs.cn
http://AOz4n0U6.mszLs.cn
http://8XhTtpzD.mszLs.cn
http://ZXBQJxYX.mszLs.cn
http://nwdtsp7V.mszLs.cn
http://muY8rgbK.mszLs.cn
http://RJ5xJ5ht.mszLs.cn
http://www.dtcms.com/a/377735.html

相关文章:

  • XCVP1902-2MSEVSVA6865 AMD 赛灵思 XilinxVersal Premium FPGA
  • iPaaS与ESB:企业集成方案的选择与实践!
  • [硬件电路-177]:如何用交流电流源(偏置电流+交变电流)模拟PD的暗电流 + 变化的光电流
  • O3.1 opencv高阶
  • 【JAVA】java的程序逻辑控制
  • 真正有效的数据指标体系应该长什么样?
  • MATLAB中的霍夫变换直线检测
  • Thread类的基本用法(上)
  • 数据建模的真相!为什么90%的团队都在做无用功
  • 30 分钟让 AI 开口查订单:React-Native + Coze 全链路语音对话落地指南
  • Nacos报错NacosException: Client not connected, current status:STARTING
  • 基于SpringBoot+Vue2开发的母婴育婴师平台
  • GNU 工具链与ARM 交叉编译工具链
  • 【大模型应用开发 6.LlamaIndex-Workflow】
  • 【蓝桥杯 2024 国 Java A】粉刷匠小蓝
  • Android 编译系统lunch配置总结
  • 2024-2025-2Linux课堂笔记及作业(不完整版)
  • ELF文件的组成格式的详细介绍
  • vue中通过heatmap.js实现热力图(多个热力点)热区展示(带鼠标移入弹窗)
  • Java基础 9.10
  • 绿色算力技术栈:AI集群功耗建模与动态调频系统
  • 从零搭建网站(第五天)
  • MySQL 8.4.6 安装
  • 前端架构知识体系:Web Worker 使用与优化指南
  • 嵌入式 - ARM4
  • Linux 的权限详解
  • 研究生开题答辩全攻略!老学姐教你轻松过关,再也不用担心被老师刁难!
  • Angr符号执行初步学习
  • Shell编程之正则表达式与文本处理工具
  • 软考系统架构设计师之UML统一建模语言