代码
/// 不要给下面代码长度吓到啊,因为些的测试用列的代码比较多,下面的CircleQueue代码还是不多的
///
/// author : jave.lin
/// date : 2017-12-28
///
static void Main(string[] args)
{
// 测试环形缓存
_testingCircleQueue();
}
#region 环形缓存队列
private static void _testingCircleQueue()
{
// 测试写入到满为止
//_testingWriteFull();
// 测试读取到空为止
//_testingReadEmpty();
// 测试读写平衡
//_testingWriteReadBalance();
// 批量测试写入到满为止
//_testingWriteFullRange();
// 批量测试读取到空为止
//_testingReadEmptyRange();
// 批量测试读写平衡
//_testingWriteReadBalanceRange();
var r = new Random();
var cq = new CircleQueue(10);
for (int i = 0, len = cq.len; i < len; ++i)
{
cq.write(r.Next(len));
}
Console.WriteLine("cq:" + cq);
var opBuff = new int[cq.len];
for (int i = 0, len = cq.len / 3; i < 3; ++i)
{
cq.readRange(opBuff, 0, len);
Console.WriteLine("opBuff:" + string.Join(",", opBuff));
Console.WriteLine("cq:" + cq);
}
cq.readRange(opBuff);
Console.WriteLine("opBuff:" + string.Join(",", opBuff));
Console.WriteLine("cq:" + cq);
Console.ReadLine();
}
private static void _testingWriteReadBalance()
{
var r = new Random();
var size = 10;
var circileBuff = new CircleQueue(size);
Console.WriteLine("buff size:" + size);
while (circileBuff.full() == false)
{
var writeRet = circileBuff.write(r.Next(10));
if (writeRet == 0)
{
Console.WriteLine("write full, break");
break;
}
writeRet = circileBuff.write(r.Next(10));
if (writeRet == 0)
{
Console.WriteLine("write full, break");
break;
}
Console.WriteLine("write byte, buff : " + circileBuff);
var readValue = 0;
circileBuff.read(ref readValue);
var readFlag = circileBuff.read(ref readValue);
if (readFlag != 0)
{
Console.WriteLine("read byte, buff : " + circileBuff);
}
else
{
Console.WriteLine("read failure, buff empty");
}
Thread.Sleep(1000);
}
Console.WriteLine("buff full:" + circileBuff);
Console.ReadLine();
}
private static void _testingReadEmpty()
{
var r = new Random();
var size = 10;
var circileBuff = new CircleQueue(size);
Console.WriteLine("buff size:" + size);
while (circileBuff.full() == false)
{
circileBuff.write(r.Next(10));
}
while (circileBuff.empty() == false)
{
var readValue = 0;
circileBuff.read(ref readValue);
var readFlag = circileBuff.read(ref readValue);
if (readFlag != 0)
{
Console.WriteLine("read byte, buff : " + circileBuff);
}
else
{
Console.WriteLine("read failure, buff empty");
break;
}
circileBuff.write(r.Next(10));
Console.WriteLine("write byte, buff : " + circileBuff);
Thread.Sleep(1000);
}
Console.WriteLine("buff empy():" + circileBuff);
Console.ReadLine();
}
private static void _testingWriteFull()
{
var r = new Random();
var size = 10;
var circileBuff = new CircleQueue(size);
Console.WriteLine("buff size:" + size);
while (circileBuff.full() == false)
{
var writeRet = circileBuff.write(r.Next(10));
if (writeRet == 0)
{
Console.WriteLine("write full, break");
break;
}
writeRet = circileBuff.write(r.Next(10));
if (writeRet == 0)
{
Console.WriteLine("write full, break");
break;
}
Console.WriteLine("write byte, buff : " + circileBuff);
var readValue = 0;
var readFlag = circileBuff.read(ref readValue);
if (readFlag != 0)
{
Console.WriteLine("read byte, buff : " + circileBuff);
}
else
{
Console.WriteLine("read failure, buff empty");
}
Thread.Sleep(1000);
}
Console.WriteLine("buff full:" + circileBuff);
Console.ReadLine();
}
private static void _testingWriteReadBalanceRange()
{
var r = new Random();
var size = 10;
var circileBuff = new CircleQueue(size);
Console.WriteLine("buff size:" + size);
var opBuff = new int[2];
while (circileBuff.full() == false)
{
opBuff[0] = r.Next(10);
opBuff[1] = r.Next(10);
var writeRet = circileBuff.writeRange(opBuff);
if (writeRet == 0)
{
Console.WriteLine("write full, break");
break;
}
Console.WriteLine("write byte, buff : " + circileBuff);
var readFlag = circileBuff.readRange(opBuff);
if (readFlag != 0)
{
Console.WriteLine("read byte, buff : " + circileBuff);
}
else
{
Console.WriteLine("read failure, buff empty");
}
Thread.Sleep(1000);
}
Console.WriteLine("buff full:" + circileBuff);
Console.ReadLine();
}
private static void _testingReadEmptyRange()
{
var r = new Random();
var size = 10;
var circileBuff = new CircleQueue(size);
Console.WriteLine("buff size:" + size);
while (circileBuff.full() == false)
{
circileBuff.write(r.Next(10));
}
var opBuff = new int[2];
while (circileBuff.empty() == false)
{
var readFlag = circileBuff.readRange(opBuff, 0, 2);
if (readFlag != 0)
{
Console.WriteLine("read byte, buff : " + circileBuff);
}
else
{
Console.WriteLine("read failure, buff empty");
break;
}
circileBuff.write(r.Next(10));
Console.WriteLine("write byte, buff : " + circileBuff);
Thread.Sleep(1000);
}
Console.WriteLine("buff empy():" + circileBuff);
Console.ReadLine();
}
private static void _testingWriteFullRange()
{
var r = new Random();
var size = 10;
var circileBuff = new CircleQueue(size);
Console.WriteLine("buff size:" + size);
var opBuff = new int[] { 0, 0 };
while (circileBuff.full() == false)
{
opBuff[0] = r.Next(10);
opBuff[1] = r.Next(10);
var writeRet = circileBuff.writeRange(opBuff);
if (writeRet == 0)
{
Console.WriteLine("write full, break");
break;
}
Console.WriteLine("write byte, buff : " + circileBuff);
var readValue = 0;
var readFlag = circileBuff.read(ref readValue);
if (readFlag != 0)
{
Console.WriteLine("read byte, buff : " + circileBuff);
}
else
{
Console.WriteLine("read failure, buff empty");
}
Thread.Sleep(1000);
}
Console.WriteLine("buff full:" + circileBuff);
Console.ReadLine();
}
///
/// author : jave.lin
/// date : 2017-12-28
///
///
class CircleQueue
{
private T[] _m_pBuff;
private int _m_iLen;
private int _m_iHeadIdex; // head, trail
private int _m_iTrailIdx;
private bool _m_bCircle; // 是否折回了,trail < head
private object _m_pLockObj = new object();
public T[] buff
{
get { return _m_pBuff; }
}
public int len
{
get { return _m_iLen; }
}
public CircleQueue( int len )
{
_m_iLen = len;
if ( _m_iLen < 2)
{
throw new Exception("CircleQueue invalidted len : " + len);
}
_m_pBuff = new T[len];
}
public override string ToString()
{
return "size:" + _m_iLen + ", h:" + _m_iHeadIdex + ", t:" + _m_iTrailIdx + ", c:" + _m_bCircle + ", frc:" + freeCount() + ", buff:" + string.Join(",", _m_pBuff);
}
public int freeCount()
{
if (_m_bCircle)
{
return _m_iHeadIdex - _m_iTrailIdx;
}
else
{
return _m_iHeadIdex + (_m_iLen - _m_iTrailIdx);
}
}
public int fillCount()
{
return _m_iLen - freeCount();
}
public bool full()
{
return freeCount() == 0;
}
public bool empty()
{
return freeCount() == _m_iLen;
}
public int readSafe(ref T result)
{
lock (_m_pLockObj)
{
return read(ref result);
}
}
public int read(ref T result)
{
if (empty()) return 0;
result = _m_pBuff[_m_iHeadIdex];
_m_iHeadIdex++;
if (_m_bCircle)
{
if (_m_iHeadIdex == _m_iLen)
{
_m_iHeadIdex = 0;
_m_bCircle = false;
}
else if (_m_iHeadIdex == _m_iTrailIdx)
{
_m_bCircle = false;
}
}
return 1;
}
public int readRangeSafe(int[] result, int resultStartIdx = 0, int readLen = 0, bool autoFitLen = true)
{
lock (_m_pLockObj)
{
return readRange(result, resultStartIdx, readLen, autoFitLen);
}
}
public int readRange( int[] result, int resultStartIdx = 0, int readLen = 0, bool autoFitLen = true )
{
var fc = fillCount();
if (autoFitLen == false)
{
if (result.Length < readLen)
{
throw new Exception("popTopRang result not enough capacity, result.len:" + result.Length + ", popLen:" + readLen);
}
}
else
{
if (readLen _m_iLen )
{
throw new Exception("popTopRange popLen to large : " + readLen + ", and buffLen : " + _m_iLen);
}
if (readLen == 0 || fc == 0 )
{
return 0;
}
if (readLen > fc)
{
return 0;
}
if (autoFitLen == false)
{
if (fc > _m_iLen)
{
throw new Exception("popTopRange popLen to large : " + readLen + ", and fillCount : " + _m_iLen);
}
}
else
{
if (_m_bCircle ) // 如果有折回过,需要特殊处理
{
var remainLenInRight = _m_iLen - _m_iHeadIdex; // 右边剩余的数量
if (remainLenInRight = _m_iLen)
{
_m_bCircle = false;
_m_iHeadIdex %= _m_iLen;
}
return readLen;
}
public int writeSafe( T v )
{
lock (_m_pLockObj)
{
return write(v);
}
}
public int write( T v )
{
if ( _m_bCircle ) // 折回过
{
if (_m_iTrailIdx == _m_iHeadIdex) // 已满
{
return 0;
}
_m_pBuff[_m_iTrailIdx] = v;
_m_iTrailIdx = _m_iTrailIdx + 1;
}
else // 没折回过
{
_m_pBuff[_m_iTrailIdx] = v;
_m_iTrailIdx = _m_iTrailIdx + 1;
}
if (_m_iTrailIdx == _m_iLen) // 折回
{
_m_iTrailIdx = 0;
_m_bCircle = true;
}
return 1;
}
public int writeRangeSafe(int[] data, int startDataIdx = 0, int writeLen = 0)
{
lock (_m_pLockObj)
{
return writeRange(data, startDataIdx, writeLen);
}
}
public int writeRange( int[] data, int startDataIdx = 0, int writeLen = 0 )
{
if ( writeLen == 0 )
{
writeLen = data.Length;
}
if ( freeCount() < writeLen )
{
return 0; // overload buff
}
if ( _m_bCircle ) // 折回过
{
Array.Copy(data, startDataIdx, _m_pBuff, _m_iTrailIdx, writeLen);
_m_iTrailIdx += writeLen;
_m_iTrailIdx %= _m_iLen;
}
else // 未折回过
{
var remainFreeLen = _m_iLen - _m_iTrailIdx;
if (remainFreeLen buff.len时,并重置回0时,标记circle=true当head>buff.len时,并重置回0时,标记circle=false 获取当前可写长度:return circle ? head-trail : head + ( len - trail);
应用
- 用在想在数据流(内存)利用率比较高的场合会使用到
- 写入、读取的速度相当时最佳,可以无限的稳定使用
- 在下位机会更多的使用,毕竟资源比较珍贵
- 否则使用一个大一些的buff来存数据流,在用另一个appliedBuff一次性读取完所有buff中的数据,下次写入buff是就从0开始写入就好了