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
50
51 Slot()
52 {
53 new (&slot.state) std::atomic<SlotState>(SlotState::FREE);
54 }
55
56 ~Slot() {}
57 };
58
66 LockFreePool(uint32_t slot_count)
67 : SLOT_COUNT(slot_count),
68 slots_(new (std::align_val_t(LibXR::CACHE_LINE_SIZE)) Slot[slot_count])
69 {
70 for (uint32_t index = 0; index < SLOT_COUNT; index++)
71 {
72 slots_[index].slot.state.store(SlotState::FREE, std::memory_order_relaxed);
73 }
74 }
75
79 ~LockFreePool() { delete[] slots_; }
80
89 ErrorCode Put(const Data& data)
90 {
91 uint32_t start_index = 0;
92 return Put(data, start_index);
93 }
94
105 ErrorCode Put(const Data& data, uint32_t& start_index)
106 {
107 for (uint32_t index = start_index; index < SLOT_COUNT; index++)
108 {
109 auto expected = slots_[index].slot.state.load(std::memory_order_relaxed);
110 if (expected == SlotState::FREE || expected == SlotState::RECYCLE)
111 {
112 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
113 std::memory_order_release,
114 std::memory_order_relaxed))
115 {
116 slots_[index].slot.data = data;
117 slots_[index].slot.state.store(SlotState::READY, std::memory_order_release);
118 start_index = index;
119 return ErrorCode::OK;
120 }
121 }
122 }
123 return ErrorCode::FULL;
124 }
125
135 ErrorCode PutToSlot(const Data& data, uint32_t index)
136 {
137 auto expected = slots_[index].slot.state.load(std::memory_order_relaxed);
138 if (expected == SlotState::FREE || expected == SlotState::RECYCLE)
139 {
140 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
141 std::memory_order_release,
142 std::memory_order_relaxed))
143 {
144 slots_[index].slot.data = data;
145 slots_[index].slot.state.store(SlotState::READY, std::memory_order_release);
146 return ErrorCode::OK;
147 }
148 }
149 return ErrorCode::FULL;
150 }
151
160 ErrorCode Get(Data& data)
161 {
162 uint32_t start_index = 0;
163
164 return Get(data, start_index);
165 }
166
177 ErrorCode Get(Data& data, uint32_t& start_index)
178 {
179 for (uint32_t index = start_index; index < SLOT_COUNT; index++)
180 {
181 auto expected = slots_[index].slot.state.load(std::memory_order_acquire);
182 if (expected == SlotState::READY)
183 {
184 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
185 std::memory_order_acquire,
186 std::memory_order_relaxed))
187 {
188 data = slots_[index].slot.data;
189 slots_[index].slot.state.store(SlotState::RECYCLE, std::memory_order_release);
190 start_index = index;
191 return ErrorCode::OK;
192 }
193 }
194 if (expected == SlotState::FREE)
195 {
196 start_index = 0;
197 return ErrorCode::EMPTY;
198 }
199 }
200
201 start_index = 0;
202 return ErrorCode::EMPTY;
203 }
204
214 ErrorCode GetFromSlot(Data& data, uint32_t index)
215 {
216 auto expected = slots_[index].slot.state.load(std::memory_order_acquire);
217 if (expected == SlotState::READY)
218 {
219 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::BUSY,
220 std::memory_order_acquire,
221 std::memory_order_relaxed))
222 {
223 data = slots_[index].slot.data;
224 slots_[index].slot.state.store(SlotState::RECYCLE, std::memory_order_release);
225 return ErrorCode::OK;
226 }
227 }
228 return ErrorCode::EMPTY;
229 }
230
239 ErrorCode RecycleSlot(uint32_t index)
240 {
241 auto expected = slots_[index].slot.state.load(std::memory_order_relaxed);
242 if (expected == SlotState::READY)
243 {
244 if (slots_[index].slot.state.compare_exchange_strong(expected, SlotState::RECYCLE,
245 std::memory_order_release,
246 std::memory_order_relaxed))
247 {
248 return ErrorCode::OK;
249 }
250 }
251 return ErrorCode::EMPTY;
252 }
253
258 [[nodiscard]] size_t Size() const
259 {
260 uint32_t size = 0;
261 for (uint32_t index = 0; index < SLOT_COUNT; index++)
262 {
263 if (slots_[index].slot.state.load(std::memory_order_relaxed) == SlotState::READY)
264 {
265 size++;
266 }
267 }
268 return size;
269 }
270
275 [[nodiscard]] size_t EmptySize()
276 {
277 uint32_t size = 0;
278 for (uint32_t index = 0; index < SLOT_COUNT; index++)
279 {
280 auto state = slots_[index].slot.state.load(std::memory_order_relaxed);
281 if (state == SlotState::FREE || state == SlotState::RECYCLE)
282 {
283 size++;
284 }
285 }
286 return size;
287 }
288
294 uint32_t SlotCount() const { return SLOT_COUNT; }
295
296 protected:
297 Slot& operator[](uint32_t index)
298 {
299 if (index >= SLOT_COUNT)
300 {
301 ASSERT(false);
302 }
303 return slots_[index];
304 }
305
306 private:
307 const uint32_t SLOT_COUNT;
309};
310} // 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 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ EMPTY
为空 | Empty
@ FULL
已满 | Full
@ OK
操作成功 | Operation successful
constexpr size_t CACHE_LINE_SIZE
缓存行大小 / Cache line size
Definition libxr_def.hpp:32
单个槽结构体 / Individual slot structure (cache line aligned)
Data data
槽内数据 / Stored data
std::atomic< SlotState > state
当前槽状态 / Current state
uint8_t pad[LibXR::CACHE_LINE_SIZE]
缓存行填充 / Cache line padding