#pragma once #include #include #include // Based on https://github.com/ademakov/Evenk namespace concurrency { struct NoBackoff { bool operator()() { return true; } }; struct YieldBackoff { bool operator()() { std::this_thread::yield(); return false; } }; class SpinLock { std::atomic_flag lock_flag = ATOMIC_FLAG_INIT; public: SpinLock() = default; SpinLock(const SpinLock &) = delete; SpinLock &operator=(const SpinLock &) = delete; void lock() noexcept { lock(NoBackoff {}); } template void lock(Backoff backoff) noexcept { while (lock_flag.test_and_set(std::memory_order_acquire)) { backoff(); } } void unlock() noexcept { lock_flag.clear(std::memory_order_release); } }; template class Atomic { concurrency::SpinLock lock; std::atomic value; public: Atomic() = default; explicit Atomic(T init) { this->operator=(init); } void operator=(T value) { std::lock_guard lck(this->lock); this->value = value; } T operator()() { std::lock_guard lck(this->lock); return this->value; } operator bool() { std::lock_guard lck(this->lock); return this->value; } bool operator==(T const& b) { std::lock_guard lck(this->lock); return this->value == b; } }; template class Value { concurrency::SpinLock lock; T value; public: Value() = default; explicit Value(T init) { this->operator=(init); } void operator=(T value) { std::lock_guard lck(this->lock); this->value = value; } T operator()() { std::lock_guard lck(this->lock); return this->value; } operator bool() { std::lock_guard lck(this->lock); return this->value; } bool operator==(T const& b) { std::lock_guard lck(this->lock); return this->value == b; } }; }