libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
LibXR::SlotPoolBase Class Reference

槽池的无类型内核:槽状态机、发布序号与扫描逻辑。 Typeless core of the slot pool: slot state machine, publish sequence and scan logic. More...

#include <slot_pool.hpp>

Inheritance diagram for LibXR::SlotPoolBase:
[legend]

Public Member Functions

 SlotPoolBase (size_t slot_size, size_t slot_align, size_t slot_count)
 构造槽池内核 / Construct the slot-pool core.
 
 ~SlotPoolBase ()
 析构槽池内核 / Destroy the slot-pool core.
 
ErrorCode Acquire (size_t &index)
 认领一个空闲槽(空闲 → 写入中) / Claim one free slot (free -> writing).
 
void Publish (size_t index)
 发布已写好的槽(写入中 → 就绪),并取得发布序号 / Publish a fully written slot (writing -> ready) and take a publish sequence number.
 
ErrorCode Take (size_t &index)
 认领序号最小的就绪槽(就绪 → 读取中) / Claim the oldest ready slot (ready -> reading).
 
void Release (size_t index)
 释放自己持有的槽(写入中或读取中 → 空闲) / Release an owned slot (writing or reading -> free).
 
size_t Size () const
 获取槽总数 / Get the total number of slots.
 

Protected Types

enum  SlotState : uint32_t { SLOT_FREE = 0 , SLOT_WRITING = 1 , SLOT_READY = 2 , SLOT_READING = 3 }
 槽状态 / Slot state. More...
 

Protected Member Functions

void * SlotPtr (size_t index)
 获取指定槽位的存储地址 / Get the storage address of one slot.
 
const void * SlotPtr (size_t index) const
 获取指定槽位的存储地址(只读)/ Get the storage address of one slot (const).
 

Protected Attributes

const size_t slot_size_
 单个槽的字节数 / Byte size of one slot.
 
const size_t slot_count_
 槽总数 / Total number of slots.
 
const size_t slot_stride_
 相邻槽位之间的步长 / Byte stride between slots.
 
const size_t alloc_align_
 
std::atomic< uint32_t > * states_
 每槽状态字 / Per-slot atomic state word.
 
std::atomic< uint32_t > * seqs_
 每槽发布序号 / Per-slot publish sequence.
 
std::byte * slots_
 槽存储缓冲区 / Byte buffer storing slots.
 
std::atomic< uint32_t > publish_seq_
 
std::atomic< uint32_t > release_count_
 

Static Protected Attributes

static constexpr size_t INVALID_INDEX = static_cast<size_t>(-1)
 无效槽位下标 / Sentinel for "no slot chosen".
 

Detailed Description

槽池的无类型内核:槽状态机、发布序号与扫描逻辑。 Typeless core of the slot pool: slot state machine, publish sequence and scan logic.

内核只管理每个槽的原子状态与发布序号,以及按槽位下标访问的原始存储; payload 类型语义由上层的 SlotPool<T> 负责。所有状态转换都用 CAS 完成, 同一时刻一个槽只属于一个执行者。

The core only manages the per-slot atomic state, the publish sequence and the raw per-index storage; payload type semantics live in SlotPool<T> above it. Every state transition is a CAS, so at any moment a slot belongs to exactly one execution context.

Definition at line 35 of file slot_pool.hpp.

Member Enumeration Documentation

◆ SlotState

enum LibXR::SlotPoolBase::SlotState : uint32_t
protected

槽状态 / Slot state.

Enumerator
SLOT_FREE 

空闲,可被 Acquire 认领 / Free, claimable by Acquire

SLOT_WRITING 

写入中,已被生产者持有 / Writing, owned by a producer

SLOT_READY 

就绪,等待 Take / Ready, waiting for Take

SLOT_READING 

读取中,已被消费者持有 / Reading, owned by a consumer

Definition at line 125 of file slot_pool.hpp.

