Я новичок во всем кольцевом/кольцевом буфере. Я прочитал несколько статей о том, как он должен работать в теории и придумал этот пример кода. В моем сценарии я буду писать несколько потоков и один поток, читаемый из буфера.CircularBuffer, мне нужно добавить замок?
Нужно ли добавить замок к методу записи?
Заранее благодарен!
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;
}
}
}
Создание кругового буфера без потоков и без ожидания - это простое упражнение для 1 продюсера и 1 потребителя. Но ваш код в этом сценарии небезопасен. Поддержка нескольких авторов намного сложнее. –
Сфокусируйте вопрос на том, что вам действительно нужно, и почему бы не ConcurrentQueue. –
Мне нужен ограниченный список FIFO с функциональностью, которую «старые» значения перезаписываются, если предел достигнут. Должен ли кольцевой буфер удовлетворять этим требованиям достаточно хорошо? – mckn