C 语言工业级通用组件手写 11:环形 FIFO 缓冲区
目录前言一、环形 FIFO 核心本质与应用场景1. 什么是环形缓冲区2. 解决的核心痛点3. 典型工业级落地场景二、核心实现原理1. 双指针循环机制2. 零拷贝读写3. 字节流式存储三、工业级设计规范1. 封装性设计2. 接口设计原则3. 鲁棒性要求4. 线程安全约束四、完整可复用源码1. 头文件 ring_fifo.h2. 实现文件 ring_fifo.c五、实战演示环形缓冲区读写示例六、工业级进阶优化方向1. 线程安全加锁封装2. 单次一字节读写接口3. peek 窥探接口4. 批量分段读写七、高频面试考点与易错坑点1. 经典面试问答2. 常见易错坑点总结前言在嵌入式串口接收、网络报文缓冲、音频数据流、传感器高频采集、异步数据收发场景中普通数组缓存存在溢出、覆盖、数据丢失、读写冲突等致命问题。普通数组无脑缓存必须手动判空、判满、移动数据代码臃肿、极易出错、无法高频运行。环形 FIFO循环缓冲区是工业流式数据缓存的标准解决方案。 本篇手写一套极简、零拷贝、全覆盖、读写分离、防溢出、可线程安全的工业级环形缓冲区源码干净、无冗余、可直接投产适配所有流式数据收发场景。一、环形 FIFO 核心本质与应用场景1. 什么是环形缓冲区环形 FIFO 是首尾相连的循环队列。依靠读指针(r)、写指针(w)实现循环读写无需数据搬迁、零拷贝、性能极致。核心特性先进先出、循环复用内存、无数据挪动、无内存碎片、读写高效。2. 解决的核心痛点解决数组缓存溢出覆盖满状态自动拦截写入杜绝数据丢失。解决数据搬迁耗时普通队列出队需要整体前移FIFO 零搬迁。解决高频数据流卡顿O (1) 读写百万级吞吐无压力。解决收发速率不匹配缓存削峰适配突发数据、高频采样。解决代码冗余混乱统一标准接口全局通用缓存组件。3. 典型工业级落地场景串口 / 485/CAN 接收缓存中断高速接收、主线程慢速解析。网络数据流缓冲TCP 流式分包、UDP 报文缓存。音视频采集音频帧、视频帧连续流式缓存。传感器高频采集高速 AD、姿态、雷达数据缓存。异步解耦架构生产快、消费慢场景削峰缓冲。二、核心实现原理1. 双指针循环机制write_ptr数据写入位置read_ptr数据读取位置缓冲区满(write 1) % size read缓冲区空write read预留一个空位区分空 / 满状态是工业最简、零 BUG 标准方案。2. 零拷贝读写读写直接操作数组指针不拷贝、不移动、不遍历性能拉满。3. 字节流式存储按字节缓存适配任意协议、任意报文、任意长度数据通用性最强。三、工业级设计规范1. 封装性设计FIFO 结构体完全封装缓存地址、读写指针、缓冲区大小。外部不可篡改内部状态保证读写闭环安全。2. 接口设计原则接口函数功能说明fifo_init初始化环形缓冲区fifo_write写入指定长度数据fifo_read读取指定长度数据fifo_available获取剩余可写空间fifo_used获取当前已缓存数据长度fifo_clear清空缓冲区3. 鲁棒性要求空指针校验、长度合法性校验。写满自动拒绝、读空自动返回。无越界、无覆盖、无数据错乱。纯 C 零依赖、裸机 / RTOS/Linux 全平台适配。4. 线程安全约束单生产单消费天然线程安全嵌入式中断写、主线程读标配。多生产多消费需外层加锁适配高并发场景。四、完整可复用源码1. 头文件 ring_fifo.h#ifndef RING_FIFO_H #define RING_FIFO_H #include stdint.h #include stddef.h #ifdef __cplusplus extern C { #endif /* 环形FIFO句柄 */ typedef struct { uint8_t *buf; size_t buf_size; size_t w_ptr; size_t r_ptr; } ring_fifo_t; /** * brief 初始化环形缓冲区 * param fifo FIFO句柄 * param buf 缓存数组地址 * param buf_size 缓存数组大小 */ void fifo_init(ring_fifo_t *fifo, uint8_t *buf, size_t buf_size); /** * brief 写入数据到FIFO * param fifo FIFO句柄 * param data 待写入数据 * param len 写入长度 * return 实际写入字节数 */ size_t fifo_write(ring_fifo_t *fifo, const uint8_t *data, size_t len); /** * brief 从FIFO读取数据 * param fifo FIFO句柄 * param data 接收缓存 * param len 读取长度 * return 实际读取字节数 */ size_t fifo_read(ring_fifo_t *fifo, uint8_t *data, size_t len); /** * brief 获取缓冲区剩余可写空间 */ size_t fifo_available(ring_fifo_t *fifo); /** * brief 获取缓冲区已存储数据长度 */ size_t fifo_used(ring_fifo_t *fifo); /** * brief 清空缓冲区 */ void fifo_clear(ring_fifo_t *fifo); #ifdef __cplusplus } #endif #endif2. 实现文件 ring_fifo.c#include ring_fifo.h #include string.h void fifo_init(ring_fifo_t *fifo, uint8_t *buf, size_t buf_size) { if (fifo NULL || buf NULL || buf_size 0) { return; } fifo-buf buf; fifo-buf_size buf_size; fifo-w_ptr 0; fifo-r_ptr 0; } size_t fifo_write(ring_fifo_t *fifo, const uint8_t *data, size_t len) { if (fifo NULL || data NULL || len 0) { return 0; } size_t avail fifo_available(fifo); if (avail 0) { return 0; } // 限制最大写入长度 len len avail ? avail : len; size_t size1 fifo-buf_size - fifo-w_ptr; if (size1 len) { memcpy(fifo-buf[fifo-w_ptr], data, len); } else { memcpy(fifo-buf[fifo-w_ptr], data, size1); memcpy(fifo-buf, data size1, len - size1); } fifo-w_ptr (fifo-w_ptr len) % fifo-buf_size; return len; } size_t fifo_read(ring_fifo_t *fifo, uint8_t *data, size_t len) { if (fifo NULL || data NULL || len 0) { return 0; } size_t used fifo_used(fifo); if (used 0) { return 0; } len len used ? used : len; size_t size1 fifo-buf_size - fifo-r_ptr; if (size1 len) { memcpy(data, fifo-buf[fifo-r_ptr], len); } else { memcpy(data, fifo-buf[fifo-r_ptr], size1); memcpy(data size1, fifo-buf, len - size1); } fifo-r_ptr (fifo-r_ptr len) % fifo-buf_size; return len; } size_t fifo_available(ring_fifo_t *fifo) { if (fifo NULL) { return 0; } // 预留1字节区分空满 return (fifo-buf_size - 1 fifo-r_ptr - fifo-w_ptr) % fifo-buf_size; } size_t fifo_used(ring_fifo_t *fifo) { if (fifo NULL) { return 0; } return (fifo-w_ptr fifo-buf_size - fifo-r_ptr) % fifo-buf_size; } void fifo_clear(ring_fifo_t *fifo) { if (fifo NULL) { return; } fifo-w_ptr 0; fifo-r_ptr 0; }五、实战演示环形缓冲区读写示例#include stdio.h #include ring_fifo.h #define FIFO_BUF_LEN 32 uint8_t fifo_buf[FIFO_BUF_LEN]; int main(void) { ring_fifo_t fifo; fifo_init(fifo, fifo_buf, FIFO_BUF_LEN); uint8_t w_data[] INDUSTRIAL_FIFO_11; uint8_t r_data[32] {0}; // 写入数据 size_t w_len fifo_write(fifo, w_data, sizeof(w_data)); printf(成功写入 %zu 字节\n, w_len); printf(当前已缓存%zu 字节\n, fifo_used(fifo)); // 读取数据 size_t r_len fifo_read(fifo, r_data, sizeof(r_data)); printf(成功读取 %zu 字节\n, r_len); printf(读取内容%s\n, r_data); return 0; }运行效果循环读写正常、边界无越界、缓冲区满自动截断、空读取直接返回零丢失、零错乱、零崩溃。六、工业级进阶优化方向1. 线程安全加锁封装搭配互斥锁支持多线程并发读写。2. 单次一字节读写接口适配串口中断单字节写入场景。3. peek 窥探接口只读不弹出适配协议头解析、预判断报文。4. 批量分段读写适配超大数据流高速吞吐。七、高频面试考点与易错坑点1. 经典面试问答Q1环形 FIFO 为什么要预留一个空位答解决空满状态歧义。读写指针相等既可以是空也可以是满预留一位可以完美区分是工业最简无 BUG 方案。Q2环形缓冲区相比普通数组的优势答无需数据搬迁、无溢出覆盖、循环复用内存、性能稳定、适配异步收发。Q3单中断写主线程读是否需要加锁答不需要。单生产单消费模式指针互不抢占天然线程安全是串口驱动标准写法。Q4FIFO 核心设计思想答以空间换时间、循环复用内存、解耦生产消费速率、零拷贝高效流转。2. 常见易错坑点不预留空位空满判断错乱读写指针不取模数组越界读取不判空、写入不判满导致数据异常频繁数据 memmove 挪动性能极差边界包裹读写处理错误尾部数据丢失总结环形 FIFO 缓冲区是嵌入式流式数据处理的第一组件。所有串口、网络、音频、采集工程100% 依赖环形缓存。本篇实现工业标准、边界全覆盖、零 BUG、可直接投产补齐整套组件库数据流转核心能力。创作不易如果对你有帮助欢迎点赞、收藏、转发。

