diff options
author | Chris Robinson <[email protected]> | 2024-01-01 10:53:52 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2024-01-01 10:53:52 -0800 |
commit | aa23d619324ca7e9d51829a2cc5d276c98305eb9 (patch) | |
tree | 59aba746e891409b01655c332a5aa4887217176b | |
parent | a03bfe04c16fa2df0ac86cde53154ca99c18ad53 (diff) |
Make and use a (simple) atomic unique_ptr
-rw-r--r-- | common/atomic.h | 66 | ||||
-rw-r--r-- | core/context.cpp | 4 | ||||
-rw-r--r-- | core/context.h | 2 |
3 files changed, 69 insertions, 3 deletions
diff --git a/common/atomic.h b/common/atomic.h index a579dcab..51ddaa5d 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -2,7 +2,9 @@ #define AL_ATOMIC_H #include <atomic> +#include <memory> +#include "almalloc.h" template<typename T> auto IncrementRef(std::atomic<T> &ref) noexcept @@ -27,4 +29,68 @@ inline void AtomicReplaceHead(std::atomic<T> &head, T newhead) std::memory_order_acq_rel, std::memory_order_acquire)); } +namespace al { + +template<typename T, typename D=std::default_delete<T>> +class atomic_unique_ptr { + std::atomic<gsl::owner<T*>> mPointer{}; + +public: + atomic_unique_ptr() = default; + atomic_unique_ptr(const atomic_unique_ptr&) = delete; + explicit atomic_unique_ptr(std::nullptr_t) noexcept { } + explicit atomic_unique_ptr(gsl::owner<T*> ptr) noexcept : mPointer{ptr} { } + explicit atomic_unique_ptr(std::unique_ptr<T>&& rhs) noexcept : mPointer{rhs.release()} { } + ~atomic_unique_ptr() { if(auto ptr = mPointer.load(std::memory_order_relaxed)) D{}(ptr); } + + atomic_unique_ptr& operator=(const atomic_unique_ptr&) = delete; + atomic_unique_ptr& operator=(std::nullptr_t) noexcept + { + if(auto ptr = mPointer.exchange(nullptr)) + D{}(ptr); + return *this; + } + atomic_unique_ptr& operator=(std::unique_ptr<T>&& rhs) noexcept + { + if(auto ptr = mPointer.exchange(rhs.release())) + D{}(ptr); + return *this; + } + + [[nodiscard]] + T* load(std::memory_order m=std::memory_order_seq_cst) const { return mPointer.load(m); } + void store(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept + { + if(auto oldptr = mPointer.exchange(nullptr, m)) + D{}(oldptr); + } + void store(gsl::owner<T*> ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { + if(auto oldptr = mPointer.exchange(ptr, m)) + D{}(oldptr); + } + void store(std::unique_ptr<T>&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { + if(auto oldptr = mPointer.exchange(ptr.release(), m)) + D{}(oldptr); + } + + [[nodiscard]] + std::unique_ptr<T> exchange(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept + { return std::unique_ptr<T>{mPointer.exchange(nullptr, m)}; } + [[nodiscard]] + std::unique_ptr<T> exchange(gsl::owner<T*> ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { return std::unique_ptr<T>{mPointer.exchange(ptr, m)}; } + [[nodiscard]] + std::unique_ptr<T> exchange(std::unique_ptr<T>&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { return std::unique_ptr<T>{mPointer.exchange(ptr.release(), m)}; } + + [[nodiscard]] + bool is_lock_free() const noexcept { mPointer.is_lock_free(); } + + static constexpr auto is_always_lock_free = std::atomic<gsl::owner<T*>>::is_always_lock_free; +}; + +} // namespace al + #endif /* AL_ATOMIC_H */ diff --git a/core/context.cpp b/core/context.cpp index b969583b..cb00ae70 100644 --- a/core/context.cpp +++ b/core/context.cpp @@ -52,7 +52,7 @@ ContextBase::~ContextBase() if(std::unique_ptr<EffectSlotArray> curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)}) std::destroy_n(curarray->end(), curarray->size()); - std::unique_ptr<ContextBase::VoiceArray>{mVoices.exchange(nullptr, std::memory_order_relaxed)}; + mVoices.store(nullptr, std::memory_order_relaxed); if(mAsyncEvents) { @@ -142,7 +142,7 @@ void ContextBase::allocVoices(size_t addcount) voice_iter = std::transform(cluster->begin(), cluster->end(), voice_iter, [](Voice &voice) noexcept -> Voice* { return &voice; }); - if(std::unique_ptr<ContextBase::VoiceArray> oldvoices{mVoices.exchange(newarray.release(), std::memory_order_acq_rel)}) + if(auto oldvoices = mVoices.exchange(std::move(newarray), std::memory_order_acq_rel)) std::ignore = mDevice->waitForMix(); } diff --git a/core/context.h b/core/context.h index 0b830205..6fc1ed5d 100644 --- a/core/context.h +++ b/core/context.h @@ -112,7 +112,7 @@ struct ContextBase { ContextParams mParams; using VoiceArray = al::FlexArray<Voice*>; - std::atomic<VoiceArray*> mVoices{}; + al::atomic_unique_ptr<VoiceArray> mVoices{}; std::atomic<size_t> mActiveVoiceCount{}; void allocVoices(size_t addcount); |