FreeRTOS三种数据结构区别(StreamBuffer,MessageBuffer,Queue)

2023-05-16

转载自博客:https://blog.zh123.top/?p=308
Queue队列是最基本的数据结构,在FreeRTOS v10.0后提供了另外两种高级数据结构为Streambuffer和MessageBuffer,称为流式缓冲区和消息缓冲区。了解它们的区别能够更好的在工作中选用合适的结构类型。本文通过引用官方文档和论坛中权威的回帖展示三者的区别,不做具体的使用介绍。

1 Queue队列

队列是任务间通信的最基础形式,也是最灵活的方式。操作系统中队列是以项(item)为基本单元。

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,
                             UBaseType_t uxItemSize );
BaseType_t xQueueSend( QueueHandle_t xQueue,
                        const void * pvItemToQueue,
                        TickType_t xTicksToWait );
BaseType_t xQueueReceive( QueueHandle_t xQueue,
                           void *pvBuffer,
                            TickType_t xTicksToWait );

从其创建函数中传参可以看出,对列需要一个固定的长度,并且每个项的大小也是固定的。从发送和接收函数中可以看出,其默认传递的方式为拷贝,将指针指向的内容拷贝到自己的内存中。所以发送完成后可以修改原来的数据存储区,同样接收完成后,数据会从队列存储区中删除。当然,可以通过传递指针的指针解决大数据量拷贝慢的问题,同样也会存在其它问题(例如接收任务接收到数据之前,该区域内容不得更改等),这里不再详述。

2 StreamBuffer流缓冲区

流式缓冲区是在队列的基础上,针对单一生产者和消费者场景,优化的一种更适合的数据结构。 流缓冲区允许将字节流从中断服务例程传递到任务,或从一个任务传递到另一个任务。字节流可以是任意长度,并且不一定具有开头或结尾。可以一次写入任意数量的字节,并且可以一次读取任意数量的字节。数据通过复制传递 – 数据由发送方复制到缓冲区中,并通过读取从缓冲区中复制出来。

StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes,
                                          size_t xTriggerLevelBytes );
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
                           const void *pvTxData,
                           size_t xDataLengthBytes,
                             TickType_t xTicksToWait );
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
                              void *pvRxData,
                              size_t xBufferLengthBytes,
                              TickType_t xTicksToWait );

上面简单列举了创建,发送和接收的函数,不难看出,流缓冲区可以任意长度读写数据,并且支持阻塞式访问。同时提供了一种辅助的触发方式(可以设定在多少字节时触发)。相比较队列而言在串口等数据调试和传输环境中具有更佳的可用性。

与大多数其他FreeRTOS API不同的是,流缓冲器针对单个读取器单写入器场景进行了优化,例如将数据从中断服务例程传递到任务,或者从双核CPU上的一个微控制器核心传递到另一个。在多任务读写的环境中,需要将该函数相关的调用置于关键区域内(taskENTER_CRITICAL和taskEXIT_CRITICAL),也可以使用互斥信号量来解决。我感觉关键区域的方式是最简单的。

NOTICE:
这里有个小问题,手册中在taskENTER_CRITICAL中明确说明了关键区域内不允许调用FreeRTOS API函数,那么和这一数据结构的使用有些冲突。下面是我对这一问题在官方论坛上询问和解答。

whzh – 23 hours ago

I see the following content in the manual, are
these two paragraphs contradictory?

Manual P365 If there are to be multiple different writers then the
application writer must place each call to a writing API function
(such as xStreamBufferSend()) inside a critical section and use a send
block time of 0.

Manual P59 FreeRTOS API functions must not be called from within a
critical section.

Richard Damon – 21 hours ago

Both those statements are in my mind a bit simplified. First,
Streambuffers don’t need a critical section, but do need some form of
protection that you NEVER have multiple tasks trying to read or write
the buffer at a given time. A critical section is one simple way to do
this, having a Mutex protect the access should also work (and that
gets around the need for 0 block time.

Second, the limitiation isn’t so much that they can’t be called from a
critical section, but that no FreeRTOS API call should block or
attempt to change the running task inside a critical section. (some
ports actually don’t have a problem with it, but some do).

三 MessageBuffer 消息缓冲区

消息缓冲区是在流式缓冲区的基础上实现的,其进一步针对“消息”进行设计改进。MessageBuffer每一条消息的写入增加了一个字节用来表示该条消息的长度。读取时需要一次性读出至少一条消息,否则会返回 0.

MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );
size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
                            const void *pvTxData,
                            size_t xDataLengthBytes,
                            TickType_t xTicksToWait );
