我是整个循环/环缓冲思维方式的新手。我在理论上阅读了一些关于它应该如何工作的文章,并提出了这个代码示例。在我的场景中,我将有多个线程写入,并从缓冲区读取一个线程。
我是否需要为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;
}
}
}
答案 0 :(得分:1)
如果您有多个线程访问缓冲区并且所有这些线程只能读取,那么您不必使用锁定。但是,如果一个或多个线程正在修改数据,那么您将需要一个锁。所以在你的情况下,答案是明确的,明确的 YES ,特别是因为你的Read()方法也改变了数据:缓冲区指针的位置。
答案 1 :(得分:1)
只要您触摸来自不同线程的数据,就必须同步访问权限。最简单的方法是lock()指令,它应该放在Read()和Write()方法中。
显然,Write()应该有lock()以避免并发提交到同一个内存单元格(因为缓冲区正在累积来自每个编写器的数据,而不是“优胜者”)。
Read()也应该有lock(),因为它
P.S。在高级别,您可以使用单向内存屏障而不是单向锁,但这需要很多经验