#pragma once #include #include #include // message queue struct BroadcastMessage { std::vector frameData; int excludeClientId; BroadcastMessage() = default; BroadcastMessage(std::vector data, int excludeId) : frameData(std::move(data)), excludeClientId(excludeId) {} }; class LockFreeBroadcastQueue { private: static const size_t QUEUE_SIZE = 65536; // Must be power of 2 static const size_t QUEUE_MASK = QUEUE_SIZE - 1; struct alignas(64) QueueSlot { std::atomic ready{false}; BroadcastMessage message; }; alignas(64) std::atomic head{0}; alignas(64) std::atomic tail{0}; QueueSlot queue[QUEUE_SIZE]; public: bool push(BroadcastMessage&& message) { const size_t currentTail = tail.load(std::memory_order_relaxed); const size_t nextTail = (currentTail + 1) & QUEUE_MASK; // queue full if (nextTail == head.load(std::memory_order_acquire)) { return false; } QueueSlot& slot = queue[currentTail]; slot.message = std::move(message); slot.ready.store(true, std::memory_order_release); tail.store(nextTail, std::memory_order_release); return true; } bool pop(BroadcastMessage& message) { const size_t currentHead = head.load(std::memory_order_relaxed); // empty if (currentHead == tail.load(std::memory_order_acquire)) { return false; } QueueSlot& slot = queue[currentHead]; if (!slot.ready.load(std::memory_order_acquire)) { return false; } message = std::move(slot.message); slot.ready.store(false, std::memory_order_release); head.store((currentHead + 1) & QUEUE_MASK, std::memory_order_release); return true; } size_t size() const { return (tail.load(std::memory_order_relaxed) - head.load(std::memory_order_relaxed)) & QUEUE_MASK; } bool empty() const { return head.load(std::memory_order_relaxed) == tail.load(std::memory_order_relaxed); } };