搜索
bottom↓
回复: 29

刚写好的FIFO源码(C++),送给需要的人!

  [复制链接]

出870入263汤圆

发表于 2018-1-25 20:25:53 | 显示全部楼层 |阅读模式
本帖最后由 armstrong 于 2018-1-25 20:27 编辑

gy_fifo.hpp
  1. #ifndef __FIFO_HPP__
  2. #define __FIFO_HPP__

  3. #include <stdint.h>

  4. class GYFIFO
  5. {
  6. private:
  7.   uint8_t *buffer;
  8.   uint32_t size;
  9.   uint32_t ip;
  10.   uint32_t op;
  11.   uint32_t (*puter)(GYFIFO& obj, uint8_t const *buf, uint32_t num);
  12.   /* 作为真正操纵FIFO写入功能的函数 */
  13.   static uint32_t RealPut(GYFIFO& obj, uint8_t const *buf, uint32_t num);
  14.   static uint32_t DumyPut(GYFIFO& obj, uint8_t const *buf, uint32_t num);
  15. public:
  16.   /* 构造器。切勿调用OS函数 */
  17.   GYFIFO(uint8_t *buf, uint32_t sz):
  18.     ip(0), op(0),
  19.     puter(DumyPut)
  20.   {
  21.     buffer = buf;
  22.     size = sz;
  23.     if(buf && sz){
  24.       /* FIFO有效 */
  25.       puter = RealPut;
  26.     }
  27.   }
  28.   /* 析构器 */
  29.   ~GYFIFO()
  30.   {
  31.     puter = DumyPut;
  32.     Clear();
  33.     buffer = NULL;
  34.     size = 0;
  35.   }
  36.   /* 把数据写入FIFO,返回成功写入的字节数 */
  37.   uint32_t Put(uint8_t const *buf, uint32_t num);
  38.   /* 读取FIFO里的数据,返回成功读取的字节数 */
  39.   uint32_t Get(uint8_t *buf, uint32_t sz);
  40.   /* 查看FIFO里现存的数据字节数 */
  41.   uint32_t Count() const
  42.   {
  43.     int num = (int)(ip - op);
  44.     if(num < 0){
  45.       num += size;
  46.     }
  47.     return num;
  48.   }
  49.   /* 查看FIFO当前剩余的空闲空间 */
  50.   uint32_t NumFree() const
  51.   {
  52.     uint32_t num = Count();
  53.     return (size - num - 1);
  54.   }
  55.   /* 查看FIFO缓冲区的原始容量 */
  56.   uint32_t Size() const
  57.   {
  58.     return size;
  59.   }
  60.   /* 清空FIFO */
  61.   void Clear()
  62.   {
  63.     op = ip;
  64.   }
  65. };

  66. #endif /* __FIFO_HPP__ */

复制代码

gy_fifo.cpp
  1. #include "gy_fifo.hpp"

  2. /* 作为FIFO无效时的空写入函数 */
  3. uint32_t GYFIFO::DumyPut(GYFIFO& obj, uint8_t const *buf, uint32_t num)
  4. {
  5.   return num;
  6. }

  7. uint32_t GYFIFO::RealPut(GYFIFO& obj, uint8_t const *buf, uint32_t num)
  8. {
  9.   uint32_t nfree = obj.NumFree();
  10.   uint32_t index = obj.ip;
  11.   uint32_t ncpy;
  12.   
  13.   if(num > nfree){
  14.     num = nfree;
  15.   }
  16.   ncpy = num;
  17.   if(index + ncpy >= obj.size){
  18.     /* 跨越缓存边界,需要分段拷贝 */
  19.     ncpy = obj.size - index;
  20.     memcpy(obj.buffer+index, buf, ncpy);
  21.     buf = buf + ncpy;
  22.     ncpy = num - ncpy;
  23.     index = 0;
  24.   }
  25.   if(ncpy > 0){
  26.     memcpy(obj.buffer+index, buf, ncpy);
  27.     index += ncpy;
  28.   }
  29.   
  30.   obj.ip = index;
  31.   return num;
  32. }

  33. uint32_t GYFIFO::Put(uint8_t const *buf, uint32_t num)
  34. {
  35.   return puter(*this, buf, num);
  36. }

  37. uint32_t GYFIFO::Get(uint8_t *buf, uint32_t sz)
  38. {
  39.   uint32_t ntotal = Count();
  40.   uint32_t index = op;
  41.   uint32_t ncpy;
  42.   
  43.   if(ntotal > sz){
  44.     ntotal = sz;
  45.   }
  46.   ncpy = ntotal;
  47.   if(index + ncpy >= size){
  48.     /* 跨越缓存边界,需要分段拷贝 */
  49.     ncpy = size - index;
  50.     memcpy(buf, buffer+index, ncpy);
  51.     buf = buf + ncpy;
  52.     ncpy = ntotal - ncpy;
  53.     index = 0;
  54.   }
  55.   if(ncpy > 0){
  56.     memcpy(buf, buffer+index, ncpy);
  57.     index += ncpy;
  58.   }
  59.   
  60.   op = index;
  61.   return ntotal;
  62. }


