我对整个循环/环形缓冲区的思维方式很陌生。我阅读了一些关于它在理论上应该如何工作的文章,并提出了这个代码示例。在我的场景中,我将有多个线程写入和一个线程从缓冲区读取。
我是否需要为 write 方法添加锁?
提前致谢!
public class CircularBuffer<T>
{
private readonly int _size;
private int _head;
private byte _headMirrorSide;
private int _tail;
private byte _tailMirrorSide;
private readonly T[] _buffer;
public CircularBuffer() : this(300) { }
public CircularBuffer(int size)
{
_size = size;
_buffer = new T[_size + 1];
_head = 0;
_headMirrorSide = 0;
_tail = 0;
_tailMirrorSide = 0;
}
private bool IsFull()
{
return _tail == _head && _tailMirrorSide != _headMirrorSide;
}
public bool IsEmpty()
{
return _tail == _head && _tailMirrorSide == _headMirrorSide;
}
private void MovePointer(ref int pointer, ref byte mirrorSide)
{
pointer = pointer + 1;
if (pointer == _size)
{
mirrorSide ^= 1;
pointer = 0;
}
}
public void Write(T obj)
{
_buffer[_head] = obj;
if (IsFull())
{
MovePointer(ref _tail, ref _tailMirrorSide);
}
MovePointer(ref _head, ref _headMirrorSide);
}
public T Read()
{
var obj = _buffer[_tail];
_buffer[_tail] = default(T);
MovePointer(ref _tail, ref _tailMirrorSide);
return obj;
}
}
编辑:最终结果是这样的。
public class CircularBuffer<T> where T : class
{
private readonly int _size;
private int _head;
private byte _headMirrorSide;
private int _tail;
private byte _tailMirrorSide;
private readonly T[] _buffer;
private readonly object _lock = new object();
public CircularBuffer() : this(300) { }
public CircularBuffer(int size)
{
_size = size;
_buffer = new T[_size + 1];
_head = 0;
_headMirrorSide = 0;
_tail = 0;
_tailMirrorSide = 0;
}
private bool IsFull()
{
return _tail == _head && _tailMirrorSide != _headMirrorSide;
}
private bool IsEmpty()
{
return _tail == _head && _tailMirrorSide == _headMirrorSide;
}
private void MovePointer(ref int pointer, ref byte mirrorSide)
{
pointer = pointer + 1;
if (pointer == _size)
{
mirrorSide ^= 1;
pointer = 0;
}
}
public void Write(T obj)
{
lock (_lock)
{
_buffer[_head] = obj;
if (IsFull())
{
MovePointer(ref _tail, ref _tailMirrorSide);
}
MovePointer(ref _head, ref _headMirrorSide);
}
}
public T Read()
{
lock (_lock)
{
if (IsEmpty())
{
return null;
}
var obj = _buffer[_tail];
MovePointer(ref _tail, ref _tailMirrorSide);
return obj;
}
}
}