64template <
typename T>
class MPMCQueue
67 MPMCQueue (
size_t buffer_size = 8) { reserve (buffer_size); }
69 ~MPMCQueue () {
delete[] _buffer; }
71 size_t capacity ()
const {
return _buffer_mask + 1; }
73 static size_t power_of_two_size (
size_t sz)
76 for (power_of_two = 1; 1U << power_of_two < sz; ++power_of_two)
78 return 1U << power_of_two;
81 void reserve (
size_t buffer_size)
83 buffer_size = power_of_two_size (buffer_size);
84 assert ((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0));
85 if (_buffer_mask >= buffer_size - 1)
90 _buffer =
new cell_t[buffer_size];
91 _buffer_mask = buffer_size - 1;
97 for (
size_t i = 0; i <= _buffer_mask; ++i)
99 _buffer[i]._sequence.store (i, std::memory_order_relaxed);
101 _enqueue_pos.store (0, std::memory_order_relaxed);
102 _dequeue_pos.store (0, std::memory_order_relaxed);
105 bool push_back (T
const &data)
108 size_t pos = _enqueue_pos.load (std::memory_order_relaxed);
112 cell = &_buffer[pos & _buffer_mask];
113 size_t seq = cell->_sequence.load (std::memory_order_acquire);
114 intptr_t dif = (intptr_t) seq - (intptr_t) pos;
117 if (_enqueue_pos.compare_exchange_weak (
118 pos, pos + 1, std::memory_order_relaxed))
129 pos = _enqueue_pos.load (std::memory_order_relaxed);
134 cell->_sequence.store (pos + 1, std::memory_order_release);
139 bool pop_front (T &data)
142 size_t pos = _dequeue_pos.load (std::memory_order_relaxed);
146 cell = &_buffer[pos & _buffer_mask];
147 size_t seq = cell->_sequence.load (std::memory_order_acquire);
148 intptr_t dif = (intptr_t) seq - (intptr_t) (pos + 1);
151 if (_dequeue_pos.compare_exchange_weak (
152 pos, pos + 1, std::memory_order_relaxed))
163 pos = _dequeue_pos.load (std::memory_order_relaxed);
168 cell->_sequence.store (pos + _buffer_mask + 1, std::memory_order_release);
175 MPMC_QUEUE_TYPE _sequence;
180 cell_t * _buffer{
nullptr };
181 size_t _buffer_mask{};
182 char _pad1[64 -
sizeof (cell_t *) -
sizeof (
size_t)] = {};
183 MPMC_QUEUE_TYPE _enqueue_pos{ 0 };
184 char _pad2[64 -
sizeof (size_t)] = {};
185 MPMC_QUEUE_TYPE _dequeue_pos = 0;
186 char _pad3[64 -
sizeof (size_t)] = {};