A circular buffer, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams.
The useful property of a circular buffer is that it does not need to have its elements shuffled around [重新排列]when one is consumed. (If a non-circular buffer were used then it would be necessary to shift all elements when one is consumed.) In other words, the circular buffer is well-suited[非常合适] as a FIFO [先进先出]buffer while a standard, non-circular buffer is well suited as a LIFO [后进后出]buffer.
Circular buffering makes a good implementation strategy for a queue that has fixed maximum size. Should a maximum size be adopted [被采用]for a queue, then a circular buffer is a completely ideal implementation; all queue operations are constant time. However, expanding a circular buffer requires shifting memory, which is comparatively[相对来说] costly. For arbitrarily expanding queues[可随意扩展的], a linked list approach[链表] may be preferred instead.
[本文作者franklin注解]环形buffer 应用于固定的块场合,一旦固定,这块内存就是专用,所以,不具备扩展性.
In some situations, overwriting [可覆盖性]circular buffer can be used, e.g. in multimedia. If the buffer is used as the bounded [有界性,有限制] buffer in the producer-consumer problem then it is probably desired for the producer (e.g., an audio generator) to overwrite old data if the consumer (e.g., the sound card) is unable to momentarily keep up. Also, the LZ77 family of lossless data compression algorithms operates on the assumption that strings seen more recently in a data stream are more likely to occur soon in the stream. Implementations store the most recent data in a circular buffer.
A circular buffer first starts empty and of some predefined length. For example, this is a 7-element buffer:
Assume that a 1 is written into the middle of the buffer (exact starting location does not matter in a circular buffer):
Then assume that two more elements are added — 2 & 3 — which get appended after the 1:
If two elements are then removed from the buffer, the oldest values inside the buffer are removed. The two elements removed, in this case, are 1 & 2, leaving the buffer with just a 3:
If the buffer has 7 elements then it is completely full:
A consequence of the circular buffer is that when it is full and a subsequent write is performed, then it starts overwriting the oldest data. In this case, two more elements — A & B — are added and they overwrite the 3 & 4:
[本文作者franklin注解][当环形buffer满的时候,后续写入数据将覆盖前面数据]
Alternatively[或者], the routines that manage the buffer could prevent overwriting the data and return an error or raise[根本就是设计成不能写入] an exception. Whether or not data is overwritten is up to the semantics of the buffer routines or the application using the circular buffer.
Finally, if two elements are now removed then what would be returned is not 3 & 4 but 5 & 6 because A & B overwrote the 3 & the 4 yielding the buffer with:
What is not shown in the example above is the mechanics of how the circular buffer is managed.
Generally, a circular buffer requires four pointers:
Alternatively[或者], a fixed-length buffer with two integers to keep track of indices can be used in languages that do not have pointers.
[没有指针也可以的]
Taking a couple of examples from above. (While there are numerous[庞大的] ways to label the pointers and exact semantics[精确到语意]can vary, this is one way to do it.)
This image shows a partially[部分] full buffer:
This image shows a full buffer with two elements having been overwritten:
What to note about the second one is that after each element is overwritten then the start pointer is incremented as well.
A small disadvantage of relying on pointers or relative indices of the start and end of data is, that in the case the buffer is entirely full, both pointers point to the same element:
This is exactly the same situation as when the buffer is empty:
[最常见的问题是,buffer的满和空的判别]
To solve this confusion there are a number of solutions:
This design always keeps one slot unallocated. A full buffer has at most slots. If both pointers refer to the same slot, the buffer is empty. If the end (write) pointer refers to the slot preceding the one referred to by the start (read) pointer, the buffer is full.
The advantage is:
The disadvantages are:
ref:
http://en.wikipedia.org/wiki/Circular_buffer
http://lmax-exchange.github.io/disruptor/
http://www.cnblogs.com/shanyou/archive/2013/02/04/2891300.html