环形缓冲区有的地方也称之为环形队列。其实很多人都搞不懂环形缓冲区的本质,从而也就不知道在什么场景下应该使用环形缓冲区。当你了解了它的本质你就知道这玩意儿一点都不高级,而且由于它的本质在某些场景下还不能使用。我看了很多网络游戏服务器的源代码,有些源代码中大量使用这玩意儿。比如我打个比方:
在游戏服务器端只要接收到一个来自客户端的连接就生成一个ClientSocket对象来管理和客户端的数据通信。然后在ClientSocket中有一个环形缓冲区对象CircularBuffer对象来存储客户端发往服务器的字节流数据。仔细想想这种情况下有必要使用CircularBuffer对象么?其实用一个普通的字节数组就足够了,因为,ClientSocket只会调用WSARecv(buffer)一次,然后服务器端IOCP底层收到数据并把数据存放到buffer中之后,唤醒一个工作者线程去让ClientSocket对象处理这个buffer中的数据,然后再次调用WSARecv(buffer)来接受下一次数据。仔细想想,整个过程就是一个生产者对应一个消费者,而且是先生产后消费的过程。用一个buffer[8192]的普通缓冲区完全足够了。而且理解方便,便于代码阅读,用那个环形缓冲区简直就是完全没必要。什么?我上面讲的你还不能完全理解?好吧,先讲讲环形缓冲区的本质。
环形缓冲区的本质:把一个缓冲区当成一个圆形的结构,这样当从里面读取数据和插入数据的时候,都不能重新释放空间和重新分配空间,否则怎么可能是圆形的结构呢?对 吧!!!所以他的好处自然就浮现在眼前了:整个软件声明周期都是使用的这个环形缓冲区不用重新释放和分配空间,这样节省了时间提高了效率。当然缺点也浮现在眼前了:
由于对环形缓冲区的空间大小是最开始就定义好的,如果这个大小估计不准确,太大的话浪费空间,太小的话,呵呵,就得重新分配空间装下新的数据,这就和普通缓冲区没区别了。所以,其实环形缓冲区在服务器编程中的大部分情况下都是很少使用的。
所以:只有当存储空间的分配/释放非常频繁 并且确实产生了明显 的影响,你才应该考虑环形缓冲区的使用。否则的话,还是老老实实用最基本、最简单的队列缓冲区 吧。
注意:环形缓冲区一般都是非线程安全的。网上有些无锁的环形缓冲区,但是本人没在项目中正式运用过,不知道是否是真的,在篇末我会给出一个无锁队列的链接,有兴趣的可以研究一下。
一般的环形缓冲区长这个样子:
看上面的图,当前head指向0这个位置,当数据不断填入,填充到11这个位置的时候数据再往后面填,就会覆盖0和0后面的数据。为了解决这个问题就 要判断head和tail指针,在实际使用中,当tail位于head的前面,计算剩余空间等问题上是很麻烦的,所以,网络上的某一位大神在此技术上运用了一个很简单的思路,来解决这个问题。这位大神的技术文章地址是:http://www.codeproject.com/Articles/3479/The-Bip-Buffer-The-Circular-Buffer-with-a-Twist 魔兽世界的私服服务器Ascent中的环形缓冲区就产生自这位大神的思路。这位大神把优化过后的circluar_buffer改名为Bip Buffer.说实话,翻译出来真的很蹩脚。shit~~~~~~
Bip Buffer:
4.http://blog.csdn.net/program_think/article/details/4040068