libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
lockfree_pool.hpp
1#pragma once
2
3#include <atomic>
4#include <new>
5
6#include "libxr_def.hpp"
7
8namespace LibXR
9{
10
24template <typename Data>
26{
27 public:
28 // NOLINTBEGIN
30 enum class SlotState : uint32_t
31 {
32 FREE = 0,
33 BUSY = 1,
34 READY = 2,
35 RECYCLE = UINT32_MAX
36
37 };
38 // NOLINTEND
39
41 union alignas(LIBXR_CACHE_LINE_SIZE) Slot
42 {
43 struct
44 {
45 std::atomic<SlotState> state;
46 Data data;
47 } slot;
48
49 uint8_t pad[LIBXR_CACHE_LINE_SIZE];
50 };
51
59 LockFreePool(uint32_t slot_count)
60 : SLOT_COUNT(slot_count),
61 slots_(new(std::align_val_t(LIBXR_CACHE_LINE_SIZE)) Slot[slot_count])
62 {
63 for (uint32_t index = 0; index < SLOT_COUNT; index++)
64 {
65 slots_[index].slot.state.store(SlotState::FREE, std::memory_order_relaxed);
66 }
67 }
68
72 ~LockFreePool() { delete[] slots_; }
73
82 ErrorCode Put(const Data &data)
83 {
84 uint32_t start_index = 0;
85 return Put(data, start_index);
86 }
87
98 ErrorCode Put(const Data &data, uint32_t &start_index)
99 {
100 for (uint32_t index = start_index; index < SLOT_COUNT; index++)
101 {
102 auto expected = slots_[index].slot.state.load(std::memory_order_relaxed);
103 if (expected == SlotState::FREE || expected == SlotState::RECYCLE)
104 {
105 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
106 std::memory_order_release,
107 std::memory_order_relaxed))
108 {
109 slots_[index].slot.data = data;
110 slots_[index].slot.state.store(SlotState::READY, std::memory_order_release);
111 start_index = index;
112 return ErrorCode::OK;
113 }
114 }
115 }
116 return ErrorCode::FULL;
117 }
118
128 ErrorCode PutToSlot(const Data &data, uint32_t index)
129 {
130 auto expected = slots_[index].slot.state.load(std::memory_order_relaxed);
131 if (expected == SlotState::FREE || expected == SlotState::RECYCLE)
132 {
133 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
134 std::memory_order_release,
135 std::memory_order_relaxed))
136 {
137 slots_[index].slot.data = data;
138 slots_[index].slot.state.store(SlotState::READY, std::memory_order_release);
139 return ErrorCode::OK;
140 }
141 }
142 return ErrorCode::FULL;
143 }
144
153 ErrorCode Get(Data &data)
154 {
155 uint32_t start_index = 0;
156
157 return Get(data, start_index);
158 }
159
170 ErrorCode Get(Data &data, uint32_t &start_index)
171 {
172 for (uint32_t index = start_index; index < SLOT_COUNT; index++)
173 {
174 auto expected = slots_[index].slot.state.load(std::memory_order_acquire);
175 if (expected == SlotState::READY)
176 {
177 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
178 std::memory_order_acquire,
179 std::memory_order_relaxed))
180 {
181 data = slots_[index].slot.data;
182 slots_[index].slot.state.store(SlotState::RECYCLE, std::memory_order_release);
183 start_index = index;
184 return ErrorCode::OK;
185 }
186 }
187 if (expected == SlotState::FREE)
188 {
189 start_index = 0;
190 return ErrorCode::EMPTY;
191 }
192 }
193
194 start_index = 0;
195 return ErrorCode::EMPTY;
196 }
197
207 ErrorCode GetFromSlot(Data &data, uint32_t index)
208 {
209 auto expected = slots_[index].slot.state.load(std::memory_order_acquire);
210 if (expected == SlotState::READY)
211 {
212 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
213 std::memory_order_acquire,
214 std::memory_order_relaxed))
215 {
216 data = slots_[index].slot.data;
217 slots_[index].slot.state.store(SlotState::RECYCLE, std::memory_order_release);
218 return ErrorCode::OK;
219 }
220 }
221 return ErrorCode::EMPTY;
222 }
223
232 ErrorCode RecycleSlot(uint32_t index)
233 {
234 auto expected = slots_[index].slot.state.load(std::memory_order_relaxed);
235 if (expected == SlotState::READY)
236 {
237 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::RECYCLE,
238 std::memory_order_release,
239 std::memory_order_relaxed))
240 {
241 return ErrorCode::OK;
242 }
243 }
244 return ErrorCode::EMPTY;
245 }
246
251 [[nodiscard]] size_t Size() const
252 {
253 uint32_t size = 0;
254 for (uint32_t index = 0; index < SLOT_COUNT; index++)
255 {
256 if (slots_[index].slot.state.load(std::memory_order_relaxed) == SlotState::READY)
257 {
258 size++;
259 }
260 }
261 return size;
262 }
263
268 [[nodiscard]] size_t EmptySize()
269 {
270 uint32_t size = 0;
271 for (uint32_t index = 0; index < SLOT_COUNT; index++)
272 {
273 auto state = slots_[index].slot.state.load(std::memory_order_relaxed);
274 if (state == SlotState::FREE || state == SlotState::RECYCLE)
275 {
276 size++;
277 }
278 }
279 return size;
280 }
281
287 uint32_t SlotCount() const { return SLOT_COUNT; }
288
289 protected:
290 Slot &operator[](uint32_t index)
291 {
292 if (index >= SLOT_COUNT)
293 {
294 ASSERT(false);
295 }
296 return slots_[index];
297 }
298
299 private:
300 const uint32_t SLOT_COUNT;
302};
303} // namespace LibXR
无锁无序槽池 / Lock-free, unordered slot pool
size_t EmptySize()
查询当前池可用槽数量 / Query the number of writable slots in the pool
ErrorCode GetFromSlot(Data &data, uint32_t index)
从指定槽位开始,取出一个元素 / Retrieve an element from the pool
Slot * slots_
槽数组指针 / Array of slots
~LockFreePool()
析构,释放槽池内存 / Destructor, releasing pool memory
ErrorCode PutToSlot(const Data &data, uint32_t index)
向指定槽放入一个元素 / Put an element into a specific slot
ErrorCode Get(Data &data, uint32_t &start_index)
从指定槽位开始,取出一个元素 / Retrieve an element from the pool
SlotState
槽状态 / Slot state
@ RECYCLE
已读待回收 / Slot was read, waiting for next write.
@ READY
写入完成,可读 / Slot contains valid data, ready to read.
@ BUSY
正在写入 / Slot is being written.
@ FREE
空闲,可写 / Slot is free and can be written.
LockFreePool(uint32_t slot_count)
构造对象池 / Constructor for the pool
ErrorCode RecycleSlot(uint32_t index)
回收指定槽位 / Recycle a slot
ErrorCode Put(const Data &data)
向池中放入一个元素 / Put an element into the pool
const uint32_t SLOT_COUNT
槽总数 / Number of slots
ErrorCode Get(Data &data)
从池中取出一个元素 / Retrieve an element from the pool
ErrorCode Put(const Data &data, uint32_t &start_index)
向池中放入一个元素,返回起始槽索引 / Put an element into the pool and return the starting slot index
size_t Size() const
查询池中可取元素数量 / Query the number of available elements in the pool
uint32_t SlotCount() const
获取槽总数 / Get the total number of slots in the pool
LibXR 命名空间
单个槽结构体 / Individual slot structure (cache line aligned)
Data data
槽内数据 / Stored data
std::atomic< SlotState > state
当前槽状态 / Current state