전 원형/링 버퍼 방식의 사고 방식이 처음이에요. 이론적으로 어떻게 작동해야하는지에 대한 기사를 읽고이 코드 예제를 생각해 냈습니다. 필자의 시나리오에서는 버퍼에서 여러 스레드 쓰기 및 단일 스레드 읽기를 수행합니다.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