编程百科全书

在这里,相信会找到令你尖叫的文章!

导航

环形缓冲区,魔戒lordrings,boost的circular_buffer

2月要过去,这个月几乎一点东西没有写,不想懒惰一个月,但有没有什么特别值得写的东西。所以翻了翻存货,抖抖尘土,找了这篇出来。

这个文章Linker看见标题会笑的,呵呵,因为他在2007年就写过一篇类似的文章《环形缓冲区的实现》。但其实我的作品应该早于他的,我的当时作品名字是cycdeuque.Linker当时刺激我的不止他的文章,还有他的类名字,ring。比我的酷了很多。于是把我的实现名字改成了魔戒lordrings。感觉爽了一点,后来稍微浏览了Boost,发现Boost也有类似的实现circular_buffer。

其实也许就是英雄所见略同。

给大家解释一下为啥要有类似的实现,写服务器的代码时,为了减少内存的分配,我们很多时候需要一个池子,讲需要分配的资源先new出来,放在池子里面。这个池子的总长度(容量)应该是大部分时候是固定,

表面看来,这种要求用std::list实现最简单,list可以在开始和结尾的地方增加删除。但你会发现,如果使用std::list作为池子,性能会是你很头疼的一个东西,std::list分配一个加入一个对象,或者释放一个对象,可能都会对应一次new,delete操作。如果这样的操作频繁,std::list就会成为效率的瓶颈。我的一个通讯程序,接受和发送的buffer都考虑用一个池子,而每一个链接的发送数据,也会考虑放在一个池子里面。开始我就是用的list,后来用Oprofile,测试发现了这个问题。我就考虑要换容器实现。于是就有了这个lordrings。后来发现服务器所有需要池子的地方,都可以用这个魔戒解决问题。

看了一下Boost的设计实现circular_buffer提供的接口,以及代码。circular_buffer和我的设计思路几乎一致。使用一个内存数据区作为数据存放区,可以在开始位置和结束位置进行插入和删除操作,开始和,结束位置的指针可以变化,通过模除保证队列可以循环;长度可以扩展;如果队列已经满了,提供插入的时候提供是否覆盖的选择。

                                                                                                                               图1 BOOST的circular_buffer的设计实现图

不同的地方大约有2点,第一点是circular_buffer的实现完全符合stl的规范,包括分配器,和迭代器等,而我的实现省去了这些东西,我在内部实现了头部尾部的增加,删除,也实现了任意位置的[]方法。第二点是我的lordrings使用了一个小技巧记录区分数据区是空还是满,就是增加一个数据的空间,当记录开始位置的指针等于结束位置的指针的时候表示空,当开始位置和结束位置相差1的时候表示满。而BOOST的circular_buffer增加了一个记录尺寸的变量。现在默默感觉了一下,BOOST的这个方法比较我的要好一点,估计我当时写的时候被自己的内存PIPE设计影响了。

最后把代码贴出来,写的时候在听张楚的姐姐,当时对模板的感觉已经开始入门了。大致进入了侯捷所说的第3个阶段吧。哈哈。

/******************************************************************************************

Copyright           : 2000-2004,FXL.

FileName            :

Author              : Sail(ZENGXING)//Author name here

Version             :

Date Of Creation    : 2006年3月11日

Description         : 一个循环的DEQUE,可以控制在数据满的情况下,是否覆盖

Others              : 原来取名cyc_deque,但是一天和Linker聊天他说说他写的类似的类名字是rings,我觉得这个

                        名字比较酷,所以选择这个名字,越来越觉得这个类好用。

Function List       :

1.  ......

Modification History:

1.Date  :

Author  :

Modification  :

喔姐姐,我想回家,牵着我的手,我有些困了

******************************************************************************************/

#ifndef _ZEN_EXTEND_STD_CYC_DEQUE_H_

#define _ZEN_EXTEND_STD_CYC_DEQUE_H_

namespace zenlib

{

template<class _value_type >

class lordrings

{

protected:

    //循环队列的起始位置

    size_t                cycdeque_start_;

    //循环队列的结束位置,注意我使用的是前开后闭

    size_t                cycdeque_end_;

    //队列的长度,使队列的容量+1

    size_t                cycdeque_len_;

    //存放数据的指针

    _value_type           *value_ptr_;

public:

    //构造函数,后面必须调用,initialize

    lordrings():

        cycdeque_start_(0),

        cycdeque_end_(cycdeque_start_),

        cycdeque_len_(1),

        value_ptr_(NULL)

    {

    }

   

    //构造函数,后面完全没有必要调用,initialize

    //因为要形成一个前闭后开的空间,所以cycdeque_len_比实际要求的数据长度+1

    lordrings(size_t data_len):

        cycdeque_start_(0),

        cycdeque_end_(cycdeque_start_),

        cycdeque_len_(data_len+1),

        value_ptr_(NULL)

    {

        assert(data_len > 0);

        value_ptr_ = new _value_type[cycdeque_len_];

    }

    ~lordrings()

    {

        if(value_ptr_)

        {

            delete[] value_ptr_;

            value_ptr_ = NULL;

        }

    }

   

    //因为要形成一个前闭后开的空间,所以cycdeque_len_比实际要求的数据长度+1