相关新闻

变频器的技术应用:接线与基本参数设置

变频器的技术应用:接线与基本参数设置

部分参考自《变频器与步进/伺服驱动技术完全精通教程》 化学工业出版社 图源:部分引自《台达 VFD-M变频器 使用手册》,其余引自互联网。 学习笔记,记录一下新变频器到手后,需要进行的配置工作。 说起来,变频器属于传动…

2026/7/21 15:49:37阅读更多 →
Data-Science-EBooks:数据科学学习者的终极免费资源宝库

Data-Science-EBooks:数据科学学习者的终极免费资源宝库

Data-Science-EBooks:数据科学学习者的终极免费资源宝库 【免费下载链接】Data-Science-EBooks Data Science E-books, Interview Resources and Cheat-sheets 项目地址: https://gitcode.com/gh_mirrors/da/Data-Science-EBooks 你是否正在寻找高质量的数据…

2026/7/21 15:47:34阅读更多 →
smsBomb配置完全指南:从配置文件到API密钥的详细设置

smsBomb配置完全指南:从配置文件到API密钥的详细设置

smsBomb配置完全指南:从配置文件到API密钥的详细设置 【免费下载链接】smsBomb 短信💣炸🐔 项目地址: https://gitcode.com/gh_mirrors/sms/smsBomb 想要掌握smsBomb短信轰炸工具的核心使用方法吗?😊 这篇完整的…

