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

linux4.1.15 rt补丁_听说你不知道 RT-Thread 有个 ringbuffer

2cb7f48eba00b2b0b89b43db09d86b97.png

在嵌入式开发中,我们经常需要用到 FIFO 数据结构来存储数据,比如任务间的通信、串口数据收发等场合。很多小伙伴不知道 RT-Thread 为我们提供了一个 ringbuffer 数据结构,代码位于:

  • components/drivers/src/ringbuffer.c
  • components/drivers/include/ipc/ringbuffer.h

RingBuffer 其实就是先进先出(FIFO)的循环缓冲区。把一段线性的存储空间当作一个环形的存储空间使用,可以提高存储空间的利用率。

750f64d9be933018b9e3781a6cd9534c.png

数据结构

RT-Thread 定义了 rt_ringbuffer 结构体,包括四组成员:缓冲区指针 buffer_ptr、缓冲区大小 buffer_size、读指针、写指针。

struct rt_ringbuffer
{
    rt_uint8_t *buffer_ptr;
    rt_uint16_t read_mirror : 1;
    rt_uint16_t read_index : 15;
    rt_uint16_t write_mirror : 1;
    rt_uint16_t write_index : 15;
    rt_int16_t buffer_size;
};

对于读、写指针,rt_ringbuffer 结构体使用位域来定义 read 和 write 的索引值和镜像位。更具体来说,使用 MSB(最高有效位)作为 read_index 和 write_index 变量的镜像位。通过这种方式,为缓冲区添加了虚拟镜像,用于指示 read 和 write 指针指向的是普通缓冲区还是镜像缓冲区。

  • 如果 write_index 和 read_index 相等,但在不同镜像,说明缓冲区满了;
  • 如果 write_index 和 read_index 相等,但在相同镜像,说明缓冲区空了。

为了让大家更好地理解,我给大家画了个图:

3a2d458e0ec5f939acd6dff14b1bf7fc.png

接口函数

初始化与重置

void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size);
void rt_ringbuffer_reset(struct rt_ringbuffer *rb);

这两个函数适用于以静态方式初始化或重置 ringbuffer,需要事先准备好 ringbuffer 对象和一段内存空间。

创建和销毁

struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t length);
void rt_ringbuffer_destroy(struct rt_ringbuffer *rb);

这两个函数适用于以动态方式创建和销毁 ringbuffer,将在堆空间申请相关资源,并返回一个 ringbuffer 指针。

写入数据

rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch);
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch);

往 ringbuffer 写入数据可以使用这组函数,其中 `_put` 为写入一串字符,`_putchar` 为写入一个字符,带 `_force` 的函数则表示如果缓冲区满了,将直接用新数据覆盖旧数据(谨慎使用)。

读出数据

rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length);
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch);

从 ringbuffer 读出数据可以使用这组函数,其中 `_get` 为读出一串字符,`_getchar` 为读出一个字符。

获取长度

读写操作前可以先判断是否有数据可读或者有位置可写,ringbuffer 提供了三个接口获取长度,包括获取 ringbuffer 的总长度、数据长度、空闲长度。

获取缓冲区数据长度

rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb);

获取缓冲区总长度

rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb);

获取缓冲区空闲长度

#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))

应用示例

下面通过一个简单的示例,来看看在程序中该如何使用 ringbuffer。首先创建一个 ringbuffer 对象,然后 Producer 线程往 ringbuffer 写入数据,Consumer 线程从 ringbuffer 读出数据。这是一个典型生产者-消费者模型。

#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>

#define RING_BUFFER_LEN        8

static struct rt_ringbuffer *rb;
static char  *str = "Hello, World";

static void consumer_thread_entry(void *arg)
{
    char ch;

    while (1)
    {
        if (1 == rt_ringbuffer_getchar(rb, &ch))
        {
            rt_kprintf("[Consumer] <- %cn", ch);
        }
        rt_thread_mdelay(500);
    }
}

static void ringbuffer_sample(int argc, char** argv)
{
    rt_thread_t tid;
    rt_uint16_t i = 0;

    rb = rt_ringbuffer_create(RING_BUFFER_LEN);
    if (rb == RT_NULL)
    {
        rt_kprintf("Can't create ringbffer");
        return;
    }

    tid = rt_thread_create("consumer", consumer_thread_entry, RT_NULL,
                           1024, RT_THREAD_PRIORITY_MAX/3, 20);
    if (tid == RT_NULL)
    {
        rt_ringbuffer_destroy(rb);
    }
    rt_thread_startup(tid);


    while (str[i] != '0')
    {
        rt_kprintf("[Producer] -> %cn", str[i]);
        rt_ringbuffer_putchar(rb, str[i++]);
        rt_thread_mdelay(500);
    }

    rt_thread_delete(tid);
    rt_ringbuffer_destroy(rb);
    
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT(ringbuffer_sample, Start a producer and a consumer with a ringbuffer);
#endif

运行结果:

c4b9b12d2224e5fc42a76d263097becd.png

相关文章:

  • python爬虫语言都能干什么_Python爬虫还能干什么?
  • xxl子任务_XXL-JOB(1) 分布式任务系统选型和XXL-JOB介绍
  • 徐小湛概率论与数理统计课件_考研数学 徐小湛教授线性代数90讲
  • 怎么下载python笔记_python学习笔记(1)python下载及运行
  • vue 给checkbox 赋值_vue中关于checkbox数据绑定v-model指令的个人理解
  • mysql中文乱码解决_java+mysql中文乱码问题
  • mysql查询之间的数据_如何从两个日期之间的MySQL查询获取数据?
  • ubuntu12.04安装mysql_Ubuntu12.04 安装MySQL简单步骤
  • mysql联合查询怎么加子查询吗_mysql学习之路_联合查询与子查询
  • shell+crontab+mysql_crontab+shell脚本实现定时备份mysql数据库
  • mysql association_MyBatis association的两种形式——MyBatis学习笔记之四
  • mysql 安装 linux debug_Linux 下 Mysql-4.0.26 安装调试问题
  • mysql语句整理_最全的mysql查询语句整理
  • mysql 同步机制_MySQL主从同步机制及同步中的问题处理
  • win8安装mysql出现2503_Win8.1安装msi出现2503错误怎么办?
  • python3.6+scrapy+mysql 爬虫实战
  • [deviceone开发]-do_Webview的基本示例
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • ES2017异步函数现已正式可用
  • iOS | NSProxy
  • java第三方包学习之lombok
  • js学习笔记
  • Mysql优化
  • spring boot 整合mybatis 无法输出sql的问题
  • Spring Boot快速入门(一):Hello Spring Boot
  • SQLServer之创建数据库快照
  • Vue2.x学习三:事件处理生命周期钩子
  • vue脚手架vue-cli
  • 基于 Babel 的 npm 包最小化设置
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 力扣(LeetCode)21
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 每天10道Java面试题,跟我走,offer有!
  • 如何解决微信端直接跳WAP端
  • 微信小程序开发问题汇总
  • 学习HTTP相关知识笔记
  • 正则表达式
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • !$boo在php中什么意思,php前戏
  • #Lua:Lua调用C++生成的DLL库
  • #QT项目实战(天气预报)
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (4) PIVOT 和 UPIVOT 的使用
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (rabbitmq的高级特性)消息可靠性
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (十六)Flask之蓝图
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • *** 2003
  • **PHP分步表单提交思路(分页表单提交)