Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
kcenon::thread::atomic_wait_helper< T > Class Template Reference

Helper class to add wait/notify functionality to std::atomic. More...

#include <atomic_wait.h>

Collaboration diagram for kcenon::thread::atomic_wait_helper< T >:
Collaboration graph

Public Member Functions

void wait (std::atomic< T > &atomic, T old) noexcept
 Blocks until the atomic value differs from the expected value.
 
void notify_one () noexcept
 Unblocks one thread waiting on this atomic.
 
void notify_all () noexcept
 Unblocks all threads waiting on this atomic.
 

Private Attributes

std::mutex mutex_
 
std::condition_variable cv_
 

Detailed Description

template<typename T>
class kcenon::thread::atomic_wait_helper< T >

Helper class to add wait/notify functionality to std::atomic.

This class provides atomic waiting primitives similar to C++20's std::atomic::wait/notify. It uses an efficient implementation with:

  • Short spin-wait to avoid syscalls for quickly-changing values
  • Mutex + condition_variable for blocking wait
  • Proper memory ordering to ensure correctness
Template Parameters
TThe atomic value type (must be trivially copyable)

Usage:

std::atomic<int> value{0};
// Thread 1: Wait until value changes from 0
waiter.wait(value, 0);
// Thread 2: Change value and notify
value.store(1, std::memory_order_release);
waiter.notify_one();
Helper class to add wait/notify functionality to std::atomic.
Definition atomic_wait.h:63
void notify_one() noexcept
Unblocks one thread waiting on this atomic.
void wait(std::atomic< T > &atomic, T old) noexcept
Blocks until the atomic value differs from the expected value.
Definition atomic_wait.h:81

Definition at line 63 of file atomic_wait.h.

Member Function Documentation

◆ notify_all()

template<typename T >
void kcenon::thread::atomic_wait_helper< T >::notify_all ( )
inlinenoexcept

Unblocks all threads waiting on this atomic.

All waiting threads will wake up and re-check their condition.

Definition at line 138 of file atomic_wait.h.

138 {
139 std::lock_guard<std::mutex> lock(mutex_);
140 cv_.notify_all();
141 }
std::condition_variable cv_

References kcenon::thread::atomic_wait_helper< T >::cv_, and kcenon::thread::atomic_wait_helper< T >::mutex_.

◆ notify_one()

template<typename T >
void kcenon::thread::atomic_wait_helper< T >::notify_one ( )
inlinenoexcept

Unblocks one thread waiting on this atomic.

If multiple threads are waiting, exactly one will be woken up. Which thread is unspecified (depends on scheduler).

Definition at line 126 of file atomic_wait.h.

126 {
127 // Lock-free fast path: if no waiters, skip mutex
128 // Note: This is an optimization, correctness doesn't depend on it
129 std::lock_guard<std::mutex> lock(mutex_);
130 cv_.notify_one();
131 }

References kcenon::thread::atomic_wait_helper< T >::cv_, and kcenon::thread::atomic_wait_helper< T >::mutex_.

◆ wait()

template<typename T >
void kcenon::thread::atomic_wait_helper< T >::wait ( std::atomic< T > & atomic,
T old )
inlinenoexcept

Blocks until the atomic value differs from the expected value.

This function implements an efficient wait with:

  1. Short spin-wait (SPIN_COUNT iterations)
  2. Exponential backoff
  3. Blocking wait on condition variable if still unchanged

Memory ordering: Uses acquire semantics to ensure proper synchronization

Parameters
atomicThe atomic variable to monitor
oldThe expected value to wait for change

Definition at line 81 of file atomic_wait.h.

81 {
82 // Phase 1: Short spin-wait
83 // Rationale: Many atomic operations complete quickly, avoiding syscall overhead
84 constexpr int SPIN_COUNT = 40;
85 for (int i = 0; i < SPIN_COUNT; ++i) {
86 if (atomic.load(std::memory_order_acquire) != old) {
87 return;
88 }
89 // Hint to CPU: this is a spin-wait loop
90 #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
91 __builtin_ia32_pause();
92 #elif defined(__aarch64__) || defined(_M_ARM64)
93 __asm__ __volatile__("yield" ::: "memory");
94 #else
95 std::this_thread::yield();
96 #endif
97 }
98
99 // Phase 2: Exponential backoff with brief sleeps
100 // Rationale: Longer operations benefit from yielding CPU
101 constexpr int BACKOFF_COUNT = 5;
102 auto backoff_time = std::chrono::microseconds(1);
103
104 for (int i = 0; i < BACKOFF_COUNT; ++i) {
105 if (atomic.load(std::memory_order_acquire) != old) {
106 return;
107 }
108 std::this_thread::sleep_for(backoff_time);
109 backoff_time *= 2; // Exponential backoff
110 }
111
112 // Phase 3: Blocking wait
113 // Rationale: Value hasn't changed after spin+backoff, use efficient blocking
114 std::unique_lock<std::mutex> lock(mutex_);
115 cv_.wait(lock, [&] {
116 return atomic.load(std::memory_order_acquire) != old;
117 });
118 }

References kcenon::thread::atomic_wait_helper< T >::cv_, and kcenon::thread::atomic_wait_helper< T >::mutex_.

Member Data Documentation

◆ cv_

◆ mutex_


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