您的位置:首页 > Web前端

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

2014-05-26 20:14 393 查看
分类: C++是促进脑死亡的最佳方式2010-02-27 22:57 4150人阅读 评论(6) 收藏 举报
bufferdeletelinkerlistnull服务器

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_

【本文作者是fullsail(雁渡寒潭),本着自由的精神,你可以在无盈利的情况完整转载此文档,转载时请附上BLOG链接:http://blog.csdn.net/fullsail,否则每字一元不讲价。】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: