Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
bug反馈
ringbuffer
5
对ringbuffer中rt_ringbuffer_put_force函数的疑问
发布于 2021-07-16 10:06:17 浏览:1036
订阅该版
[tocm] 最近研究驱动框架,顺带研读了ringbuffer源代码,发现一处疑问,个人认为是bug,也可能能力有限分析不对,请各位大佬批评指正,代码如下: ```c rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length) { rt_uint16_t space_length; RT_ASSERT(rb != RT_NULL); space_length = rt_ringbuffer_space_len(rb); if (length > rb->buffer_size) { ptr = &ptr[length - rb->buffer_size]; length = rb->buffer_size; } if (rb->buffer_size - rb->write_index > length) { /* read_index - write_index = empty space */ memcpy(&rb->buffer_ptr[rb->write_index], ptr, length); /* this should not cause overflow because there is enough space for * length of data in current mirror */ rb->write_index += length; if (length > space_length) rb->read_index = rb->write_index; return length; } memcpy(&rb->buffer_ptr[rb->write_index], &ptr[0], rb->buffer_size - rb->write_index); memcpy(&rb->buffer_ptr[0], &ptr[rb->buffer_size - rb->write_index], length - (rb->buffer_size - rb->write_index)); /* we are going into the other side of the mirror */ rb->write_mirror = ~rb->write_mirror; rb->write_index = length - (rb->buffer_size - rb->write_index); /******************分析这里,似乎是有bug??? ****************/ if (length > space_length) { rb->read_mirror = ~rb->read_mirror; rb->read_index = rb->write_index; } return length; } RTM_EXPORT(rt_ringbuffer_put_force); ``` `rt_ringbuffer_put_force`函数,向buffer中put数据的策略为: 1)如果数据长度`length > buffer_size,`就将数据截断,只留后面的`buffer_size`长度的数据,从下面代码可以看出来: ```c if (length > rb->buffer_size) { ptr = &ptr[length - rb->buffer_size]; length = rb->buffer_size; } ``` 2)space_length为空闲区长度,如果`length > space_length`,就将buffer中老的数据覆盖掉。 的确,`rt_ringbuffer_put_force`是按照上面两条策略在put数据,但是代码到下面这几行,存在问题了: 这里是一条华丽的分界线 --- ```c if (length > space_length) { rb->read_mirror = ~rb->read_mirror; rb->read_index = rb->write_index; } ``` 这里是`length >= buffer_size - write_index`的情况,不然前面的代码直接return了。针对这种情况: 1. `write_index`一定会溢出(也就是会超过`buffer_size`),这个时候一定有`write_mirror = ~write_mirror`。(问题来了:`read_index`是否会溢出?这得分情况讨论,看下面2) 2. read_index 呢(`length > space_length, read_index`就一定会超过buffer_size???,我认为不一定 ),下面讨论: ### 情况2 `write_index < read_index`,这种情况下,空闲区域在缓冲区中间,有数据的区域在缓冲区两头,这种情况下,read_index和write_index都会溢出,因此有: ` read_mirror = ~read_mirror` ### 情况1 `read_index < write_index`,这种情况,有数据区域在缓冲区中间,缓冲区两头是空闲的,这个时候,write_index一定会溢出,但是read_index却不会溢出(因为前面限定了length最大不会超过buffer_size),这种情况下,read_mirror不变。 附一张截图,供大家理解我的意思:  所以我认为应该这样改: ```c if (length > space_length && write_index ≤ read_index) { rb->read_mirror = ~rb->read_mirror; rb->read_index = rb->write_index; } ``` 大家认为呢?
查看更多
123
认证专家
2021-07-16
这家伙很懒,什么也没写!
@RongLiu 先表一表楼主,可以的,很细心。👍 首先这个不叫溢出,这个叫回环,环形buffer的回环属于正常操作。(而溢出是致命的错误,溢出有标准的解释和处理手段,不要乱起名字)。 然后是这个 `情况1`,分析的很有道理,`write_index` 回环的时候,`read_index` 不一定会触发回环,这个时候如果强行将 `read_mirror` 取反,则会导致 环形缓冲区的数据长度清空,而不是满。 最后是关于楼主修改的部分是有问题的,应该这样改 ```c if (length > space_length) { if(rb->write_index <= rb->read_index) /* 情况1 */ rb->read_mirror = ~rb->read_mirror; rb->read_index = rb->write_index; /* 情况2 */ } ``` 应该充分考虑当`length > space_length`时候的情况,也就是情况1和情况2,显然楼主分析完之后,代码没有考虑情况2. 另外提供一份测试代码,方便测试: ```c void test(void) { rt_uint8_t ring_buffer[64]; /* ringbuffer的缓冲区*/ rt_memset(ring_buffer, -1, 64); /* 先格式化为0xff */ struct rt_ringbuffer test_rb; rt_ringbuffer_init(&test_rb, ring_buffer, 64); rt_uint8_t write_buffer[40], read_buffer[40]; /* 读buffer缓冲区和写buffer缓冲区 */ rt_memset(write_buffer, 0, 40); rt_ringbuffer_put(&test_rb, write_buffer, 40); rt_ringbuffer_get(&test_rb, read_buffer, 5); rt_kprintf("rt_ringbuffer_data_len = [%d]\n", rt_ringbuffer_data_len(&test_rb)); rt_uint8_t write_second_buffer[34]; rt_memset(write_second_buffer, 1, 40); rt_ringbuffer_put_force(&test_rb, write_second_buffer, 34); rt_kprintf("rt_ringbuffer_data_len = [%d]\n", rt_ringbuffer_data_len(&test_rb)); } ```
5
个回答
默认排序
按发布时间排序
aozima
2021-07-16
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!
笔记好评!(草书看不懂,先夸再说 :-( ) ---
玩具箱
2021-07-16
这家伙很懒,什么也没写!
不明白为什么会认为write_index一定会溢出?
flyboy
2021-07-23
Do my self();
厉害了,谁来把测试用例提交上来👍 https://github.com/RT-Thread/rt-thread/tree/master/examples/utest
zhang515140166
2022-04-27
这家伙很懒,什么也没写!
```c if (length > space_length) { rb->read_mirror = ~rb->write_mirror; rb->read_index = rb->write_index; } ``` 这样改就可以了。
撰写答案
登录
注册新账号
关注者
0
被浏览
1k
关于作者
arminker
这家伙很懒,什么也没写!
提问
11
回答
5
被采纳
0
关注TA
发私信
相关问题
1
大量接收数据 如何处理能减少丢包率
2
有没有一种实现类似 ringbuffer, 但返回数据长度 和传入时候一样
3
使用ringbuffer时,自检到thread的type不匹配
4
RINGBUFF里镜像索引取反是为什么?
5
系统提供环形FIFO写入重载时可能存在数据错乱问题
6
rt_ringbuffer_peak疑问
7
串口 DMA ringbuffer 接收有可能覆盖数据
8
studio的setting功能详细配置页有问题
9
master主支BSP\STM32\stm32f429-st-disco无法编译
10
论坛的模糊搜索真的是太差劲了
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
五分钟玩转RT-Thread新社区
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
6
国产MCU移植系列教程汇总,欢迎查看!
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用 D1s (RDC2022 纪念版) 连接 thingspeak
2
RTduino 初体验
3
stm32wle5 双SRAM使用
4
开工大吉 | 借RT-Thread的论坛宝地,给各位嵌入式开发者送106块开发板!
5
随笔、FinSH原理浅析
热门标签
RT-Thread Studio
串口
LWIP
SPI
Env
AT
FinSH
ART-Pi
Bootloader
CAN总线
Hardfault
文件系统
USB
DMA
RT-Thread
线程
stm32
RT-Thread Nano
SCons
MQTT
ESP8266
ota
packages_软件包
UART
rtthread
RTC
freemodbus
I2C
flash
cubemx
W5500
rt-smart
定时器
FAL
rtt
PWM
ADC
BSP
SDIO
msh
AB32VG1
Debug
C++_cpp
socket
SFUD
中断
编译报错
MicroPython
keil
LVGL
本月问答贡献
出出啊
1424
个答案
315
次被采纳
小小李sunny
1326
个答案
262
次被采纳
crystal266
486
个答案
144
次被采纳
whj467467222
1210
个答案
141
次被采纳
张世争
581
个答案
131
次被采纳
本月文章贡献
出出啊
4
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
crystal266
1
篇文章
1
次点赞
whj467467222
2
篇文章
2
次点赞
张世争
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部