复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出870入263汤圆

 楼主| 发表于 2018-1-25 20:50:46 | 显示全部楼层
我说说本代码的关键优点吧:如果有两个线程访问该FIFO(包括前后台系统的主循环和中断之间),一个读,一个写。这种情况下,该FIFO实现是不需要互斥保护的!
而RealPut和DumyPut的设计,是初始化为无效buffer指针和字节数时,仍然不会非法地址访问;而初始化buffer和size有效时,这样的性能仍然很高(相对于每次Put方法里去判断buffer和size是否有效的做法)!

出870入263汤圆

 楼主| 发表于 2018-1-25 20:28:39 | 显示全部楼层
大家有时间再去网络上找找看别人家的FIFO实现,与我的比比看就知道优点有哪些了。

出870入263汤圆

 楼主| 发表于 2018-1-25 20:30:26 | 显示全部楼层
如果FIFO缓存的字节数强制2的幂次的话,还可以再优化性能的。
但有得就有失,我就不强制缓存字节数了。

出100入85汤圆

发表于 2018-1-25 20:42:57 | 显示全部楼层
谢谢您的分享

出20入25汤圆

发表于 2018-1-25 21:10:04 来自手机 | 显示全部楼层
armstrong 发表于 2018-1-25 20:50
我说说本代码的关键优点吧:如果有两个线程访问该FIFO(包括前后台系统的主循环和中断之间),一个读,一个 ...

来个C的应用更广,线程安全实现在哪

出870入263汤圆

 楼主| 发表于 2018-1-25 21:21:02 | 显示全部楼层
chenchaoting 发表于 2018-1-25 21:10
来个C的应用更广,线程安全实现在哪

代码本身就实现为线程安全了。
限制是一个读一个写;不能多个读或者多个写。
C++代码很容易改成C,我之前都是用C写的。
这段时间改用C++,所以重新实现了一遍而已。

用MDK,IAR,GCC,都可以开发C++程序的。

出20入25汤圆

发表于 2018-1-25 21:28:41 来自手机 | 显示全部楼层
armstrong 发表于 2018-1-25 21:21
代码本身就实现为线程安全了。
限制是一个读一个写;不能多个读或者多个写。
C++代码很容易改成C,我之前 ...

前台要读,中断要写,不需要fifo修改内部代码

出0入0汤圆

发表于 2018-1-25 21:37:50 | 显示全部楼层
楼主参考一下kfifo,更简洁

出870入263汤圆

 楼主| 发表于 2018-1-25 21:45:43 | 显示全部楼层
本帖最后由 armstrong 于 2018-1-25 21:50 编辑
tabing 发表于 2018-1-25 21:37
楼主参考一下kfifo,更简洁


kfifo强制了size必须2的幂次,才有那样的简洁,如同我3楼所说。我是取舍之后选择灵活性。

此外,kfifo看起来简洁(其memcpy两次没有做条件判断),其实性能不如条件判断。
因为,memcpy传入的size为0时,虽然拷贝0字节。但确实发生了函数调用跳转,甚至堆栈的push-pop。而条件判断在现代的arm处理器上大部分是不会发生跳转的,这叫“分支预测”,比如ADDNE,BNE等等。

出0入0汤圆

发表于 2018-1-25 21:50:33 | 显示全部楼层
高手,顶顶顶,
多谢!

出235入235汤圆

发表于 2018-1-25 22:05:09 | 显示全部楼层
学习了。感谢分享

出140入8汤圆

发表于 2018-1-26 06:39:58 | 显示全部楼层
刚写好就拿出来把我们当小白鼠帮你做测试…
嗯,先收藏了再说…⊙∀⊙

