一:概述

实际学习和工作中,我们经常会遇到读写大量数据的情况,这个时候我们可能就用到了循环缓冲区。

循环缓冲区在处理大量数据的时候有很大的优点,循环缓冲区在一些竞争问题上提供了一种免锁的机制,免锁的前提是,生产者和消费都只有一个的情况下,否则也要加锁。

二:循环缓冲区的实现理论如下图

三:实现代码如下所示:

  1. //CRecycleQueue.h
  2.  
  3. #include<iostream>
  4.  
  5. //循环缓冲区类模板
  6. template<class T>
  7. class CRecycleQueue{
  8.  
  9. private:
  10. //循环缓冲区地址指针
  11. T **_queue;
  12. //循环缓冲区读游标 (读的位置)
  13. int _read;
  14. //循环缓冲区写游标 (写的位置)
  15. int _write;
  16. //循环缓冲区的大小
  17. int _size;
  18. //我们姑且称这个变量为掩码,接下来用来作位&运算,从而实现循环缓冲
  19. int _mask;
  20.  
  21. public:
  22. CRecycleQueue(){
  23. _queue = NULL;
  24. _read = ;
  25. _write = ;
  26. _size = ;
  27. _mask = ;
  28. }
  29. //初始化循环缓冲区
  30. bool InitRecycleQueue(int exp){
  31.  
  32. if( > exp){
  33.  
  34. return false;
  35. }
  36.  
  37. _read = ;
  38. _write = ;
  39. //传进来一个整数,对1进行位移操作
  40. //比如exp = 4
  41. //_size的二进制表示:1000
  42. _size = << exp;
  43. //_mask的二进制表示:0111
  44. _mask = _size - ;
  45. //分配缓冲区空间
  46. _queue = (T **)new char[sizeof (T *) * _size];
  47.  
  48. if(NULL == _queue){
  49.  
  50. return false;
  51. }
  52.  
  53. return true;
  54. }
  55. /*
  56. * size = 1000 mask = 0111
  57. * write或read同mask 作&运算,可以实现循环缓冲区的功能
  58. * 也许你会问这里为什么不使用 % 运算实现循环的循环功能呢?
  59. * 答案是系统 & 运算效率要比 % 运算效率高
  60. *
  61. * Push:
  62. * write = 0;
  63. * 0000 & 0111 = 0; write++ (写入缓冲队列的第0位置)
  64. * write = 1;
  65. * 0001 & 0111 = 1; write++ (写入缓冲队列的第1位置)
  66. * write = 2;
  67. * 0010 & 0111 = 2; write++
  68. * write = 3;
  69. * 0011 & 0111 = 3; write++
  70. * ...
  71. * write = 8;
  72. * 1000 & 0111 = 0; write++
  73. * write = 9;
  74. * 1001 & 0111 = 1; write++
  75. * ...
  76. *
  77. * Pop:
  78. * read = 0;
  79. * 0000 & 0111 = 0; read++ (读取缓冲队列的第0位置的数据)
  80. * read = 1;
  81. * 0001 & 0111 = 1; read++ (读取缓冲队列的第1位置的数据)
  82. * read = 2;
  83. * 0010 & 0111 = 2; read++
  84. * read = 3
  85. * 0011 & 0111 = 3; read++
  86. * ...
  87. * read = 8;
  88. * 1000 & 0111 = 0; read++
  89. * ...
  90. * */
  91.  
  92. bool Push(T *type){
  93.  
  94. if(NULL == type){
  95.  
  96. return false;
  97. }
  98. //当条件不满足的时候,说明缓冲区已满,Push进来的数据就会丢失
  99. if(_write < _read + _size){
  100. //我们这里存入的是type指针,这个指针指向了一个我们分配的内存空间或者类
  101. _queue[_write & _mask] = type;
  102. _write++;
  103. return true;
  104. }
  105.  
  106. return false;
  107. }
  108.  
  109. T *Pop(){
  110.  
  111. T *tmp = NULL;
  112. //当条件不满足的时候说明缓冲区已经没有数据
  113. if(_read < _write){
  114. //取出队列的数据
  115. tmp = _queue[_read & _mask];
  116. _read++;
  117. }
  118.  
  119. return tmp;
  120. }
  121.  
  122. int GetRemainSize(){
  123.  
  124. return (_write - _read);
  125. }
  126. };

下面是简单的测试代码:

  1. //main.cpp
  2.  
  3. #include <iostream>
  4. #include <pthread.h>
  5. #include "CRecycleQueue.h"
  6. using namespace std;
  7.  
  8. class UserInfo{
  9.  
  10. private :
  11. int _num;
  12.  
  13. public:
  14. UserInfo(int num){
  15.  
  16. _num = num;
  17. }
  18.  
  19. int getUserNum(){
  20.  
  21. return _num;
  22. }
  23. };
  24.  
  25. CRecycleQueue<UserInfo> *queue = new CRecycleQueue<UserInfo>;
  26.  
  27. void *write_func(void *args){
  28.  
  29. int num = ;
  30. while(){
  31.  
  32. //UserInfo里可以封装你自己想要的数据
  33. //这里仅仅是一个简单的测试用例
  34. UserInfo *info = new UserInfo(num++);
  35.  
  36. if(!queue->Push(info)){
  37. //Push失败 删除手动分配的内存空间
  38. delete info;
  39. }
  40. sleep();
  41. }
  42. }
  43.  
  44. void *read_func(void *args){
  45.  
  46. while(){
  47.  
  48. UserInfo *info = NULL;
  49. if(info = queue->Pop()){
  50.  
  51. cout<<info->getUserNum()<<endl;
  52. delete info;
  53. }
  54. sleep();
  55. }
  56. }
  57. int
  58. main(){
  59.  
  60. queue->InitRecycleQueue();
  61.  
  62. pthread_t pid1;
  63. pthread_t pid2;
  64. //这种生产者和消费者都只有一个的情况下,这个循环缓冲区为竞争问题提供了免锁,大大提高了程序的处理效率
  65. pthread_create(&pid1,NULL,read_func,NULL);
  66. pthread_create(&pid2,NULL,write_func,NULL);
  67.  
  68. pthread_join(pid1,NULL);
  69. pthread_join(pid2,NULL);
  70.  
  71. return ;
  72. }

