1#ifndef BTLLIB_ORDER_QUEUE_HPP
2#define BTLLIB_ORDER_QUEUE_HPP
6#include <condition_variable>
22 Block(
const size_t block_size)
29 : current(block.current)
33 std::swap(data, block.data);
39 Block& operator=(
const Block& block) =
default;
43 std::swap(data, block.data);
44 current = block.current;
63 Slot(
size_t block_size)
66 Slot(
const Slot& slot)
68 , occupied(slot.occupied)
69 , last_tenant(slot.last_tenant)
71 Slot(Slot&& slot) noexcept
73 , occupied(slot.occupied)
74 , last_tenant(slot.last_tenant)
77 Slot& operator=(
const Slot& slot)
83 occupied = slot.occupied;
84 last_tenant = slot.last_tenant;
87 Slot& operator=(Slot&& slot)
noexcept
90 occupied = slot.occupied;
91 last_tenant = slot.last_tenant;
95 typename OrderQueue<T>::Block block;
97 bool occupied =
false;
98 std::condition_variable occupancy_changed;
99 size_t last_tenant = -1;
102 size_t elements()
const {
return element_count; }
106 bool closed_expected =
false;
107 if (closed.compare_exchange_strong(closed_expected,
true)) {
108 for (
auto& slot : this->slots) {
109 std::unique_lock<std::mutex> busy_lock(slot.busy);
110 slot.occupancy_changed.notify_all();
115 bool is_closed()
const {
return closed; }
117 OrderQueue(
const size_t queue_size,
const size_t block_size)
118 : slots(queue_size, Slot(block_size))
119 , queue_size(queue_size)
120 , block_size(block_size)
123 OrderQueue(
const OrderQueue&) =
delete;
124 OrderQueue(OrderQueue&&) =
delete;
127 std::vector<Slot> slots;
128 size_t queue_size, block_size;
129 size_t read_counter = 0;
130 std::atomic<size_t> element_count{ 0 };
131 std::atomic<bool> closed{
false };
134#define ORDER_QUEUE_XPXC(SUFFIX, \
136 EXTRA_WRITE_LOCK_CONDS, \
140 EXTRA_READ_LOCK_CONDS, \
144 template<typename T> \
145 class OrderQueue##SUFFIX : public OrderQueue<T> \
149 OrderQueue##SUFFIX(const size_t queue_size, const size_t block_size) \
150 : OrderQueue<T>(queue_size, block_size) \
153 using Block = typename OrderQueue<T>::Block; \
154 using Slot = typename OrderQueue<T>::Slot; \
156 void write(Block& block) \
159 const auto num = block.num; \
160 auto& target = this->slots[num % this->queue_size]; \
161 std::unique_lock<std::mutex> busy_lock(target.busy); \
162 target.occupancy_changed.wait(busy_lock, [&] { \
163 return (!target.occupied EXTRA_WRITE_LOCK_CONDS) || this->closed; \
165 if (this->closed) { \
169 target.block = std::move(block); \
170 target.occupied = true; \
171 target.occupancy_changed.NOTIFY_WRITE(); \
172 ++(this->element_count); \
175 void read(Block& block) \
178 auto& target = this->slots[this->read_counter % this->queue_size]; \
179 std::unique_lock<std::mutex> busy_lock(target.busy); \
180 target.occupancy_changed.wait(busy_lock, [&] { \
181 return (target.occupied EXTRA_READ_LOCK_CONDS) || this->closed; \
183 if (this->closed) { \
186 ++(this->read_counter); \
188 block = std::move(target.block); \
189 target.occupied = false; \
190 target.occupancy_changed.NOTIFY_READ(); \
191 --(this->element_count); \
198ORDER_QUEUE_XPXC(SPSC, , , , notify_one, , , , notify_one, )
199ORDER_QUEUE_XPXC(MPSC,
201 &&(num - target.last_tenant <= this->queue_size),
202 target.last_tenant = num,
208ORDER_QUEUE_XPXC(SPMC,
213 std::unique_lock<std::mutex> read_lock(read_mutex),
217 std::mutex read_mutex;)
218ORDER_QUEUE_XPXC(MPMC,
220 &&(num - target.last_tenant <= this->queue_size),
221 target.last_tenant = num,
223 std::unique_lock<std::mutex> read_lock(read_mutex),
227 std::mutex read_mutex;)
229#undef ORDER_QUEUE_XPXC
Definition: order_queue.hpp:16
Definition: bloom_filter.hpp:18
Definition: order_queue.hpp:20