2026/7/21 15:47:34阅读更多 →
本地语音助手搭建:Whisper.cpp+Llama.cpp+ElevenLabs实战链路

本地语音助手搭建:Whisper.cpp+Llama.cpp+ElevenLabs实战链路

1. 项目概述:在本地跑出接近GPT-4o语音交互体验的完整链路 “Whisper.cpp Llama.cpp ElevenLabs: Local GPT-4o-like Voice Heaven”这个标题乍看像一串技术堆砌,但背后是一条被很多人忽略却极具实操价值的路径—— 用纯本地轻量模型完成语音输入、本…

2026/7/21 21:05:21阅读更多 →
Windows Qt开发必备:Heob内存泄漏检测工具原理与实战指南

Windows Qt开发必备:Heob内存泄漏检测工具原理与实战指南

1. 项目概述:为什么我们需要Heob这样的内存分析工具?如果你是一名C/Qt开发者,尤其是在Windows平台上,那么“内存泄漏”这个词对你来说一定不陌生。它就像一个幽灵,平时运行得好好的程序,可能在连续运行几天…

2026/7/21 21:05:21阅读更多 →
GR00T N1.7社区贡献指南:如何参与开源机器人基础模型开发

GR00T N1.7社区贡献指南:如何参与开源机器人基础模型开发