出870入263汤圆

 楼主| 发表于 2018-1-26 08:13:43 | 显示全部楼层
leiyitan 发表于 2018-1-26 06:39
刚写好就拿出来把我们当小白鼠帮你做测试…
嗯,先收藏了再说…⊙∀⊙


以前用C的,现在改用C++重新实现。不会当你是白鼠的,当青蛙而已。

出0入0汤圆

发表于 2018-1-26 08:38:29 | 显示全部楼层
这个只适合中断传输,不适合DMA的。
如果是DMA,需要使用队列。

出870入263汤圆

 楼主| 发表于 2018-1-26 09:10:47 | 显示全部楼层
wuzhujian 发表于 2018-1-26 08:38
这个只适合中断传输,不适合DMA的。
如果是DMA,需要使用队列。

应用场景是各位应用开发者考虑的事吧

出0入0汤圆

发表于 2018-1-26 09:39:34 | 显示全部楼层
学习了,谢谢分享

出0入0汤圆

发表于 2018-1-26 09:44:24 来自手机 | 显示全部楼层
c版本的也共享吧,谢谢楼主

出0入0汤圆

发表于 2018-1-26 13:27:05 来自手机 | 显示全部楼层
本帖最后由 lovemini 于 2018-1-26 13:29 编辑

学习了,希望楼主提供一下C语言版本

出140入8汤圆

发表于 2018-1-26 23:24:59 | 显示全部楼层
armstrong 发表于 2018-1-26 08:13
以前用C的,现在改用C++重新实现。不会当你是白鼠的,当青蛙而已。  ...

希望论坛有更多像你这样乐于分享自己的作品并且把我们当青蛙的大神哈

出0入0汤圆

发表于 2018-1-27 11:15:52 | 显示全部楼层
如果用C++ ,写个模板类把
顺便加上零界接口

出870入263汤圆

 楼主| 发表于 2018-1-27 13:17:40 | 显示全部楼层
日日♂夜夜 发表于 2018-1-27 11:15
如果用C++ ,写个模板类把
顺便加上零界接口

我用的是Embedded C++不支持模板,是标准C++的子集。

出0入0汤圆

发表于 2018-1-27 15:04:06 | 显示全部楼层
armstrong 发表于 2018-1-27 13:17
我用的是Embedded C++不支持模板,是标准C++的子集。

这...不会吧,stl都没有么..那用这个C++干啥..
还不如写C算了

出0入0汤圆

发表于 2018-1-27 20:32:11 | 显示全部楼层
C++ STL容器类强大多了,这个是标准库,换GCC吧,不要用假的C++了

出300入477汤圆

发表于 2018-1-27 21:00:31 来自手机 | 显示全部楼层
日日♂夜夜 发表于 2018-1-27 15:04
这...不会吧,stl都没有么..那用这个C++干啥..
还不如写C算了

stl并不是线程安全的。
其实只当作带类的c,己经比纯c好多了

出100入101汤圆

发表于 2018-1-28 14:12:43 | 显示全部楼层
armstrong 发表于 2018-1-25 20:50
我说说本代码的关键优点吧:如果有两个线程访问该FIFO(包括前后台系统的主循环和中断之间),一个读,一个 ...

不需要互斥保护,能普及下原因么?

出0入0汤圆

发表于 2018-1-28 14:21:12 来自手机 | 显示全部楼层
感谢楼主分享

出0入0汤圆

发表于 2018-1-28 17:03:03 来自手机 | 显示全部楼层
fengyunyu 发表于 2018-1-28 14:12
不需要互斥保护,能普及下原因么?

猜测一下,是不是没有并发的读取或者并发写入的原因呢?

出0入0汤圆

发表于 2018-9-11 09:36:07 | 显示全部楼层
谢谢分享

出870入263汤圆

 楼主| 发表于 2019-12-9 10:32:10 | 显示全部楼层
hexenzhou 发表于 2018-1-27 20:32
C++ STL容器类强大多了,这个是标准库,换GCC吧,不要用假的C++了

今天用了STL的queue了,发现它push加入条目,用的是动态分配内存,而且pop之后内存还不归还,这不适合在小内存单片机上用的。
单片机上通常容器的条目数可预测,也不要频繁new/malloc操作,所以还是自己实现的fifo更适用。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 14:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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