61 m_seq.fetch_add(1U, std::memory_order_release);
71 m_seq.fetch_add(1U, std::memory_order_release);
86 v =
m_seq.load(std::memory_order_acquire);
97 [[nodiscard]]
bool read_retry(uint32_t snapshot)
const noexcept
99 std::atomic_thread_fence(std::memory_order_acquire);
100 return m_seq.load(std::memory_order_relaxed) != snapshot;
111 return m_seq.load(std::memory_order_relaxed);
190template <std::invocable Fn>
193 uint32_t max_attempts,
194 Fn&& fn) -> std::optional<std::invoke_result_t<Fn>>
196 uint32_t attempts = 0;
197 while (max_attempts == 0 || attempts < max_attempts) {
198 uint32_t snap = lock.read_begin();
199 auto result = std::invoke(std::forward<Fn>(fn));
200 if (!lock.read_retry(snap))
220template <std::invocable Fn>
221 requires std::is_void_v<std::invoke_result_t<Fn>>
224 uint32_t max_attempts,
227 uint32_t attempts = 0;
228 while (max_attempts == 0 || attempts < max_attempts) {
230 std::invoke(std::forward<Fn>(fn));
297 for (
size_t i = 0; i < n; ++i)
298 m_slots.emplace_back(std::make_unique<Seqlock>());
304 [[nodiscard]]
size_t size() const noexcept {
return m_slots.size(); }
319 std::vector<std::unique_ptr<Seqlock>>
m_slots;
const Seqlock & operator[](size_t i) const noexcept
Access the Seqlock at index i (const overload).
SeqlockArray & operator=(SeqlockArray &&)=delete
SeqlockArray(SeqlockArray &&)=delete
void resize(size_t n)
Replace the slot array with n default-constructed Seqlock instances.
SeqlockArray & operator=(const SeqlockArray &)=delete
size_t size() const noexcept
Number of slots.
Seqlock & operator[](size_t i) noexcept
Access the Seqlock at index i.
std::vector< std::unique_ptr< Seqlock > > m_slots
SeqlockArray(const SeqlockArray &)=delete
Indexed collection of independent, equal-ranked Seqlock instances.
SeqlockWriteGuard(SeqlockWriteGuard &&)=delete
SeqlockWriteGuard(const SeqlockWriteGuard &)=delete
SeqlockWriteGuard & operator=(SeqlockWriteGuard &&)=delete
SeqlockWriteGuard & operator=(const SeqlockWriteGuard &)=delete
SeqlockWriteGuard(Seqlock &lock) noexcept
~SeqlockWriteGuard() noexcept
RAII guard that brackets a Seqlock write region.
void end_write() noexcept
End a write: advances the counter back to an even value.
uint32_t read_begin() const noexcept
Begin a read: spin until the counter is even, return the snapshot.
uint32_t sequence() const noexcept
Return the raw sequence counter value.
bool read_retry(uint32_t snapshot) const noexcept
Check whether a write overlapped the read just completed.
std::atomic< uint32_t > m_seq
void begin_write() noexcept
Begin a write: advances the counter to an odd value.
Seqlock() noexcept=default
Single-writer multiple-reader sequence lock for fixed-size data regions.
auto seqlock_read(const Seqlock &lock, uint32_t max_attempts, Fn &&fn) -> std::optional< std::invoke_result_t< Fn > >
Invoke a read functor under a Seqlock with a bounded retry count.
bool seqlock_read_void(const Seqlock &lock, uint32_t max_attempts, Fn &&fn)
Invoke a void read functor under a Seqlock with a bounded retry count.