One must be able to handle the case where the queue is full and there is still incoming data. This case is known as the overflow condition. There are two methods which handle this case. They are to drop the latest data or to overwrite the oldest data. Either style may be implemented. In our case, I will use the drop latest incoming data method.
当数据缓存区已经满了,但是数据还在不停的接收,怎么办? 溢出了,通常两种方法来处理而非解决,要么覆盖旧数据,要么丢掉新数据,本文决定使用丢掉新数据的模式(可怜)。
In this very specific software queue implementation, I shall use the KISS principle to implement a very simple ring buffer queue. The basic purpose here is to create a queue which can handle a stream of bytes into a fixed buffer for the single process to single process use case. This type of ring buffer is very handy to have for a simple buffered serial device. The design features for this simple queue is as follows:
在这个需要特别设计的序列实现方法上,就用最简原则("Keep it simple, stupid")来做一个环形缓冲序列。最基本的目标是实现一个用于单轨至单轨的数据流固定缓冲区。这种类型的缓存设计对于串行设备的数据序列化最合适不过了。设计流程如下:
1. The buffer will contain a fixed number of bytes. This number of bytes will be set by a macro definition in the header file.
头文件中用宏定义固定字节数的缓存。
2. The overflow condition will be managed via the drop latest information process. This means in the event of an overflow, the latest incoming data will be dropped.
在数据发生溢出时,采用丢弃最新数据的方式进行处理。
Given these features leads us to our first listing. Again, the 1st listing (Listing 1) is the main ring buffer header file. This file defines all the interfaces and attributes required for our very simple ring buffer implementation.
首先就是头文件中的接口与属性的定义,后面的程序部分就不翻译了。
Listing 1. The interfaces and attributes for a simple ring buffer object.
#ifndef __RINGBUFS_H
#define __RINGBUFS_H
#define RBUF_SIZE 256
typedef struct ringBufS
{
unsigned char buf[RBUF_SIZE];
int head;
int tail;
int count;
} ringBufS;
#ifdef __cplusplus
extern "C" {
#endif
void ringBufS_init (ringBufS *_this);
int ringBufS_empty (ringBufS *_this);
int ringBufS_full (ringBufS *_this);
int ringBufS_get (ringBufS *_this);
void ringBufS_put (ringBufS *_this, const unsigned char c);
void ringBufS_flush (ringBufS *_this, const int clearBuffer);
#ifdef __cplusplus
}
#endif
#endif
The simple ring buffer record
Inspection of Listing 1 shows very little is required to implement the simple ring buffer. Also, the buffer size is fixed via the RBUF_SIZE macro, which in this case happens to be 256 bytes. The following is a list of what is contained within the ringBufS record.
buf[]缓存区
This is the managed buffer. The size of this buffer is set by the RBUF_SIZE macro. In our case, we are managing a 256 byte buffer of unsigned characters.
head头指示
This is the head index. The incoming bytes get written to the managed buffer using this index. The arithmetic for this index is in modulo-256. This is because the RBUF_SIZE macro is defined as 256. Of course, if we defined a different value for the buffer size then the modulus arithmetic will change accordingly.
tail尾指示
This index is used to retrieve the oldest data in the queue. This index also follows the same modulus arithmetic as in the HEAD index case.
count已记录字节个数
This field is used to keep track of the total number of elements currently in the queue. The maximum value of this field is set by the RBUF_SIZE macro.
The simple ring buffer methods实现函数
There are six(6) methods for the simple unsigned character ring buffer. A brief description of these methods is shown in Table 1.
![](http://m.eet.com/media/1195743/0713embWadaT01.png)
Table 1: The set of ring buffer queue methods.
ringBufS_init
Listing 2 shows the implementation of the simple ring buffer initialization process. In this case, we simply clear all of the object memory. This not only flushes the queue. It also clears the buffer too.
Listing 2: initializing the simple ring buffer.
#include <string.h>
#include "ringBufS.h"
void ringBufS_init (ringBufS *_this)
{
/*****
The following clears:
-> buf
-> head
-> tail
-> count
and sets head = tail
***/
memset (_this, 0, sizeof (*_this));
}
ringBufS_empty
Listing 3 shows the implementation for checking the empty status of the queue. In this case we just check to see whether or not the count field is zero.
Listing 3. Testing the queue empty condition.
#include "ringBufS.h"
int ringBufS_empty (ringBufS *_this)
{
return (0==_this->count);
}
ringBufS_full
Of course, we also need to check the queue full condition. Listing 4 shows that this is simply a check of the count field against the buffer size.
Listing 4. Testing the queue full condition
.
#include "ringBufS.h"
int ringBufS_full (ringBufS *_this)
{
return (_this->count>=RBUF_SIZE);
}
ringBufS_get
In Listing 5 we get a byte from the queue. Notice that the return value in this method is an integer. We use the value of -1 to signal that an attempt was made to retrieve a value from an empty queue.
We introduce the
modulo_inc()
method here. This method encapsulates the modulus arithmetic required for updating the buffer indices.
Listing 5. Getting a byte from the queue.
#include "modulo.h"
#include "ringBufS.h"
int ringBufS_get (ringBufS *_this)
{
int c;
if (_this->count>0)
{
c = _this->buf[_this->tail];
_this->tail = modulo_inc (_this->tail, RBUF_SIZE);
--_this->count;
}
else
{
c = -1;
}
return (c);
}
ringBufS_put
Listing 6 shows how we put a byte to the queue. This listing shows the incoming byte is dropped if the queue is full.
Listing 6. Placing the data into the queue.
#include "modulo.h"
#include "ringBufS.h"
void ringBufS_put (ringBufS *_this, const unsigned char c)
{
if (_this->count < RBUF_SIZE)
{
_this->buf[_this->head] = c;
_this->head = modulo_inc (_this->head, RBUF_SIZE);
++_this->count;
}
}
ringBufS_flush
Listing 7 shows how to flush the queue. In this case we set the count and the indices to zero. We can optionally clear the buffer to zero (0) if required. In some cases this may be useful for diagnostics purposes.
Listing 7. Flushing the queue.
#include <string.h>
#include "ringBufS.h"
void ringBufS_flush (ringBufS *_this, const int clearBuffer)
{
_this->count = 0;
_this->head = 0;
_this->tail = 0;
if (clearBuffer)
{
memset (_this->buf, 0, sizeof (_this->buf));
}
}
#include "modulo.h"
/****************************************************************************/
/* CODE STARTS HERE */
/****************************************************************************/
unsigned int modulo_inc (const unsigned int value, const unsigned int modulus)
{
unsigned int my_value = value + 1;
if (my_value >= modulus)
{
my_value = 0;
}
return (my_value);
}
unsigned int modulo_dec (const unsigned int value, const unsigned int modulus)
{
unsigned int my_value = (0==value) ? (modulus - 1) : (value - 1);
return (my_value);
}