GR00T N1.7社区贡献指南:如何参与开源机器人基础模型开发 【免费下载链接】gr00t17-lerobot-libero_spatial-640 项目地址: https://ai.gitcode.com/hf_mirrors/nvidia/gr00t17-lerobot-libero_spatial-640 欢迎来到GR00T N1.7开源机器人基础模型的世界&…

2026/7/21 21:05:21阅读更多 →
咨询转产品:结构化思维如何迁移为产品决策力

咨询转产品:结构化思维如何迁移为产品决策力

1. 这不是转行,是能力迁移的精密校准“从咨询转产品”这个标题在职业社区里每年被搜索上万次,但绝大多数人点开后看到的是一堆模糊的鸡汤:“多学点Axure”“去实习三个月”“考个PMP证书”。我干了八年管理咨询,前五年在麦肯锡做战…

2026/7/21 21:05:21阅读更多 →
Databricks免费版+AWS S3+MLflow开源版端到端MLOps实践

Databricks免费版+AWS S3+MLflow开源版端到端MLOps实践

1. 项目概述:为什么说“免费用 Databricks S3 MLflow”不是标题党你刚看到这个标题时,大概率会下意识皱眉——Databricks 明明是按计算时长和 DBU(Databricks Unit)计费的,AWS S3 虽然便宜但绝非零成本,M…

2026/7/21 21:05:21阅读更多 →
别再手动调试Chain了!:用可观测性工具链5分钟定位AI工作流97%的耗时黑洞

别再手动调试Chain了!:用可观测性工具链5分钟定位AI工作流97%的耗时黑洞

更多请点击: https://kaifayun.com 第一章:别再手动调试Chain了!:用可观测性工具链5分钟定位AI工作流97%的耗时黑洞 在构建 LLM 应用时,一个典型的 Chain(如 LangChain 或 LlamaIndex 中的调用链&#xf…

2026/7/21 21:03:21阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 0:51:49阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 0:51:49阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 0:51:49阅读更多 →
Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

📌教程适配:OpenClaw v2.7.9 | 兼容 Windows10/11、macOS 双系统 📖前言 当下各类本地 AI 工具层出不穷,多数产品仅能完成文字问答交互,很难直接操控电脑执行实际操作。OpenClaw,业内常称小龙虾 AI&#…

2026/7/21 0:01:46阅读更多 →
Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

聊《一次Codex项目复盘,问题最后出在流程而不是模型》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要先把这篇文章的目标说清楚:看完之后,你应该能判断这件事值不值得做&…

2026/7/21 0:01:46阅读更多 →
手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

大家好,还是我。前几期带大家做了心情日记本和可视化大屏,后台有朋友留言:“能不能教点好玩的?我想做游戏,但一行代码都不会。”行,这期就安排。今天的目标:从零做一个五子棋游戏。 带AI对战、三…

2026/7/21 0:03:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/20 22:51:39阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/21 18:53:30阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/21 18:53:30阅读更多 →