forked from sin365/AxibugEmuOnline
74 lines
1.9 KiB
C#
74 lines
1.9 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
public class RingBuffer<T>
|
|
{
|
|
private readonly T[] buffer;
|
|
private readonly int capacity;
|
|
private int writePos;
|
|
private int readPos;
|
|
private int count;
|
|
|
|
public RingBuffer(int capacity)
|
|
{
|
|
this.capacity = capacity;
|
|
this.buffer = new T[capacity];
|
|
this.writePos = 0;
|
|
this.readPos = 0;
|
|
this.count = 0;
|
|
}
|
|
|
|
public void Write(T item)
|
|
{
|
|
int localWritePos;
|
|
int localReadPos;
|
|
|
|
do
|
|
{
|
|
localWritePos = Volatile.Read(ref writePos);
|
|
localReadPos = Volatile.Read(ref readPos);
|
|
|
|
int nextWritePos = (localWritePos + 1) % capacity;
|
|
|
|
if (nextWritePos == localReadPos)
|
|
{
|
|
// 缓冲区已满,覆盖最旧的未读数据
|
|
Interlocked.CompareExchange(ref readPos, (localReadPos + 1) % capacity, localReadPos);
|
|
}
|
|
}
|
|
while (Interlocked.CompareExchange(ref writePos, (localWritePos + 1) % capacity, localWritePos) != localWritePos);
|
|
|
|
buffer[localWritePos] = item;
|
|
Interlocked.Increment(ref count);
|
|
}
|
|
|
|
public bool TryRead(out T item)
|
|
{
|
|
item = default(T);
|
|
|
|
int localReadPos;
|
|
int localWritePos;
|
|
|
|
do
|
|
{
|
|
localReadPos = Volatile.Read(ref readPos);
|
|
localWritePos = Volatile.Read(ref writePos);
|
|
|
|
if (localReadPos == localWritePos)
|
|
{
|
|
return false; // 缓冲区为空
|
|
}
|
|
}
|
|
while (Interlocked.CompareExchange(ref readPos, (localReadPos + 1) % capacity, localReadPos) != localReadPos);
|
|
|
|
item = buffer[localReadPos];
|
|
Interlocked.Decrement(ref count);
|
|
return true;
|
|
}
|
|
|
|
public int Available()
|
|
{
|
|
return Volatile.Read(ref count);
|
|
}
|
|
}
|