9 template<
class _Ty,
class _Sty = u
int32_t>
10 struct ring_queue_lockfree
12 using value_type = _Ty;
13 using size_type = _Sty;
15 ring_queue_lockfree(
size_t sz);
17 ring_queue_lockfree(
const ring_queue_lockfree&) =
delete;
18 ring_queue_lockfree(ring_queue_lockfree&&) =
default;
19 ring_queue_lockfree& operator =(
const ring_queue_lockfree&) =
delete;
20 ring_queue_lockfree& operator =(ring_queue_lockfree&&) =
default;
22 auto size() const noexcept->size_type;
23 auto capacity() const noexcept->size_type;
24 bool empty() const noexcept;
25 bool full() const noexcept;
27 bool try_push(U&& value) noexcept(std::is_nothrow_move_constructible_v<U>);
28 bool try_pop(value_type& value) noexcept(std::is_nothrow_move_constructible_v<value_type>);
30 std::unique_ptr<value_type[]> m_bufferPtr;
31 size_type m_bufferSize;
33 std::atomic<size_type> m_writeIndex;
34 std::atomic<size_type> m_readIndex;
35 std::atomic<size_type> m_maximumReadIndex;
41 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
42 std::atomic<size_type> m_count;
45 auto countToIndex(size_type a_count)
const noexcept->size_type;
46 auto nextIndex(size_type a_count)
const noexcept->size_type;
49 template<
class _Ty,
class _Sty>
50 ring_queue_lockfree<_Ty, _Sty>::ring_queue_lockfree(
size_t sz)
51 : m_bufferPtr(new value_type[sz + 1])
52 , m_bufferSize(static_cast<size_type>(sz + 1))
55 , m_maximumReadIndex(0)
56 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
60 assert(sz < (std::numeric_limits<size_type>::max)());
63 template<
class _Ty,
class _Sty>
64 auto ring_queue_lockfree<_Ty, _Sty>::countToIndex(size_type a_count)
const noexcept->size_type
70 template<
class _Ty,
class _Sty>
71 auto ring_queue_lockfree<_Ty, _Sty>::nextIndex(size_type a_count)
const noexcept->size_type
74 return static_cast<size_type
>((a_count + 1) % m_bufferSize);
77 template<
class _Ty,
class _Sty>
78 auto ring_queue_lockfree<_Ty, _Sty>::size() const noexcept->size_type
80 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
81 return m_count.load();
83 auto currentWriteIndex = m_maximumReadIndex.load(std::memory_order_acquire);
84 currentWriteIndex = countToIndex(currentWriteIndex);
86 auto currentReadIndex = m_readIndex.load(std::memory_order_acquire);
87 currentReadIndex = countToIndex(currentReadIndex);
89 if (currentWriteIndex >= currentReadIndex)
90 return (currentWriteIndex - currentReadIndex);
92 return (m_bufferSize + currentWriteIndex - currentReadIndex);
93 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
96 template<
class _Ty,
class _Sty>
97 auto ring_queue_lockfree<_Ty, _Sty>::capacity() const noexcept->size_type
99 return m_bufferSize - 1;
102 template<
class _Ty,
class _Sty>
103 bool ring_queue_lockfree<_Ty, _Sty>::empty() const noexcept
105 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
106 return m_count.load() == 0;
108 auto currentWriteIndex = m_maximumReadIndex.load(std::memory_order_acquire);
109 auto currentReadIndex = m_readIndex.load(std::memory_order_acquire);
110 return countToIndex(currentWriteIndex) == countToIndex(currentReadIndex);
111 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
114 template<
class _Ty,
class _Sty>
115 bool ring_queue_lockfree<_Ty, _Sty>::full() const noexcept
117 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
118 return (m_count.load() == (m_bufferSize - 1));
120 auto currentWriteIndex = m_writeIndex.load(std::memory_order_acquire);
121 auto currentReadIndex = m_readIndex.load(std::memory_order_acquire);
122 return countToIndex(nextIndex(currentWriteIndex)) == countToIndex(currentReadIndex);
123 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
126 template<
class _Ty,
class _Sty>
128 bool ring_queue_lockfree<_Ty, _Sty>::try_push(U&& value) noexcept(std::is_nothrow_move_constructible_v<U>)
130 auto currentWriteIndex = m_writeIndex.load(std::memory_order_acquire);
134 if (countToIndex(nextIndex(currentWriteIndex)) == countToIndex(m_readIndex.load(std::memory_order_acquire)))
147 }
while (!m_writeIndex.compare_exchange_strong(currentWriteIndex, nextIndex(currentWriteIndex), std::memory_order_acq_rel));
150 m_bufferPtr[countToIndex(currentWriteIndex)] = std::move(value);
161 auto savedWriteIndex = currentWriteIndex;
162 while (!m_maximumReadIndex.compare_exchange_weak(currentWriteIndex, nextIndex(currentWriteIndex), std::memory_order_acq_rel))
164 currentWriteIndex = savedWriteIndex;
169 std::this_thread::yield();
173 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
174 m_count.fetch_add(1);
179 template<
class _Ty,
class _Sty>
180 bool ring_queue_lockfree<_Ty, _Sty>::try_pop(value_type& value) noexcept(std::is_nothrow_move_constructible_v<value_type>)
182 auto currentReadIndex = m_readIndex.load(std::memory_order_acquire);
186 auto idx = countToIndex(currentReadIndex);
190 if (idx == countToIndex(m_maximumReadIndex.load(std::memory_order_acquire)))
199 value = m_bufferPtr[idx];
204 if (m_readIndex.compare_exchange_strong(currentReadIndex, nextIndex(currentReadIndex), std::memory_order_acq_rel))
208 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
209 m_count.fetch_sub(1);