• linux c++循环缓冲区模板类


    一:概述

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

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

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

    三:实现代码如下所示:

    //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 = 0;
                _write = 0;
                _size = 0;
                _mask = 0;
            }
            //初始化循环缓冲区
            bool InitRecycleQueue(int exp){
                
                if(0 > exp){
    
                    return false;
                }
    
                _read = 0;
                _write = 0;
                //传进来一个整数,对1进行位移操作
                //比如exp = 4
                //_size的二进制表示:1000
                _size = 1 << exp;
                //_mask的二进制表示:0111
                _mask = _size - 1;
                //分配缓冲区空间
                _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 = 0;
        while(1){
    
            //UserInfo里可以封装你自己想要的数据
            //这里仅仅是一个简单的测试用例    
            UserInfo *info = new UserInfo(num++);
    
            if(!queue->Push(info)){
                //Push失败 删除手动分配的内存空间    
                delete info;
            }
            sleep(1);
        }
    }
    
    void *read_func(void *args){
    
        while(1){
    
            UserInfo *info = NULL;
            if(info = queue->Pop()){
    
                cout<<info->getUserNum()<<endl;
                delete info;
            }
            sleep(1);
        }
    }
    int 
    main(){
    
        queue->InitRecycleQueue(8);
    
        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 0;
    }

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

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

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

  • 相关阅读:
    语录
    Python 自动化Web测试
    HTTP监视网络
    网络端口的转发和重定向
    [翻译]对为Microsoft Robotics Studio的设计做贡献感兴趣?
    [翻译]谈话记录:介绍Microsoft Robotics Studio
    [视频]名家讲坛ASP.NET之父Scott Guthrie[上海站]
    如何使用AJAX RoundedCorners Extender控件(视频字幕)
    给SlideShowExtender增加链接
    delphi7调用c#写的webservice(.net2.0)
  • 原文地址:https://www.cnblogs.com/program-framework/p/4679052.html
Copyright © 2020-2023  润新知