20#ifndef LIBE3_LOCKFREE_QUEUE_HPP
21#define LIBE3_LOCKFREE_QUEUE_HPP
31#include <condition_variable>
58 E3_LOG_DEBUG(LOG_TAG) <<
"Lock-free queue created, capacity="
83 if (shutdown_.load(std::memory_order_relaxed)) {
84 return ErrorCode::NOT_INITIALIZED;
87 if (!ring_.try_push(std::move(item))) {
88 E3_LOG_WARN(LOG_TAG) <<
"Queue full, dropping message";
89 return ErrorCode::BUFFER_TOO_SMALL;
99 std::lock_guard<std::mutex> lock(wait_mutex_);
101 wait_cv_.notify_one();
104 return ErrorCode::SUCCESS;
116 for (
size_t i = 0; i < SPIN_COUNT; ++i) {
117 if (ring_.try_pop(item))
return item;
118 if (shutdown_.load(std::memory_order_relaxed))
return T{};
123 for (
size_t i = 0; i < YIELD_COUNT; ++i) {
124 if (ring_.try_pop(item))
return item;
125 if (shutdown_.load(std::memory_order_relaxed))
return T{};
126 std::this_thread::yield();
136 std::unique_lock<std::mutex> lock(wait_mutex_);
138 if (ring_.try_pop(item))
return item;
139 if (shutdown_.load(std::memory_order_relaxed))
return T{};
148 std::optional<T>
pop(std::chrono::milliseconds timeout) {
150 auto deadline = std::chrono::steady_clock::now() + timeout;
153 for (
size_t i = 0; i < SPIN_COUNT; ++i) {
154 if (ring_.try_pop(item))
return item;
155 if (shutdown_.load(std::memory_order_relaxed))
return std::nullopt;
160 for (
size_t i = 0; i < YIELD_COUNT; ++i) {
161 if (ring_.try_pop(item))
return item;
162 if (shutdown_.load(std::memory_order_relaxed))
return std::nullopt;
163 std::this_thread::yield();
171 std::unique_lock<std::mutex> lock(wait_mutex_);
172 while (std::chrono::steady_clock::now() < deadline) {
173 if (ring_.try_pop(item))
return item;
174 if (shutdown_.load(std::memory_order_relaxed))
return std::nullopt;
175 wait_cv_.wait_until(lock, deadline);
180 if (ring_.try_pop(item))
return item;
190 if (ring_.try_pop(item))
return item;
195 bool empty()
const {
return ring_.empty_approx(); }
198 size_t size()
const {
return ring_.size_approx(); }
201 size_t capacity() const noexcept {
return ring_.capacity(); }
206 while (ring_.try_pop(item)) {}
214 shutdown_.store(
true, std::memory_order_relaxed);
218 std::lock_guard<std::mutex> lock(wait_mutex_);
220 wait_cv_.notify_all();
226 return shutdown_.load(std::memory_order_relaxed);
236 shutdown_.store(
false, std::memory_order_relaxed);
241 static constexpr const char* LOG_TAG =
"Queue";
244 std::atomic<bool> shutdown_{
false};
247 std::mutex wait_mutex_;
248 std::condition_variable wait_cv_;
251 static constexpr size_t SPIN_COUNT = 40;
252 static constexpr size_t YIELD_COUNT = 100;
ErrorCode push(T item)
Enqueue an item (non-blocking, lock-free).
LockFreeQueue & operator=(const LockFreeQueue &)=delete
std::optional< T > try_pop()
Try to dequeue without blocking.
std::optional< T > pop(std::chrono::milliseconds timeout)
Dequeue an item with a maximum wait duration.
LockFreeQueue(LockFreeQueue &&)=delete
LockFreeQueue(size_t capacity=128)
Construct a LockFreeQueue.
size_t size() const
Return the approximate number of items in the queue.
bool empty() const
Return true if the queue appears empty (approximate).
void shutdown()
Signal shutdown so that all blocked pop() calls return promptly.
void clear()
Discard all items currently in the queue.
size_t capacity() const noexcept
Return the ring buffer capacity (always a power of two).
~LockFreeQueue()
Destructor – signals shutdown so any blocked pop() returns.
T pop()
Dequeue an item, blocking indefinitely until one is available.
void rearm()
Clear shutdown and discard any residual items so the queue is reusable after a shutdown()....
LockFreeQueue & operator=(LockFreeQueue &&)=delete
bool is_shutdown() const
Return true if shutdown() has been called.
LockFreeQueue(const LockFreeQueue &)=delete
Lock-free bounded MPMC ring buffer.
Logging facility for libe3.
#define E3_LOG_TRACE(component)
#define E3_LOG_WARN(component)
#define E3_LOG_DEBUG(component)
Lock-free bounded Multi-Producer Multi-Consumer (MPMC) ring buffer.
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
void cpu_relax() noexcept
Emit a CPU-level pause/yield hint inside spin-wait loops.
E3AP Protocol Types - Vendor-neutral type definitions.