126 {
127 SLOT_FREE = 0,
128 SLOT_WRITING = 1,
129 SLOT_READY = 2,
130 SLOT_READING = 3
131 };
@ SLOT_READING
读取中,已被消费者持有 / Reading, owned by a consumer
@ SLOT_READY
就绪,等待 Take / Ready, waiting for Take
@ SLOT_FREE
空闲,可被 Acquire 认领 / Free, claimable by Acquire
@ SLOT_WRITING
写入中,已被生产者持有 / Writing, owned by a producer

Constructor & Destructor Documentation

◆ SlotPoolBase()

LibXR::SlotPoolBase::SlotPoolBase ( size_t slot_size,
size_t slot_align,
size_t slot_count )

构造槽池内核 / Construct the slot-pool core.

Parameters
slot_size单个槽的字节数 / Byte size of one slot
slot_align槽存储的对齐要求 / Alignment requirement of the slot storage
slot_count槽总数 / Total number of slots
Note
仅构造时分配内存,运行期不再分配 / Allocates only at construction; no allocation at run time.

Definition at line 8 of file slot_pool.cpp.

9 : slot_size_(slot_size),
10 slot_count_(slot_count),
11 slot_stride_(AlignUp(slot_size_, slot_align)),
12 alloc_align_(std::max(alignof(std::max_align_t), slot_align)),
13 states_(nullptr),
14 seqs_(nullptr),
15 slots_(nullptr),
16 publish_seq_(0),
18{
19 ASSERT(slot_size_ > 0);
20 ASSERT(slot_count_ > 0);
21 ASSERT(slot_align > 0);
22 ASSERT(slot_count_ <= std::numeric_limits<size_t>::max() / slot_stride_);
23 ASSERT(slot_stride_ <= std::numeric_limits<size_t>::max() / slot_align);
24
25 states_ = new (std::align_val_t(LibXR::CONCURRENCY_ALIGNMENT))
26 std::atomic<uint32_t>[slot_count_];
27 seqs_ = new (std::align_val_t(LibXR::CONCURRENCY_ALIGNMENT))
28 std::atomic<uint32_t>[slot_count_];
29
30 slots_ = static_cast<std::byte*>(
31 ::operator new[](slot_stride_ * slot_count_, std::align_val_t(alloc_align_)));
32
33 for (size_t index = 0; index < slot_count_; ++index)
34 {
35 states_[index].store(SLOT_FREE, std::memory_order_relaxed);
36 seqs_[index].store(0, std::memory_order_relaxed);
37 }
38}
const size_t alloc_align_
std::byte * slots_
槽存储缓冲区 / Byte buffer storing slots.
const size_t slot_count_
槽总数 / Total number of slots.
std::atomic< uint32_t > publish_seq_
std::atomic< uint32_t > * states_
每槽状态字 / Per-slot atomic state word.
std::atomic< uint32_t > release_count_
const size_t slot_stride_
相邻槽位之间的步长 / Byte stride between slots.
const size_t slot_size_
单个槽的字节数 / Byte size of one slot.
std::atomic< uint32_t > * seqs_
每槽发布序号 / Per-slot publish sequence.
constexpr size_t CONCURRENCY_ALIGNMENT
并发结构对齐粒度(用于降低多核伪共享) / Alignment policy used by concurrency-oriented structures
Definition libxr_def.hpp:61

◆ ~SlotPoolBase()

LibXR::SlotPoolBase::~SlotPoolBase ( )

析构槽池内核 / Destroy the slot-pool core.

Definition at line 40 of file slot_pool.cpp.

41{
42 ::operator delete[](slots_, std::align_val_t(alloc_align_));
43 // 与构造时显式对齐的 new[] 配对 / Pairs with the explicitly aligned new[] of
44 // the constructor.
45 ::operator delete[](states_, std::align_val_t(LibXR::CONCURRENCY_ALIGNMENT));
46 ::operator delete[](seqs_, std::align_val_t(LibXR::CONCURRENCY_ALIGNMENT));
47}

Member Function Documentation

◆ Acquire()

ErrorCode LibXR::SlotPoolBase::Acquire ( size_t & index)

认领一个空闲槽(空闲 → 写入中) / Claim one free slot (free -> writing).