编译:g++ main.cpp -lpthread -o test

这个循环缓冲队列大体的功能已经实现,其中循环缓冲队列一些其他操作并没有去实现,只是描述了一些核心的操作!

如果有错误和其他意见,提出来大家一起相互讨论和学习!

linux c++循环缓冲区模板类的更多相关文章

  1. 24小时学通Linux内核--内核探索工具类

    寒假闲下来了,可以尽情的做自己喜欢的事情,专心待在实验室里燥起来了,因为大二的时候接触过Linux,只是关于内核方面确实是不好懂,所以十天的时间里还是希望能够补充一下Linux内核相关知识,接下来继续 ...

  2. 单链表的C++实现(采用模板类)

    采用模板类实现的好处是,不用拘泥于特定的数据类型.就像活字印刷术,制定好模板,就可以批量印刷,比手抄要强多少倍! 此处不具体介绍泛型编程,还是着重叙述链表的定义和相关操作.  链表结构定义 定义单链表 ...

  3. C++11特性(模板类 initializer_list)

    [1]initializer_list模板类 C++primer 原文如下: 通读原文相关篇幅,分析解读内容如下: 提供initializer_list类的初衷,为了便于将有限个同一类型(或可转换为同 ...

  4. 高效的两段式循环缓冲区──BipBuffer

    Simon Cooke,美国 (原作者) 北京理工大学 20981 陈罡(翻译) 写在前面的话: 循环缓冲区是一个非常常用的数据存储结构,已经被广泛地用于连续.流数据的存储和通信应用中.对于循环缓冲区 ...

  5. 7.2 C++模板类实例化

    参考:http://www.weixueyuan.net/view/6399.html 总结: array < int >表明用int类型来代替模板类中的类参数“T”,编译器会将模板类ar ...

  6. C++模板类练习题

    题目说明: 编写一个程序,使用类模板对数组元素进行排序,倒置.查找和求和 具有对数组元素进行排序,倒置.查找和求和功能, 然后产生类型实参分别为int型和double型的两个模板类, 分别对整型数组与 ...

  7. 027_编写MapReduce的模板类Mapper、Reducer和Driver

    模板类编写好后写MapReduce程序,的模板类编写好以后只需要改参数就行了,代码如下: package org.dragon.hadoop.mr.module; import java.io.IOE ...

  8. 学艺不精而惭愧--论C++模板类的使用

    自己断断续续地使用C++也有一段时间了.有些时候产生了自满的情绪.觉得自己对C++的语言特性已经知道的几乎相同了,在语法方面没有什么难倒我的地方了,如今所要做的是依据实际问题编敲代码,问题的难点在于算 ...

  9. 模板类 error LNK2019: 无法解析的外部符号

    如果将类模板的声明和实现写在两个独立的文件中,在构建时会出现"error LNK2019: 无法解析的外部符号 "的错误. 解决方法有: 第一种方法,就是把类模板中成员函数的声明和 ...

随机推荐

  1. 使用Linux碎解一

    一.安装VMwarestation. 二.安装Linux系统(这里是CentOS7) 步骤: #==========================part1===================== ...

  2. js中原型继承的概念

  3. 关于使用READ TABLE语句的几点注意事项

    原文地址   http://www.dlsap.com/thread-34-1-1.html 1.  如果使用READ TABLE语句来读取内部表数据,而不是简单看返回值判断是否存在,那么在使用REA ...

  4. 签名 cd

    http://blog.sina.com.cn/s/blog_618199e60101uc7w.html

  5. js算出生日是当年第多少天

    var year, month, day, monthSum = 0; var arr = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, ...

  6. js鼠标经过文字滚动,移开还原

    不说别的,直接贴代码. <div class="kj-scroll" id="countrylist0" onmouseover="wPAa = ...

  7. MYSQL-5.5二进制包安装

    groupadd mysql 添加用户组 useradd mysql -s /sbin/nologin -g mysql -M  添加用户 mv mysql-5.5.54-linux2.6-x86_6 ...

  8. js中常用的操作

    1.js中常用的数组操作 2.js中常用的字符串操作 3.js中常用的时间日期操作 4.定时器

  9. Java C# C语言中的占位符

    一般拼接一段字符串在编程中是很常见的事,下面简单做个总结: 什么是占位符?占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号. 1.Java中处理方法: package com.amos; ...

  10. Android开发学习---android下的数据持久化,保存数据到rom文件,android_data目录下文件访问的权限控制

    一.需求 做一个类似QQ登录似的app,将数据写到ROM文件里,并对数据进行回显. 二.截图 登录界面: 文件浏览器,查看文件的保存路径:/data/data/com.amos.datasave/fi ...