1.1 环形缓冲区(Ring Buffer)的实现与应用
★★ 中等考点: 读写指针、空/满判断、无锁 SPSC 环形缓冲、音频/网络缓冲应用
参考答案:
- 环形缓冲区是"带环绕"的定长 FIFO:Head(读)/Tail(写)指针随读写前移,到达容量边界时取模回绕,入队/出队均为 O(1);
- 空/满判断两种方案:维护 Count 计数(空=Count==0,满=Count==Capacity);或牺牲一个槽位(Tail+1==Head 为满);
- 容量取 2 的幂时可用位运算
(p+1)&(Cap-1)替代取模,进一步提速; - 单生产者单消费者(SPSC)可实现无锁:Head/Tail 分置不同缓存行(
alignas(64))避免 false sharing,Tail 用 release、Head 用 acquire 内存序; - 游戏应用:音频解码→播放缓冲、网络消息收发、输入缓冲、帧历史(网络回滚)。
代码示例:
template<typename T>
class TRingBuffer {
TArray<T> Buffer;
int32 Head = 0, Tail = 0, Count = 0, Capacity;
public:
TRingBuffer(int32 Cap) : Capacity(Cap) { Buffer.SetNum(Cap); }
bool Enqueue(const T& Item) {
if (Count == Capacity) return false;
Buffer[Tail] = Item; Tail = (Tail + 1) % Capacity; Count++;
return true;
}
bool Dequeue(T& Out) {
if (Count == 0) return false;
Out = Buffer[Head]; Head = (Head + 1) % Capacity; Count--;
return true;
}
};
// 无锁 SPSC 环形缓冲:Head/Tail 分置不同缓存行
template<typename T>
class TLockFreeRingBuffer {
TArray<T> Buffer;
int32 Capacity;
alignas(64) std::atomic<int32> Head{0}; // 消费者读
alignas(64) std::atomic<int32> Tail{0}; // 生产者写
public:
bool Enqueue(const T& Item) {
int32 Cur = Tail.load(std::memory_order_relaxed);
int32 Next = (Cur + 1) % Capacity;
if (Next == Head.load(std::memory_order_acquire)) return false;
Buffer[Cur] = Item;
Tail.store(Next, std::memory_order_release);
return true;
}
bool Dequeue(T& Out) {
int32 Cur = Head.load(std::memory_order_relaxed);
if (Cur == Tail.load(std::memory_order_acquire)) return false;
Out = Buffer[Cur];
Head.store((Cur + 1) % Capacity, std::memory_order_release);
return true;
}
};