Parameters
index成功时写入认领的槽位下标 / Receives the claimed slot index on success
Returns
成功返回 ErrorCode::OK;没有空闲槽返回 ErrorCode::FULL Returns ErrorCode::OK on success; ErrorCode::FULL when no slot is free

扫描全部槽位,跳过被其他上下文占用的槽(写入中、就绪、读取中)。 一个被打断的操作只占住它自己的槽,不会挡住其他上下文认领剩余的空闲槽。 The full slot array is scanned and slots owned by other contexts (writing, ready, reading) are skipped. An interrupted operation only occupies its own slot and never blocks other contexts from claiming the remaining free slots.

Definition at line 49 of file slot_pool.cpp.

50{
51 // 释放计数作为重扫的变化检测:扫描期间有槽被释放时,FULL 才允许重扫一次。
52 // The release counter detects changes across the scan: a FULL result may only
53 // trigger one rescan when some slot was released meanwhile.
54 uint32_t release_begin = release_count_.load(std::memory_order_acquire);
55 bool rescanned = false;
56
57 for (;;)
58 {
59 for (size_t i = 0; i < slot_count_; ++i)
60 {
61 if (states_[i].load(std::memory_order_acquire) != SLOT_FREE)
62 {
63 continue;
64 }
65
66 uint32_t expected = SLOT_FREE;
67 if (states_[i].compare_exchange_strong(expected, SLOT_WRITING,
68 std::memory_order_acq_rel,
69 std::memory_order_acquire))
70 {
71 index = i;
72 return ErrorCode::OK;
73 }
74 // 该槽刚被其他上下文认领:继续扫剩余槽位。
75 // The slot was just claimed by another context: keep scanning the rest.
76 }
77
78 const uint32_t release_end = release_count_.load(std::memory_order_acquire);
79 if (release_end == release_begin || rescanned)
80 {
81 return ErrorCode::FULL;
82 }
83 release_begin = release_end;
84 rescanned = true;
85 }
86}
@ FULL
已满 / Full
@ OK
操作成功 / Operation successful

◆ Publish()

void LibXR::SlotPoolBase::Publish ( size_t index)

发布已写好的槽(写入中 → 就绪),并取得发布序号 / Publish a fully written slot (writing -> ready) and take a publish sequence number.

Parameters
index已通过 Acquire 认领的槽位下标 / Slot index claimed via Acquire

发布序号在 Publish 开始时由全局计数器 fetch_add 取得;Take 在已就绪 的槽中按序号先后出队。调用方必须仍持有该槽(写入中),重复发布或发布未 认领的槽是调用方错误。 The sequence number comes from a global fetch_add counter when Publish begins; Take dequeues ready slots in sequence order. The caller must still own the slot (writing); double publishing or publishing an unclaimed slot is a caller error.

Definition at line 88 of file slot_pool.cpp.

89{
90 ASSERT(index < slot_count_);
91
92 // 先取序号再置就绪:重扫的发布计数变化先于就绪状态可见。
93 // Take the sequence first, then publish: the counter change that drives the
94 // rescan becomes visible before the ready state itself.
95 const uint32_t seq = publish_seq_.fetch_add(1, std::memory_order_release);
96 seqs_[index].store(seq, std::memory_order_relaxed);
97
98 uint32_t expected = SLOT_WRITING;
99 const bool ok = states_[index].compare_exchange_strong(
100 expected, SLOT_READY, std::memory_order_release, std::memory_order_acquire);
101 ASSERT(ok);
102}

◆ Release()

void LibXR::SlotPoolBase::Release ( size_t index)

释放自己持有的槽(写入中或读取中 → 空闲) / Release an owned slot (writing or reading -> free).

Parameters
index自己持有的槽位下标 / Slot index owned by the caller

释放不会失败;放弃一个只 Acquire 未发布的槽同样是合法用法 (分配器模式)。释放其他执行者持有的槽是调用方错误。 Releasing cannot fail; abandoning a slot that was only acquired (allocator usage) is also valid. Releasing a slot owned by another context is a caller error.

Definition at line 184 of file slot_pool.cpp.