size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
                              void *pvRxData,
                              size_t xBufferLengthBytes,
                               TickType_t xTicksToWait );

综上,对比了三种数据结构的区别,每一种数据结构都是在上一中简单结构中的增强和针对性的改进。确定的场景中选用合适的数据结构将事半功倍。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS三种数据结构区别(StreamBuffer,MessageBuffer,Queue) 的相关文章

  • 将 Laravel 事件订阅者排队

    我通过事件订阅者处理多个事件 而不是创建单独的事件 侦听器 我想对其中几个事件进行排队 但我还没有找到实现这一目标的方法 我已经关注官方了文档 https laravel com docs 5 2 events event subscrib
  • 持久 Akka 邮箱和无损

    在 Akka 中 当一个 actor 在处理消息时死亡 内部onReceive 该消息丢失 有没有办法保证无损 有没有办法配置 Akka 始终保留消息before将他们发送到onReceive 以便在演员死亡时可以恢复并重播 也许像持久邮箱
  • 如何在Mule中创建独占队列消费者?

    在 ActiveMQ 中 您可以为队列配置独占消费者 例如 Queue Name Here consumer exclusive true 如何在 Mule 中配置像上面这样的独占消费者 您需要对队列名称进行 URL 编码 因为 Mule
  • 使用 Celery 创建动态队列

    这是我的场景 当用户登录我的网站时 我会为给定用户排队一堆任务 通常每个任务需要 100 毫秒 每个用户有 100 多个任务 这些任务排队到默认的 Celery 队列中 并且我有数百个工作线程正在运行 当任务在后端完成时 我使用 webso
  • 使用 Celery(RabbitMQ、Django)检索队列长度

    我在 django 项目中使用 Celery 我的代理是 RabbitMQ 我想检索队列的长度 我浏览了 Celery 的代码 但没有找到执行此操作的工具 我在 stackoverflow 上发现了这个问题 从客户端检查 RabbitMQ
  • 使用 Javascript 进行速率限制并将 ajax 调用排队为每 15 秒一次

    我有一个应用程序 每次用户执行某些操作时都会自动发送推文 如果用户愿意 可以轻松地每秒执行一次该操作 Twitter 的速率限制表示 它关注 15 分钟内发生了多少条推文 从技术上讲 我认为我总是低于 15 分钟标记 但 Twitter 似
  • “入队”和“出队”之间的区别

    有人可以解释一下主要区别吗 我对任何语言编程中的这些函数都没有明确的了解 C 和 C 等编程语言中的一些基本数据结构是堆栈和队列 堆栈数据结构遵循 先进后出 策略 FILO 其中插入或 推入 堆栈的第一个元素是最后一个从堆栈中删除或 弹出
  • NodeJS 推送队列,由 Laravel Worker 消耗

    我正在尝试使用节点应用程序发送到 SQS 的消息 因此 推送 操作由服务器 A 上的 Node App 执行 监听 操作由服务器 B 上的 Laravel App 执行 我的问题 我不知道如何格式化要使用的有效负载php artisan q
  • Java 中保存最后 N 个元素的大小受限队列

    关于 Java 库的一个非常简单快速的问题 是否有一个现成的类可以实现Queue具有固定的最大大小 即它始终允许添加元素 但它会默默地删除头元素以为新添加的元素提供空间 当然 手动实现它很简单 import java util Linked
  • 如何在java中排队并调用实际方法(而不是立即评估)?

    有一个对时间敏感的任务列表 但在这种情况下 时间 对于另一个程序告诉我的内容是任意的 它更像是 滴答声 而不是时间 但是 我不希望立即评估所述方法 我希望一个在另一个完成后执行 我在队列中使用链表 但我不确定如何 是否可以访问类中的实际方法
  • 使用java工具的类似Sidekiq的队列?

    我想要一个工作队列 其行为几乎与 ruby 的 sidekiq 完全相同 它不need使用 Redis 但它可以 我只是不能使用 ruby 甚至不能使用 Jruby 基本上 我希望能够创建使用某些参数运行的作业 并且工作池执行作业 工作人员
  • Azure 有害队列计数警报规则

    在之前的一个项目中 我设法设置了一个警报规则 该规则会查看有害队列消息计数 并在队列中存在某些内容时 每天一次 使用 webhook 向 slack 发出警报 我试图找到它在 Azure 中的位置 因为看起来事情已经发生了变化 如果这不是
  • 将非泛型类扩展为泛型类

    org apache commons collections buffer 包中的 Java 类 CircularFifoBuffer 是非泛型的 可以存储任何类的对象 我想创建一个通用版本 它只能保存类 T 的对象 我的第一个想法是扩展
  • GCD获取队列名称/标签

    如何获取当前队列名称 我的意思是队列标签com example myqueue 在 Xcode 4 调试器中我只能看到 block invoke 1 怎么样dispatch queue get label http developer ap
  • 为什么 std::queue 使用 std::dequeue 作为底层默认容器?

    继续阅读cplusplus com http www cplusplus com reference queue queue std queue实现如下 队列被实现为容器适配器 这些类 使用特定容器类的封装对象作为其 底层容器 提供一组特定
  • 有队列实现吗?

    任何人都可以建议使用 Go 容器来实现简单快速的 FIF 队列 Go 有 3 种不同的容器 heap list and vector 哪一种更适合实现队列 事实上 如果您想要的是一个基本且易于使用的 fifo 队列 slice 可以满足您所
  • 如何实现可运行队列

    我正在尝试实现一个可运行队列 在异步任务期间依次执行 意味着队列中的下一个将在另一个完成后执行 我编写了一个管理器来管理这些可运行对象和本身就是可运行对象的任务 然后 我获取异步任务中的第一个任务并运行它 希望它能够在队列中运行 但是它最终
  • python 队列获取大小,使用 qsize() 还是 len()?

    我见过这样的例子qsize and len 已用于计算队列的大小 两者有什么区别 对于大多数容器 您需要len but Queue Queue实际上并不支持len 这可能是因为它很旧 或者因为在多线程环境中获取队列的长度并不是特别有用 无论
  • ArrayDeque 和 LinkedBlockingDeque

    只是想知道为什么他们做了一个LinkedBlockingDeque而同一个非并发对应物是ArrayDeque它基于可调整大小的数组 LinkedBlockingQueue使用一组节点 例如LinkedList 尽管没有实施List 我知道可
  • 是否可以更改队列中的元素?

    假设我有一个整数队列 或任何 T 类 我可以更改队列中元素的值吗 更具体地说 如果我将队列定义如下 Queue

