22#include <condition_variable>
27#ifdef USE_STD_CONCEPTS
31#ifdef HAS_STD_ATOMIC_WAIT
64 static_assert(std::is_trivially_copyable<T>::value,
65 "T must be trivially copyable for atomic operations");
81 void wait(std::atomic<T>& atomic, T old)
noexcept {
84 constexpr int SPIN_COUNT = 40;
85 for (
int i = 0; i < SPIN_COUNT; ++i) {
86 if (atomic.load(std::memory_order_acquire) != old) {
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");
95 std::this_thread::yield();
101 constexpr int BACKOFF_COUNT = 5;
102 auto backoff_time = std::chrono::microseconds(1);
104 for (
int i = 0; i < BACKOFF_COUNT; ++i) {
105 if (atomic.load(std::memory_order_acquire) != old) {
108 std::this_thread::sleep_for(backoff_time);
114 std::unique_lock<std::mutex> lock(
mutex_);
116 return atomic.load(std::memory_order_acquire) != old;
129 std::lock_guard<std::mutex> lock(
mutex_);
139 std::lock_guard<std::mutex> lock(
mutex_);
145 mutable std::condition_variable
cv_;
179 T
load(std::memory_order order = std::memory_order_seq_cst)
const noexcept {
180 return value_.load(order);
183 void store(T desired, std::memory_order order = std::memory_order_seq_cst)
noexcept {
184 value_.store(desired, order);
187 T
exchange(T desired, std::memory_order order = std::memory_order_seq_cst)
noexcept {
188 return value_.exchange(desired, order);
192 std::memory_order order = std::memory_order_seq_cst)
noexcept {
193 return value_.compare_exchange_weak(expected, desired, order);
197 std::memory_order order = std::memory_order_seq_cst)
noexcept {
198 return value_.compare_exchange_strong(expected, desired, order);
202 void wait(T old, std::memory_order order = std::memory_order_seq_cst)
noexcept {
215 operator T() const noexcept {
226#ifdef USE_STD_CONCEPTS
227 T
fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst)
noexcept
228 requires std::integral<T>
230 return value_.fetch_add(arg, order);
233 T
fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst)
noexcept
234 requires std::integral<T>
236 return value_.fetch_sub(arg, order);
240 requires
std::integral<T>
246 requires std::integral<T>
252 requires
std::integral<T>
258 requires std::integral<T>
264 template<
typename U = T>
265 typename std::enable_if<std::is_integral<U>::value, U>::type
266 fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst)
noexcept {
267 return value_.fetch_add(arg, order);
270 template<
typename U = T>
271 typename std::enable_if<std::is_integral<U>::value, U>::type
272 fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst)
noexcept {
273 return value_.fetch_sub(arg, order);
276 template<
typename U = T>
277 typename std::enable_if<std::is_integral<U>::value, U>::type
282 template<
typename U = T>
283 typename std::enable_if<std::is_integral<U>::value, U>::type
288 template<
typename U = T>
289 typename std::enable_if<std::is_integral<U>::value, U>::type
294 template<
typename U = T>
295 typename std::enable_if<std::is_integral<U>::value, U>::type
Helper class to add wait/notify functionality to std::atomic.
void notify_all() noexcept
Unblocks all threads waiting on this atomic.
std::condition_variable cv_
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.
RAII wrapper to add wait/notify to atomic variables.
std::enable_if< std::is_integral< U >::value, U >::type operator--(int) noexcept
void store(T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
void notify_one() noexcept
T load(std::memory_order order=std::memory_order_seq_cst) const noexcept
void wait(T old, std::memory_order order=std::memory_order_seq_cst) noexcept
atomic_with_wait(T initial) noexcept
T operator=(T desired) noexcept
bool compare_exchange_weak(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
void notify_all() noexcept
atomic_wait_helper< T > waiter_
std::enable_if< std::is_integral< U >::value, U >::type operator++(int) noexcept
std::enable_if< std::is_integral< U >::value, U >::type operator--() noexcept
T exchange(T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
bool compare_exchange_strong(T &expected, T desired, std::memory_order order=std::memory_order_seq_cst) noexcept
std::enable_if< std::is_integral< U >::value, U >::type fetch_add(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
atomic_with_wait(const atomic_with_wait &)=delete
std::enable_if< std::is_integral< U >::value, U >::type operator++() noexcept
atomic_with_wait & operator=(const atomic_with_wait &)=delete
atomic_with_wait() noexcept
std::enable_if< std::is_integral< U >::value, U >::type fetch_sub(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Core threading foundation of the thread system library.