185{
186 ASSERT(index < slot_count_);
187
188 // 释放计数先于状态置回空闲:已经扫过该槽的上下文能通过计数变化发现它。
189 // Bump the release counter before the state returns to free: a context that
190 // already scanned past this slot can detect it through the counter change.
191 release_count_.fetch_add(1, std::memory_order_release);
192
193 uint32_t expected = states_[index].load(std::memory_order_relaxed);
194 // 只有持有者(写入中或读取中)才能释放 / Only the holder (writing or reading)
195 // may release.
196 ASSERT(expected == SLOT_WRITING || expected == SLOT_READING);
197 const bool ok = states_[index].compare_exchange_strong(
198 expected, SLOT_FREE, std::memory_order_release, std::memory_order_acquire);
199 ASSERT(ok);
200}

◆ Size()

size_t LibXR::SlotPoolBase::Size ( ) const
inlinenodiscard

获取槽总数 / Get the total number of slots.

Returns
槽总数 / Total number of slots

Definition at line 113 of file slot_pool.hpp.

113{ return slot_count_; }

◆ SlotPtr() [1/2]

void * LibXR::SlotPoolBase::SlotPtr ( size_t index)
nodiscardprotected

获取指定槽位的存储地址 / Get the storage address of one slot.

Definition at line 202 of file slot_pool.cpp.

203{
204 ASSERT(index < slot_count_);
205 return slots_ + index * slot_stride_;
206}

◆ SlotPtr() [2/2]

const void * LibXR::SlotPoolBase::SlotPtr ( size_t index) const
nodiscardprotected

获取指定槽位的存储地址(只读)/ Get the storage address of one slot (const).

Definition at line 208 of file slot_pool.cpp.

209{
210 ASSERT(index < slot_count_);
211 return slots_ + index * slot_stride_;
212}

◆ Take()

ErrorCode LibXR::SlotPoolBase::Take ( size_t & index)

认领序号最小的就绪槽(就绪 → 读取中) / Claim the oldest ready slot (ready -> reading).

Parameters
index成功时写入认领的槽位下标 / Receives the claimed slot index on success
Returns
成功返回 ErrorCode::OK;没有就绪槽返回 ErrorCode::EMPTY Returns ErrorCode::OK on success; ErrorCode::EMPTY when no slot is ready

槽之间按发布序号挑选(序号比较允许回绕):同一发布者内部严格保序;一个 还没发布完的槽不会挡住其他就绪槽,因此不同发布者之间不保证先进先出。 Slots are selected by publish sequence (wraparound-safe comparison): each publisher keeps its own order, and a slot that is not published yet never hides other ready slots, so there is no FIFO guarantee across publishers.

Definition at line 104 of file slot_pool.cpp.

