Here comes he RunT!
This commit is contained in:
75
Sources/broadcast_queue.h
Normal file
75
Sources/broadcast_queue.h
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
// message queue
|
||||
struct BroadcastMessage {
|
||||
std::vector<uint8_t> frameData;
|
||||
int excludeClientId;
|
||||
|
||||
BroadcastMessage() = default;
|
||||
BroadcastMessage(std::vector<uint8_t> 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<bool> ready{false};
|
||||
BroadcastMessage message;
|
||||
};
|
||||
|
||||
alignas(64) std::atomic<size_t> head{0};
|
||||
alignas(64) std::atomic<size_t> 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);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user