硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2245|回复: 16
收起左侧

[技术讨论] 环形缓冲区实现方案

  [复制链接]

78

主题

693

回帖

927

积分

金牌会员

积分
927
发表于 2022-2-20 01:27:18 | 显示全部楼层 |阅读模式
各位大佬。目前想实现一个串口缓冲区,需要判空和判满,想到两种方案,大家觉得那种方案会更加安全稳定
方案1:使用缓冲区读写指针的相对位置来判断缓冲区满与空
方案2:使用一个变量统计环形缓冲区内容数量,通过判断缓冲区内容大小来判断缓冲区空与满

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107100
QQ
发表于 2022-2-20 10:28:51 | 显示全部楼层
都行,关键还是满了之后的处理机制,是阻塞等待还是覆盖。

回复

使用道具 举报

747

主题

1049

回帖

3295

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3295
发表于 2022-2-20 10:37:59 | 显示全部楼层
方案2实现简单。 方案1判断有逻辑问题
回复

使用道具 举报

78

主题

693

回帖

927

积分

金牌会员

积分
927
 楼主| 发表于 2022-2-20 12:44:37 | 显示全部楼层
armfly 发表于 2022-2-20 10:37
方案2实现简单。 方案1判断有逻辑问题

也总觉得方案有什么问题,但是又说不出来的那种
回复

使用道具 举报

78

主题

693

回帖

927

积分

金牌会员

积分
927
 楼主| 发表于 2022-2-20 12:45:09 | 显示全部楼层
eric2013 发表于 2022-2-20 10:28
都行,关键还是满了之后的处理机制,是阻塞等待还是覆盖。

方案1总感觉有什么问题,但是又说不出来
回复

使用道具 举报

2

主题

269

回帖

275

积分

高级会员

积分
275
发表于 2022-2-20 13:21:51 | 显示全部楼层
方案1 如果不会溢出是没问题的,如果溢出问题就大了
所以我用了ringbuffer的开源库,我发过一个demo可以自己翻翻
回复

使用道具 举报

4

主题

10

回帖

22

积分

新手上路

积分
22
发表于 2022-2-21 17:31:18 | 显示全部楼层
我一直都在用方式1,没什么问题。如果满的话就覆盖(本来就是暂存的)。
回复

使用道具 举报

41

主题

215

回帖

338

积分

高级会员

积分
338
发表于 2022-2-21 19:16:07 | 显示全部楼层
回复

使用道具 举报

5

主题

196

回帖

211

积分

高级会员

积分
211
发表于 2022-2-22 02:09:21 | 显示全部楼层
缓冲满了就不让继续写,返回0让上层retry。
回复

使用道具 举报

2

主题

24

回帖

30

积分

新手上路

积分
30
发表于 2022-2-22 09:41:34 | 显示全部楼层
现在成熟的环形缓冲区方案在判空方法上采用两个变量统计头尾偏移量,在判满方法上采用方案2。至于满了之后的处理机制,既然是缓冲区,常规是覆盖旧数据。
回复

使用道具 举报

1

主题

8

回帖

11

积分

新手上路

积分
11
发表于 2022-2-22 10:33:39 | 显示全部楼层
可以看看rtthread 的环形缓冲区实现
回复

使用道具 举报

3

主题

38

回帖

47

积分

新手上路

积分
47
发表于 2022-2-23 08:33:10 | 显示全部楼层
可以参考linux内核的kfifo环形队列。
回复

使用道具 举报

335

主题

2040

回帖

3050

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3050
发表于 2022-2-23 09:17:35 | 显示全部楼层
snakeemail 发表于 2022-2-21 19:16
https://github.com/QuantumLeaps/lock-free-ring-buffer

这个代码里面没看懂 RingBuf_process_all 是干什么的函数?
回复

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-2-23 10:13:09 | 显示全部楼层
本帖最后由 ihavedone 于 2022-2-23 10:15 编辑
庄永 发表于 2022-2-20 12:45
方案1总感觉有什么问题,但是又说不出来

方案 1 的问题就是不能全部写满,必须要留一个空字节。 如果全部写满了,就不知道是空还是满。。。方案 1 如果满了需要覆盖,就需要同时移动读写指针,但必须保证写指针不会套圈读指针。
回复

使用道具 举报

78

主题

693

回帖

927

积分

金牌会员

积分
927
 楼主| 发表于 2022-2-23 22:15:26 | 显示全部楼层
ihavedone 发表于 2022-2-23 10:13
方案 1 的问题就是不能全部写满,必须要留一个空字节。 如果全部写满了,就不知道是空还是满。。。方案 1 ...

体会下你的这个说法。没大理解
回复

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-2-24 11:38:11 | 显示全部楼层
庄永 发表于 2022-2-23 22:15
体会下你的这个说法。没大理解

假设缓冲区 buf 大小  size = 10,初始状态 wr == rd。
1、缓冲区空,wr==rd。
不考虑超出缓冲区,指针重新归零的情况。

2、写一个字节,wr++,此时 wr == rd + 1。
3、读一个字节,rd++,此时 wr==rd。


假设缓冲区为初始状态,wr==rd==0的情况。
4、一次性写满,则最多只能写 9 个字节,此时 buf[0] ~ buf[8] 有数据,wr==9。
5、如果写 10 个字节,此时 buf[0] ~ buf[9] 有数据,wr == 10,超出范围,必须将 wr = 0。  此时 wr==rd,就区分不了是 10 个字节,还是 0 个字节。

缓冲区满覆盖数据的情况。
6、上面 5 中,wr 超出范围,重新赋值 0 的时候,因为 wr == rd,所以此时要增加 rd,使 wr != rd。即 wr = 0, rd = 1。  
7、上面 6 中,如果读数据,则可以读到 buf[1]~buf[9],读完之后 rd = 0,此时 wr==rd,即缓冲区为空。buf[0] 的数据没有读出来,但是已经读不到了,也就是被覆盖了。

计算缓冲区中数据量 cnt:
8、如果 wr >= rd,则 cnt = wr-rd。
9、如果 wr < rd,则 cnt = size-rd+wr。
回复

使用道具 举报

78

主题

693

回帖

927

积分

金牌会员

积分
927
 楼主| 发表于 2022-2-24 22:41:25 | 显示全部楼层
tian1993 发表于 2022-2-22 10:33
可以看看rtthread 的环形缓冲区实现

感谢提醒,rtt的这块好像确实很牛逼
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-17 11:40 , Processed in 0.211727 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表