105{
106 bool rescanned = false;
107
108 for (;;)
109 {
110 // 本轮开始时的发布计数:本轮开始前就绪的条目,序号都早于它。
111 // Publish count at the start of this pass: every item that was ready before
112 // the pass began has a sequence before it.
113 const uint32_t pass_begin = publish_seq_.load(std::memory_order_acquire);
114 size_t best = INVALID_INDEX;
115 uint32_t best_seq = 0;
116
117 for (size_t i = 0; i < slot_count_; ++i)
118 {
119 if (states_[i].load(std::memory_order_acquire) != SLOT_READY)
120 {
121 continue;
122 }
123
124 const uint32_t seq = seqs_[i].load(std::memory_order_relaxed);
125 if (best == INVALID_INDEX || SeqBefore(seq, best_seq))
126 {
127 best = i;
128 best_seq = seq;
129 }
130 }
131
132 if (best != INVALID_INDEX)
133 {
134 // 选中的条目在本轮开始后才取得序号时,同一发布者更早的条目可能在本轮
135 // 扫过它的槽之后才就绪而被漏掉:重新扫描,直到选中的条目早于本轮开始。
136 // 单核上中断里的扫描不会被低优先级上下文的发布插入,不会走到这里。
137 // When the chosen item took its sequence after this pass began, an earlier
138 // item of the same publisher may have become ready only after the pass had
139 // scanned its slot: rescan until the chosen item predates the pass. On a
140 // single core, a scan inside an interrupt cannot be interleaved with
141 // publications from lower-priority contexts, so it never gets here.
142 if (!SeqBefore(best_seq, pass_begin))
143 {
144 continue;
145 }
146
147 uint32_t expected = SLOT_READY;
148 if (states_[best].compare_exchange_strong(expected, SLOT_READING,
149 std::memory_order_acq_rel,
150 std::memory_order_acquire))
151 {
152 // CAS 成功后复读序号:扫描到 CAS 之间该槽若被取走、释放并重新发布,
153 // CAS 赢到的是新条目。撤销本次认领(读取中 → 就绪),把新条目留在
154 // 池里,重新扫描,保证选中的仍是最早发布项。
155 // Re-read the sequence after a winning CAS: if the slot was taken,
156 // released and re-published between the scan and the CAS, the CAS won
157 // the NEW item. Undo this claim (reading -> ready) to leave the new
158 // item in the pool, then rescan so the oldest item still wins.
159 if (seqs_[best].load(std::memory_order_relaxed) == best_seq)
160 {
161 index = best;
162 return ErrorCode::OK;
163 }
164 uint32_t reading = SLOT_READING;
165 const bool undone = states_[best].compare_exchange_strong(
166 reading, SLOT_READY, std::memory_order_release, std::memory_order_acquire);
167 ASSERT(undone);
168 continue;
169 }
170 // 该槽刚被其他消费者取走:重新扫描。
171 // Another consumer just claimed the slot: rescan.
172 continue;
173 }
174
175 const uint32_t publish_end = publish_seq_.load(std::memory_order_acquire);
176 if (publish_end == pass_begin || rescanned)
177 {
178 return ErrorCode::EMPTY;
179 }
180 rescanned = true;
181 }
182}
static constexpr size_t INVALID_INDEX
无效槽位下标 / Sentinel for "no slot chosen".
@ EMPTY
为空 / Empty

Member Data Documentation

◆ alloc_align_

const size_t LibXR::SlotPoolBase::alloc_align_
protected

槽存储的分配对齐 / Allocation alignment of the slot storage.

Definition at line 136 of file slot_pool.hpp.

◆ INVALID_INDEX

size_t LibXR::SlotPoolBase::INVALID_INDEX = static_cast<size_t>(-1)
staticconstexprprotected

无效槽位下标 / Sentinel for "no slot chosen".

Definition at line 122 of file slot_pool.hpp.

◆ publish_seq_

std::atomic<uint32_t> LibXR::SlotPoolBase::publish_seq_
protected

发布序号计数器,兼作 Take 重扫的发布计数 / Publish counter, also the change detector for the Take rescan.

Definition at line 144 of file slot_pool.hpp.

◆ release_count_

std::atomic<uint32_t> LibXR::SlotPoolBase::release_count_
protected

释放计数,Acquire 重扫的变化检测 / Release counter, the change detector for the Acquire rescan.

Definition at line 147 of file slot_pool.hpp.

◆ seqs_

std::atomic<uint32_t>* LibXR::SlotPoolBase::seqs_
protected

每槽发布序号 / Per-slot publish sequence.

Definition at line 139 of file slot_pool.hpp.

◆ slot_count_

const size_t LibXR::SlotPoolBase::slot_count_
protected

槽总数 / Total number of slots.

Definition at line 134 of file slot_pool.hpp.

◆ slot_size_

const size_t LibXR::SlotPoolBase::slot_size_
protected

单个槽的字节数 / Byte size of one slot.

Definition at line 133 of file slot_pool.hpp.

◆ slot_stride_

const size_t LibXR::SlotPoolBase::slot_stride_
protected

相邻槽位之间的步长 / Byte stride between slots.

Definition at line 135 of file slot_pool.hpp.

◆ slots_

std::byte* LibXR::SlotPoolBase::slots_
protected

槽存储缓冲区 / Byte buffer storing slots.

Definition at line 140 of file slot_pool.hpp.

◆ states_

std::atomic<uint32_t>* LibXR::SlotPoolBase::states_
protected

每槽状态字 / Per-slot atomic state word.

Definition at line 138 of file slot_pool.hpp.


The documentation for this class was generated from the following files: