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

实际项目中的环形缓冲区

在实际项目中,环形缓冲区的设计要比之前讲到的原型稍微复杂一些,需要一些接口函数来实现数据结构封装。GitHub上有个大帅哥写了一个轻量的环形缓冲区库,可以学习参考,也可以直接集成到自己的项目中,功能已经非常完善。

LwRB

特点

  • 使用C语言编写(C11),与size_t兼容的大小数据类型
  • 独立于平台,没有特定于体系结构的代码
  • 先进先出(FIFO)缓冲区实现
  • 无动态内存分配,数据为静态数组
  • 使用优化的内存复制而不是循环来读取/写入内存中的数据
  • 在作为单个写入和单个读取条目的管道时线程安全
  • 在作为单个写入和单个读取条目的管道时中断安全
  • 适用于在缓冲区和应用程序内存之间进行零拷贝的DMA传输
  • 支持数据的查看、读取跳过和写入前进
  • 实现事件通知的支持
  • 用户友好的MIT许可证

要求

  • C编译器
  • 少于1kB的非易失性存储器

示例代码

用于读取和写入缓冲区的简化示例代码:

/* 声明rb实例和原始数据 */
lwrb_t buff;
uint8_t buff_data[8];/* 应用程序变量 */
uint8_t data[2];
size_t len;/* 应用程序代码... */
lwrb_init(&buff, buff_data, sizeof(buff_data)); /* 初始化缓冲区 *//* 写入4个字节的数据 */
lwrb_write(&buff, "0123", 4);/* 尝试读取缓冲区 */
/* len保存读取的字节数 */
/* 当缓冲区为空时,读取直到len == 0 */
while ((len = lwrb_read(&buff, data, sizeof(data))) > 0) {printf("成功读取%d个字节\r\n", (int)len);
}

我们首先看下这个库的接口文件:

/*** \file            lwrb.h* \brief           LwRB - Lightweight ring buffer*//** Copyright (c) 2023 Tilen MAJERLE** Permission is hereby granted, free of charge, to any person* obtaining a copy of this software and associated documentation* files (the "Software"), to deal in the Software without restriction,* including without limitation the rights to use, copy, modify, merge,* publish, distribute, sublicense, and/or sell copies of the Software,* and to permit persons to whom the Software is furnished to do so,* subject to the following conditions:** The above copyright notice and this permission notice shall be* included in all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR* OTHER DEALINGS IN THE SOFTWARE.** This file is part of LwRB - Lightweight ring buffer library.** Author:          Tilen MAJERLE <tilen@majerle.eu>* Version:         v3.1.0*/
#ifndef LWRB_HDR_H
#define LWRB_HDR_H#include <stddef.h>
#include <stdint.h>
#include <string.h>#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus *//*** \defgroup        LWRB Lightweight ring buffer manager* \brief           Lightweight ring buffer manager* \{*/#if !defined(LWRB_DISABLE_ATOMIC) || __DOXYGEN__
#include <stdatomic.h>/*** \brief           Atomic type for size variable.* Default value is set to be `unsigned 32-bits` type*/
typedef atomic_ulong lwrb_sz_atomic_t;/*** \brief           Size variable for all library operations.* Default value is set to be `unsigned 32-bits` type*/
typedef unsigned long lwrb_sz_t;
#else
typedef unsigned long lwrb_sz_atomic_t;
typedef unsigned long lwrb_sz_t;
#endif/*** \brief           Event type for buffer operations*/
typedef enum {LWRB_EVT_READ,  /*!< Read event */LWRB_EVT_WRITE, /*!< Write event */LWRB_EVT_RESET, /*!< Reset event */
} lwrb_evt_type_t;/*** \brief           Buffer structure forward declaration*/
struct lwrb;/*** \brief           Event callback function type* \param[in]       buff: Buffer handle for event* \param[in]       evt: Event type* \param[in]       bp: Number of bytes written or read (when used), depends on event type*/
typedef void (*lwrb_evt_fn)(struct lwrb* buff, lwrb_evt_type_t evt, lwrb_sz_t bp);/* List of flags */
#define LWRB_FLAG_READ_ALL  ((uint16_t)0x0001)
#define LWRB_FLAG_WRITE_ALL ((uint16_t)0x0001)/*** \brief           Buffer structure*/
typedef struct lwrb {uint8_t* buff;  /*!< Pointer to buffer data. Buffer is considered initialized when `buff != NULL` and `size > 0` */lwrb_sz_t size; /*!< Size of buffer data. Size of actual buffer is `1` byte less than value holds */lwrb_sz_atomic_t r; /*!< Next read pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */lwrb_sz_atomic_t w; /*!< Next write pointer. Buffer is considered empty when `r == w` and full when `w == r - 1` */lwrb_evt_fn evt_fn; /*!< Pointer to event callback function */
} lwrb_t;uint8_t lwrb_init(lwrb_t* buff, void* buffdata, lwrb_sz_t size);
uint8_t lwrb_is_ready(lwrb_t* buff);
void lwrb_free(lwrb_t* buff);
void lwrb_reset(lwrb_t* buff);
void lwrb_set_evt_fn(lwrb_t* buff, lwrb_evt_fn fn);/* Read/Write functions */
lwrb_sz_t lwrb_write(lwrb_t* buff, const void* data, lwrb_sz_t btw);
lwrb_sz_t lwrb_read(lwrb_t* buff, void* data, lwrb_sz_t btr);
lwrb_sz_t lwrb_peek(const lwrb_t* buff, lwrb_sz_t skip_count, void* data, lwrb_sz_t btp);/* Extended read/write functions */
uint8_t lwrb_write_ex(lwrb_t* buff, const void* data, lwrb_sz_t btw, lwrb_sz_t* bw, uint16_t flags);
uint8_t lwrb_read_ex(lwrb_t* buff, void* data, lwrb_sz_t btr, lwrb_sz_t* br, uint16_t flags);/* Buffer size information */
lwrb_sz_t lwrb_get_free(const lwrb_t* buff);
lwrb_sz_t lwrb_get_full(const lwrb_t* buff);/* Read data block management */
void* lwrb_get_linear_block_read_address(const lwrb_t* buff);
lwrb_sz_t lwrb_get_linear_block_read_length(const lwrb_t* buff);
lwrb_sz_t lwrb_skip(lwrb_t* buff, lwrb_sz_t len);/* Write data block management */
void* lwrb_get_linear_block_write_address(const lwrb_t* buff);
lwrb_sz_t lwrb_get_linear_block_write_length(const lwrb_t* buff);
lwrb_sz_t lwrb_advance(lwrb_t* buff, lwrb_sz_t len);/* Search in buffer */
uint8_t lwrb_find(const lwrb_t* buff, const void* bts, lwrb_sz_t len, lwrb_sz_t start_offset, lwrb_sz_t* found_idx);
lwrb_sz_t lwrb_overwrite(lwrb_t* buff, const void* data, lwrb_sz_t btw);
lwrb_sz_t lwrb_move(lwrb_t* dest, lwrb_t* src);/*** \}*/#ifdef __cplusplus
}
#endif /* __cplusplus */#endif /* LWRB_HDR_H */

首先,代码包含了一些必要的头文件,并检查是否在C++环境中。如果是,就使用extern "C"来确保C++编译器以C语言的方式处理这个库。

然后,定义了一些类型和枚举。例如,lwrb_sz_tlwrb_sz_atomic_t用于表示缓冲区的大小,lwrb_evt_type_t是一个枚举,表示缓冲区操作的事件类型。

lwrb_t是主要的数据结构,表示一个环形缓冲区。它包含了指向缓冲区数据的指针、缓冲区的大小、读写指针以及一个事件回调函数。与之前介绍的最简化的环形缓冲区相比,这个结构中还包含了一个缓冲区大小和一个事件回调函数。事件回调函数用于在缓冲区操作时通知应用程序。

接下来是一系列的函数声明,这些函数用于操作环形缓冲区。例如,lwrb_init用于初始化一个环形缓冲区,lwrb_writelwrb_read用于向缓冲区写入数据和从缓冲区读取数据。

最后,代码检查是否在C++环境中。如果是,就结束extern "C"

事件

在应用程序中使用 LwRB 时,获取有关不同事件的通知可能会很有用,例如在向缓冲区写入或读取数据时获得通知。

该库支持在缓冲区数据发生修改时调用的事件,这意味着在每次读取或写入操作时都会触发事件。

一些用例:

  • 通知应用程序层 LwRB 操作已被执行并发送调试消息
  • 当应用程序使用操作系统时,当已写入/读取足够数量的字节到/从缓冲区时,解锁信号量
  • 在操作系统级别的消息队列中写入通知以唤醒另一个任务

注意: 每个修改 readwrite 内部指针的操作都被视为读取或写入操作。唯一的例外是 重置 事件,它将两个内部指针都设置为 0

#include <stdio.h>
#include "lwrb/lwrb.h"// Example callback function for LwRB events
void example_event_callback(lwrb_t* buffer, lwrb_event_t event, size_t length) {switch (event) {case LWRB_EVENT_READ:printf("Read event: %zu bytes read from buffer\n", length);break;case LWRB_EVENT_WRITE:printf("Write event: %zu bytes written to buffer\n", length);break;case LWRB_EVENT_RESET:printf("Reset event: Buffer has been reset\n");break;default:break;}
}int main() {// Initialize LwRB bufferlwrb_t buffer;uint8_t data[16];lwrb_init(&buffer, data, sizeof(data));// Set the event callback functionlwrb_set_event_callback(&buffer, example_event_callback);// Example operations on the bufferlwrb_write(&buffer, (uint8_t*)"Hello", 5);lwrb_read(&buffer, data, 3);lwrb_reset(&buffer);return 0;
}

上述代码演示了如何设置 LwRB 缓冲区的事件回调函数以获取关于读取、写入和重置操作的通知。在每次读取或写入时,将调用相应的事件回调函数。

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top

相关文章:

实际项目中的环形缓冲区

在实际项目中&#xff0c;环形缓冲区的设计要比之前讲到的原型稍微复杂一些&#xff0c;需要一些接口函数来实现数据结构封装。GitHub上有个大帅哥写了一个轻量的环形缓冲区库&#xff0c;可以学习参考&#xff0c;也可以直接集成到自己的项目中&#xff0c;功能已经非常完善。…...

输出回文数-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第23讲。 输出回文数&#…...

内存溢出会导致模块测试正常,植入系统失败

前些天&#xff0c;遇到了一个问题&#xff1a;需要在系统中添加一个小功能&#xff0c;单独测试&#xff0c;然后植入系统。 代码使用了从网上下载的函数&#xff0c;模块单独运行&#xff0c;没有问题&#xff0c;但是放在系统中运行就会出问题。 不得已的情况下&#xff0c…...

【taro react】 ---- QRCode 二维码生成

1. 需求分析 需要将输入的值转换为图片资源;由于只是单纯的展示,所以不需要很多比如加 logo 等复杂功能;不需要后端生成,直接前端操作;使用的第三方库尽可能小,功能单一;最后选择使用 qrcode-generator 库,只有 40kb。2. 使用第三方库 qrcode-generator 3. 转换 base…...

rk3566 armbian修复usb2.0并挂载U盘

文章目录 usb接口修复一 执行命令二 修改rk3566-panther-x2.dts⽂件三 查看是否识别 U盘格式化、挂载一 U盘格式化1.1 查看U盘1.2 查看U盘文件系统类型1.3 格式化为ext4系统 二 挂载U盘2.1 手动挂载2.2 自动挂载&#xff08;可选&#xff09; usb接口修复 一 执行命令 将位于…...

猫头虎博主第9期赠书活动:《YOLO目标检测》计算机AI视觉实战YOLO人工智能目标检测与跟踪图像处理深度学习图像检测书籍

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…...

python 如何将英语单词翻译成中文

要将英语单词翻译成中文&#xff0c;可以使用 Python 的第三方库 googletrans。该库使用 Google Translate 提供的 API 来进行翻译。 首先&#xff0c;需要安装 googletrans 库。可以使用以下命令在终端或命令提示符中安装&#xff1a; pip install googletrans4.0.0-rc1然后…...

Linux_CentOS_7.9_MySQL_5.7配置数据库服务开机自启动之简易记录

前言&#xff1a; 作为运维保障&#xff0c;都无法准确预估硬件宕机的突发阶段&#xff0c;其生产数据实时在产出&#xff0c;那作为dba数据库服务的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录&#xff0c;便于大家学习参考。 # 如出现服务器重启后登入报错无…...

js实现拖动盒子查看内容 内容拖动

一.分析实现过程 1.鼠标拖动的操作是&#xff0c;按下鼠标不松&#xff0c;拖动鼠标&#xff0c;就需要监听鼠标点击事件(onmousedown),鼠标拖动事件(onmousemove) 2.鼠标拖动事件的监听时机&#xff0c;是在按下鼠标之后监听的&#xff0c;所以鼠标拖动事件需要放在鼠标按下事…...

[C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测

【官方框架地址】 https://github.com/ViewFaceCore/ViewFaceCore 【算法介绍】 SeetaFace6是由中国科技公司自主研发的一款人脸识别技术&#xff0c;它基于深度学习算法&#xff0c;能够快速、准确地识别出人脸&#xff0c;并且支持多种应用场景&#xff0c;如门禁系统、移动…...

c++ execl 执行 重定向

#include <unistd.h>int main() {pid_t childPid fork(); // 创建子进程if (childPid 0) {// 子进程// 关闭标准输入、输出和错误流close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);// 打开要写入的文件int fd open("output.txt", O_WRONLY…...

uni-app中实现元素拖动

uni-app中实现元素拖动 1、代码示例 <template><movable-area class"music-layout"><movable-view class"img-layout" :x"x" :y"y" direction"all"><img :src"musicDetail.bgUrl" :class&…...

Java系列-Class.forName和ClassLoader.loadClass的区别

Class.forName 和 ClassLoader.loadClass 是 Java 中两种加载类的方式&#xff0c;它们的主要区别在于加载类的时机和对异常的处理。 1.Class.forName Class.forName 是一个静态方法&#xff0c;用于在运行时加载类。它返回一个 Class 对象&#xff0c;但在加载类的过程中&am…...

找不到模块 “path“ 或其相对应的类型声明

src别名的配置 在开发项目的时候文件与文件关系可能很复杂&#xff0c;因此我们需要给src文件夹配置一个别名 // vite.config.ts import {defineConfig} from vite import vue from vitejs/plugin-vue import path from path export default defineConfig({plugins: [vue()],r…...

Linux第17步_安装SSH服务

secure shell protocol简称SSH。 目的&#xff1a;在进行数据传输之前&#xff0c;SSH先对联级数据包通过加密技术进行加密处理&#xff0c;然后再进行数据传输&#xff0c;确保数据传输安全。 1、在安装前&#xff0c;要检查虚拟机可以上网&#xff0c;否则可能会导致安装失…...

C语言—数据类型

变量和基本数据类型 变量类型的概念 变量是在程序中可以发生变化的量&#xff0c;变量是有类型的&#xff0c;变量的类型决定了变量存储空间的大小以及如何解释存储的位模式。 1字节&#xff08;Byte&#xff09;8位&#xff08;bit&#xff09; 定义格式 存储类型 数据…...

静态网页设计——多彩贵州(HTML+CSS+JavaScript)(dw、sublime Text、webstorm、HBuilder X)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a;https://www.bilibili.com/video/BV1cK411v7R2/?vd_source5f425e0074a7f92921f53ab87712357b 源码&#xff1a;https://space.bilibili.com…...

unity PDFRender Curved UI3.3

【PDF】PDFRender 链接&#xff1a;https://pan.baidu.com/s/1wSlmfiWTAHZKqEESxuMH6Q 提取码&#xff1a;csdn 【曲面ui】 Curved UI3.3 链接&#xff1a;https://pan.baidu.com/s/1uNZySJTW0-pPwi2FTE6fgA 提取码&#xff1a;csdn...

基于深度学习的停车位关键点检测系统(代码+原理)

摘要&#xff1a; DMPR-PS是一种基于深度学习的停车位检测系统&#xff0c;旨在实时监测和识别停车场中的停车位。该系统利用图像处理和分析技术&#xff0c;通过摄像头获取停车场的实时图像&#xff0c;并自动检测停车位的位置和状态。本文详细介绍了DMPR-PS系统的算法原理、…...

C#,入门教程(09)——运算符的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(08)——基本数据类型及使用的基础知识https://blog.csdn.net/beijinghorn/article/details/123906998 一、算术运算符号 算术运算符号包括&#xff1a;四则运算 加 , 减-, 乘*, 除/与取模%。 // 加法&#xff0c;运算 int va 1 …...

企业出海数据合规:GDPR中的个人数据与非个人数据之区分

GDPR仅适用于个人数据&#xff0c;这意味着非个人数据不在其适用范围内。因此&#xff0c;个人数据的定义是一个至关重要的因素&#xff0c;因为它决定了处理数据的实体是否要遵守该法规对数据控制者规定的各种义务。尽管如此&#xff0c;什么是个人数据仍然是当前数据保护制度…...

如何在Ubuntu搭建Emlog博客站点并发布至公网可随时远程访问管理界面——“cpolar内网穿透”

文章目录 前言1. 网站搭建1.1 Emolog网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总结 前言 博客作为使…...

【金猿CIO展】是石科技CIO侯建业:算力产业赋能,促进数字经济建设

‍ 侯建业 本文由是石科技CIO侯建业撰写并投递参与“数据猿年度金猿策划活动——2023大数据产业年度优秀CIO榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 是石科技&#xff08;江苏&#xff09;有限公司成立于2021年&#xff0c;由国家超级计算无锡中心与…...

TypeScript 类

目录 1、实例 2、创建类的数据成员 3、创建实例化对象 4、完整实例 5、类的继承 6、继承类的方法重写 7、static关键字 8、instanceof运算符 9、访问控制修饰符 10、类和接口 TypeScript 是面向对象的 JavaScript。类描述了所创建的对象共同的属性和方法。支持面向对…...

Oracle分区表

文章目录 A. varchar2类型时间字段(20240102)分区实战1. 表要不要分区2. 将已经存在的表改造为分区表(时间字段&#xff0c;varchar2类型)3. 增加分区3.1 增加分区3.2 置换分区&#xff0c;不会复制索引&#xff0c;不要用这种语法建表&#xff0c;这是专门为置换分区用的3.3 分…...

【leetcode】力扣算法之旋转图像【难度中等】

题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 用例 输入&#xff1a; matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&…...

【Java集合类篇】HashMap的数据结构是怎样的?

HashMap的数据结构是怎样的? ✔️HashMap的数据结构✔️ 数组✔️ 链表 ✔️HashMap的数据结构 在Java中&#xff0c;保存数据有两种比较简单的数据结构: 数组和链表&#xff08;或红黑树&#xff09;。 HashMap是 Java 中常用的数据结构&#xff0c;它实现了 Map 接口。Has…...

Spring 应用合并之路(一):摸石头过河 | 京东云技术团队

公司在推进降本增效&#xff0c;在尝试多种手段之后&#xff0c;发现应用太多&#xff0c;每个应用都做跨机房容灾部署&#xff0c;则最少需要 4 台机器&#xff08;称为容器更合适&#xff09;。那么&#xff0c;将相近应用做一个合并&#xff0c;减少维护项目&#xff0c;提高…...

Android13配置selinux让system应用可读sys,proc,SN号

system权限应用读sys,proc目录及SN号 Android13预置的system应用&#xff0c;需要读/sys, /proc目录&#xff0c;读(SN)serial number号, 需要修改selinux配置&#xff0c;否则会报avc错&#xff0e; 其修改方法会比Android11复杂一些&#xff0e; 实现 system_app.te中添加…...

防勒索病毒攻击的关键措施

【作者】朱向东 中原银行 高级工程师 在当今数字化时代&#xff0c;勒索病毒成为了企业和个人面临的一项严峻威胁。勒索病毒攻击可以导致数据丢失、系统瘫痪以及经济损失。为了保护自己和组织的利益&#xff0c;采取一系列的防范措施是至关重要的。下面是一些关键的措施&#…...

凡科做的网站行不行/seo管理

一.多层路由 如果django里的app数量越来越多&#xff0c;那项目里的urls文件配置起来将会很麻烦&#xff0c;而且也不利于后续项目的改动和整理 所以看了杨老师的视频https://www.bilibili.com/video/av17267741后&#xff0c;记录一下关于多层路由的配置 url文件分为两类&…...

做全景效果图的网站/网络推广属于什么专业

题目连接&#xff1a;点击打开链接 网上啥啥都特别乱&#xff0c;自己看了点&#xff0c;直接自己写了个被称为原地逆序。 void ABBA(char a[]) { int left0,rightstrlen(a)-1; while(left<right) { swap(a[left],a[right]); left; r…...

复制网站模板/网络营销学什么内容

http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#1732 深入Java核心Java内存分配原理精讲 url&#xff1a;http://xwood.iteye.com/blog/762286 Java内存分配与管理是Java的核心技术之一&#xff0c;之前我们曾介绍过Java的内存管理与内存泄露以及…...

武汉网站建设武汉/百度搜索下载app

下面是小凰凰的简介&#xff0c;看下吧&#xff01; &#x1f497;人生态度&#xff1a;珍惜时间&#xff0c;渴望学习&#xff0c;热爱音乐&#xff0c;把握命运&#xff0c;享受生活 &#x1f497;学习技能&#xff1a;网络 -> 云计算运维 -> python全栈( 当前正在学习…...

建设网站费用评估/百度手机下载安装

GBDT&#xff08;MART&#xff09; 迭代决策树入门教程 | 简介 http://blog.csdn.net/w28971023/article/details/8240756转载于:https://www.cnblogs.com/zhangbojiangfeng/p/6127237.html...

网站开发工程师绩效/站长工具seo综合查询怎么使用的

linux开发感受最深的莫过于linux的动态库加载了&#xff0c;仅仅凭借这一点这支撑起了公司的灵活多变的业务。一个嵌入式Linux系统粗略的可以划分为系统层和应用层&#xff1b;应用层中基本都是10个以上的App来支撑起一个功能完备的嵌入式产品&#xff0c;这么多代码维护起来必…...