随机推荐

  • LwIP IP 层常用函数和宏

    1 将 4 字节数据组成 IP 地址 头文件 xff1a ip addr h span class token function IP ADDR4 span span class token punctuation span ipaddr
  • 测试驱动的嵌入式开发 001:VSCode + CMake + CppUTest 环境搭建

    本文是对 测试驱动的嵌入式 C 语言开发 第二章的实践 对资源受限的嵌入式项目如何进行测试驱动开发的所有疑问 xff0c 都因为本书第二章最开始的一句话而消解 xff0c 当我读到这句话时 xff0c 脑袋里有闪电掠过 这句话是 xff1a
  • 测试驱动的嵌入式开发 002:VSCode + CMake + Unity 环境搭建

    本文是对 测试驱动的嵌入式 C 语言开发 第二章的实践 搭建 VSCode 这部分参考博文 基于Windows 的 VS Code C C 43 43 编译环境搭建 安装 CMake 安装 CMake xff0c 在官网下载最新安装包 安装
  • 原理图与 PCB 绘制备忘

    原理图绘制 导出 BOM 点击菜单 Reports Bill of Materials xff0c 在弹出的生成 BOM 界面中 xff0c 点击 OK 按钮导出 BOM 批量修改器件标识 xff08 比如型号 xff0c 阻值 xff09
  • Windows 10 安装 MySQL

    确认是否已安装 MySQL xff08 1 xff09 按 win 43 r 快捷键打开运行 xff1b xff08 2 xff09 输入 services msc xff1b xff08 3 xff09 点击 确定 xff0c 在打开的服
  • lwIP 细节之四:ARP 相关知识

    ARP 表项的最大存活时间与宏 ARP MAXAGE 相关 xff0c 默认为 240 x 5000ms 61 20 分钟 当 ARP 表项还有最后一分钟 xff08 由宏 ARP AGE REREQUEST USED 控制 xff09 存
  • Windows 环境下的 Socket 编程 4 - 基于 UDP 的服务器/客户端

    在 TCP 中 xff0c 套接字之间应该是一对一的关系 若向 10 个客户端提供服务 xff0c 则除了守门的服务器套接字外 xff0c 还需要 10 个服务器端套接字 但在 UDP 中 xff0c 不管是服务器端还是客户端都只需要 1
  • ADS1120 备忘

    ADS1120 是一个小型 低功耗 16 bit 模数转换器 xff08 ADC xff09 xff1a 内置 PGA xff08 1 128 xff09 内置参考基准 xff08 2 048V xff09 内置温度传感器内置 2 个已配对
  • Windows 环境下的 Socket 编程 5 - 套接字的可选项

    套接字具有多种特性 xff0c 这些特性可以更改 更改和读取可选项函数 span class token keyword int span span class token function getsockopt span span cla
  • 使能中断与禁止中断策略比较

    本文描述的内容仅适用于 Cortex M3 M4 架构 Keil MDK 编译环境 在阅读 RT Thread 源码和 FreeRTOS 源码时 xff0c 发现二者使能中断和禁止中断的方式不同 xff0c 再加上 CMSIS 也提供了使能
  • FreeModbus RTU 移植指南

    FreeModbus 简介 FreeModbus 是一个免费的软件协议栈 xff0c 实现了 Modbus 从机功能 xff1a 纯 C 语言支持 Modbus RTU ASCII支持 Modbus TCP 本文介绍 Modbus RTU
  • 随想007:模块化代码

    你一定不止一次的听说过模块化代码 理想的模块化代码高内聚低耦合 逻辑清晰 经过严格测试 xff0c 易于复用 嵌入式 C 编程界到处流传着它的大名 在学校 在公司 在各种技术书籍中 xff0c 你总能找到它的身影 它被描述的像是无所不能 x
  • VS Code 用作嵌入式开发编辑器

    使用 Keil MDK 进行嵌入式开发时 xff0c Keil 的编辑器相对于主流编辑器而言有些不方便 xff0c 比如缺少暗色主题 缺少智能悬停感知 xff08 鼠标停在一个宏上 xff0c 能自动展开最终的宏结果 xff09 代码补全不
  • CSDN Marddown 编辑器语法备忘

    原文链接 xff1a https blog csdn net blogdevteam article details 103478461 本文对其二次加工 xff0c 增加渲染样式 补充例程 添加未收录的常用语法 CSDN Markdown
  • 随想008:烂摊子

    我看到过很多离谱的现象 比如 xff1a 程序 代码重复 命名随意 逻辑混乱 甚至对齐都不一致 xff0c 当我询问代码为什么这样写时 xff0c 他们告诉我 xff1a 我接手时就是这样 xff01 原理图参数错误 器件老旧 xff0c
  • MySQL —— Database initialization failed 错误处理

    安装 MySQL 过程中遇到的错误 xff0c 记录一下 xff0c 避免下次又遇到同样的错误 安装 MySQL 8 0 33 到最后一步时 xff0c 出现了小红点无法往下执行了 找了网上的方法解决了问题 xff0c 为了避免下次遇到同样
  • 随想009:读书

    我很懊恼的意识到 xff0c 直到过了 30 岁 xff0c 我才明白如何读书 我们在网上浏览新闻 阅读小说 xff0c 这些让人愉悦的阅读不叫读书 xff0c 顶多叫消遣 xff1b 我们在学校背诵历史 地理 xff0c 记住数学公式和化
  • 找文心一言问了几个嵌入式软件开发的问题

    百度终于通知我可以试用文心一言了 xff0c 试验了一番 xff0c 总体满意 xff0c 记录几个文心一言回答的问题 我是一个嵌入式软件开发者 xff0c 你能帮我做什么工作以提高我的开发效率 作为一个嵌入式软件开发者 xff0c 以下是
  • JavaScript常用数组属性和方法

    本文给出了js xff08 JavaScript xff09 数组 xff08 Array xff09 操作所涉及到的所有常用内置函数说明及用法 xff0c 希望对大家有所帮助 数组的属性和方法 属性length属性 xff1a 方法1 把
  • FreeRTOS三种数据结构区别(StreamBuffer,MessageBuffer,Queue)

    转载自博客 xff1a https blog zh123 top p 61 308 Queue队列是最基本的数据结构 xff0c 在FreeRTOS v10 0后提供了另外两种高级数据结构为Streambuffer和MessageBuffe