一:概述

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

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

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

三:实现代码如下所示:

//CRecycleQueue.h

#include<iostream>

//循环缓冲区类模板
template<class T>
class CRecycleQueue{ private:
//循环缓冲区地址指针
T **_queue;
//循环缓冲区读游标 (读的位置)
int _read;
//循环缓冲区写游标 (写的位置)
int _write;
//循环缓冲区的大小
int _size;
//我们姑且称这个变量为掩码,接下来用来作位&运算,从而实现循环缓冲
int _mask; public:
CRecycleQueue(){
_queue = NULL;
_read = ;
_write = ;
_size = ;
_mask = ;
}
//初始化循环缓冲区
bool InitRecycleQueue(int exp){ if( > exp){ return false;
} _read = ;
_write = ;
//传进来一个整数,对1进行位移操作
//比如exp = 4
//_size的二进制表示:1000
_size = << exp;
//_mask的二进制表示:0111
_mask = _size - ;
//分配缓冲区空间
_queue = (T **)new char[sizeof (T *) * _size]; if(NULL == _queue){ return false;
} return true;
}
/*
* size = 1000 mask = 0111
* write或read同mask 作&运算,可以实现循环缓冲区的功能
* 也许你会问这里为什么不使用 % 运算实现循环的循环功能呢?
* 答案是系统 & 运算效率要比 % 运算效率高
*
* Push:
* write = 0;
* 0000 & 0111 = 0; write++ (写入缓冲队列的第0位置)
* write = 1;
* 0001 & 0111 = 1; write++ (写入缓冲队列的第1位置)
* write = 2;
* 0010 & 0111 = 2; write++
* write = 3;
* 0011 & 0111 = 3; write++
* ...
* write = 8;
* 1000 & 0111 = 0; write++
* write = 9;
* 1001 & 0111 = 1; write++
* ...
*
* Pop:
* read = 0;
* 0000 & 0111 = 0; read++ (读取缓冲队列的第0位置的数据)
* read = 1;
* 0001 & 0111 = 1; read++ (读取缓冲队列的第1位置的数据)
* read = 2;
* 0010 & 0111 = 2; read++
* read = 3
* 0011 & 0111 = 3; read++
* ...
* read = 8;
* 1000 & 0111 = 0; read++
* ...
* */ bool Push(T *type){ if(NULL == type){ return false;
}
//当条件不满足的时候,说明缓冲区已满,Push进来的数据就会丢失
if(_write < _read + _size){
//我们这里存入的是type指针,这个指针指向了一个我们分配的内存空间或者类
_queue[_write & _mask] = type;
_write++;
return true;
} return false;
} T *Pop(){ T *tmp = NULL;
//当条件不满足的时候说明缓冲区已经没有数据
if(_read < _write){
//取出队列的数据
tmp = _queue[_read & _mask];
_read++;
} return tmp;
} int GetRemainSize(){ return (_write - _read);
}
};

下面是简单的测试代码:

//main.cpp

#include <iostream>
#include <pthread.h>
#include "CRecycleQueue.h"
using namespace std; class UserInfo{ private :
int _num; public:
UserInfo(int num){ _num = num;
} int getUserNum(){ return _num;
}
}; CRecycleQueue<UserInfo> *queue = new CRecycleQueue<UserInfo>; void *write_func(void *args){ int num = ;
while(){ //UserInfo里可以封装你自己想要的数据
//这里仅仅是一个简单的测试用例
UserInfo *info = new UserInfo(num++); if(!queue->Push(info)){
//Push失败 删除手动分配的内存空间
delete info;
}
sleep();
}
} void *read_func(void *args){ while(){ UserInfo *info = NULL;
if(info = queue->Pop()){ cout<<info->getUserNum()<<endl;
delete info;
}
sleep();
}
}
int
main(){ queue->InitRecycleQueue(); pthread_t pid1;
pthread_t pid2;
//这种生产者和消费者都只有一个的情况下,这个循环缓冲区为竞争问题提供了免锁,大大提高了程序的处理效率
pthread_create(&pid1,NULL,read_func,NULL);
pthread_create(&pid2,NULL,write_func,NULL); pthread_join(pid1,NULL);
pthread_join(pid2,NULL); return ;
}

编译: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. 完整的 mime type 列表

    原文地址:http://blog.csdn.net/zhaoyw2008/article/details/46647723 Suffixes applicable Media type and sub ...

  2. lua代码设置unity对象的基础属性

    设置对象的父节点: wall.transform:SetParent(GameObject.Find("Walls").transform) 设置颜色: wall:GetCompo ...

  3. 循序渐进Python3(十一) --3--  web之dom

    DOM                  文档对象模型(Document Object Model,DOM)是一种用于HTML和XML文档的编程接口.它给文档提供了一种结构化的表示方法,可以改变文档的 ...

  4. error-2015-9-9

    类型的建键部分无效,该键的所有部分均不可为null 映射从第行开始的片段时有问题 表的键具有潜在运行时冲突 列映射到概念端的属性 但是它们未形成entitySet的键属性 报错: 未能加载文件或程序集 ...

  5. Oracle中分区表的使用

       查询分区:Select *From user_extents WHERE partition_name='分区名'; 1)创建表空间 create tablespace HRPM0 datafi ...

  6. android虚拟机

    参考:http://baike.baidu.com/link?url=06bC3y5DSQ7DQ_QbEr6hTfMNpmg2f-39w6FpU69xxkbNoJ5OR4N9xCKoMwMMGTZfF ...

  7. Data import/export of Netezza using external table

    Introduction External table is a special table in Netezza system, which could be  used to import/exp ...

  8. Win10切换中英输入法问题

    用此方法解决后的效果: Win10系统只剩下"美式键盘"和"搜狗拼音"两种输入法,且默认为美式键盘. 按Ctrl+Shift切换到搜狗拼音,输入完成后,再按Ct ...

  9. java写入和写出EXCEL(含源代码)

    这两天帮老师做一个数据库,将所有实验交易的数据导入到数据库中,但是不想天天在实验室里面待着,气氛太压抑,就想着先把数据读进EXCEL中,哪天带到实验室导进去 数据原来是这样的,不同的实验有一个专门的文 ...

  10. Python3利用BeautifulSoup4批量抓取站点图片的代码

    边学边写代码,记录下来.这段代码用于批量抓取主站下所有子网页中符合特定尺寸要求的的图片文件,支持中断. 原理很简单:使用BeautifulSoup4分析网页,获取网页<a/>和<im ...