    void initialize(size_t data_len)

    {

        assert(data_len > 0);

        cycdeque_start_ =0;

        cycdeque_end_ = cycdeque_start_;

        cycdeque_len_ = data_len+1;

        //清理现场

        if(value_ptr_)

        {

            delete[] value_ptr_;

            value_ptr_ = NULL;

        }

        value_ptr_ = new _value_type[cycdeque_len_];

    }

    //

    void finit()

    {

        cycdeque_start_ = 0;

        cycdeque_end_ = cycdeque_start_;

        cycdeque_len_ = 1;

        //清理现场

        if(value_ptr_)

        {

            delete[] value_ptr_;

            value_ptr_ = NULL;

        }

    }

    //重新

    void clear()

    {

        cycdeque_start_ =0;

        cycdeque_end_ = cycdeque_start_;

    }

       

    //尺寸空间

    inline size_t size() const

    {

        //

        if ( cycdeque_end_ >= cycdeque_start_ )

        {

            return cycdeque_end_ - cycdeque_start_ ;

        }

        else

        {

            return cycdeque_end_+cycdeque_len_ -cycdeque_start_ ;

        }

    }

    //返回空闲空间的大小

    inline size_t freesize() const

    {

        return cycdeque_len_ -size() -1;

    }

    //返回队列的容量

    inline size_t capacity() const

    {

        return cycdeque_len_ -1;

    }

    //检查是否已经满了

    inline bool full() const

    {

        //如果结束+1%

        if((cycdeque_end_ + 1)%cycdeque_len_ ==cycdeque_start_)

        {

            return true;

        }

        return false;

    }

    //判断队列是否为空

    inline bool empty() const

    {

        //如果发现开始==结束

        if(cycdeque_start_ == cycdeque_end_)

        {

            return true;

        }

        return false;

    }

    //重新分配一个空间,

    bool resize(size_t new_size)

    {

        assert(new_size > 0);

        size_t deque_size = size();

        //如果原来的尺寸大于新的尺寸,无法扩展

        if( deque_size > new_size )

        {

            return false;

        }

        _value_type *new_value_ptr = new _value_type[new_size+1];

        //调整几个内部参数

        cycdeque_start_ =0;

        cycdeque_end_ = deque_size;

        cycdeque_len_ = new_size+1;

       

        //如果原来有数据

        if(value_ptr_ != NULL)

        {

            for (size_t i=0;i<deque_size;++i)

            {

                new_value_ptr[i] = value_ptr_[(cycdeque_start_+i)%cycdeque_len_];

            }

            delete[] value_ptr_;

            value_ptr_ = NULL;

        }

        value_ptr_ = new_value_ptr;

        return true;

    }

    //将一个数据放入队列的尾部,如果队列已经满了,你可以将lay_over参数置位true,覆盖原有的数据

    bool push_back(const _value_type &value_data,bool lay_over =false)

    {  

        //

        if((cycdeque_end_ + 1)%cycdeque_len_ ==cycdeque_start_ )

        {

            //如果不要覆盖,返回错误

            if(lay_over == false)

            {

                return false;

            }

            //如果要覆盖

            else

            {

                //将最后一个位置覆盖,并且调整起始和结束位置

                value_ptr_[cycdeque_end_] = value_data;

                cycdeque_start_ = (cycdeque_start_ +1 ) % cycdeque_len_;

                cycdeque_end_ = (cycdeque_end_+1) % cycdeque_len_;

                return true;

            }

        }

        //

        value_ptr_[cycdeque_end_] = value_data;

        cycdeque_end_ = (cycdeque_end_+1) % cycdeque_len_;

        return true;

    }

    //从队列的前面得到一个数据

    bool pop_front(_value_type &value_data)

    {

        //

        if (size() == 0)

        {

            return false;

        }

        value_data = value_ptr_[cycdeque_start_];

        cycdeque_start_ = (cycdeque_start_ +1 ) % cycdeque_len_;

        return true;

    }

    bool pop_front()

    {

        //

        if (size() == 0)

        {

            return false;

        }

        cycdeque_start_ = (cycdeque_start_ +1 ) % cycdeque_len_;

        return true;

    }

    //从队列的前面得到一个数据

    bool pop_end(_value_type &value_data)

    {

        //

        if (size() == 0)

        {

            return false;

        }

        cycdeque_end_ = (cycdeque_end_ > 0)?cycdeque_end_-1:cycdeque_len_-1;

        value_data = value_ptr_[cycdeque_end_];

       

        return true;

    }

    bool pop_end()

    {

        //

        if (size() == 0)

        {

            return false;

        }

        cycdeque_end_ = (cycdeque_end_ > 0)?cycdeque_end_-1:cycdeque_len_-1;

        return true;

    }

   

    //ID不要越界,自己保证,我没兴趣为你干什么

    _value_type& operator[](size_t id)

    {

        return value_ptr_[(cycdeque_start_ + id) % cycdeque_len_];

    }

   

    

};

};

#endif //#ifndef _ZEN_EXTEND_STD_CYC_DEQUE_H_

posted on 2011-02-24 13:10  天天编程  阅读(620)  评论(0编辑  收藏  举报