diff options
author | arkady-e1ppa <arkady-e1ppa@yandex-team.com> | 2024-10-14 17:25:51 +0300 |
---|---|---|
committer | arkady-e1ppa <arkady-e1ppa@yandex-team.com> | 2024-10-14 17:40:51 +0300 |
commit | 3b92e669413cdc39137dbfd1d23417b23ef276ef (patch) | |
tree | 8e5709b2cbef24a7f0b42ad82574252896bb2dc7 /library/cpp | |
parent | d74394815fdeebaee897571642e270f3d459557e (diff) | |
download | ydb-3b92e669413cdc39137dbfd1d23417b23ef276ef.tar.gz |
Move atomic object to library/cpp/yt/threading
[nodiff:caesar]
commit_hash:446e45e0378f6b2cb31d85bcc3e4516efbdfe5a7
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/yt/threading/atomic_object-inl.h | 97 | ||||
-rw-r--r-- | library/cpp/yt/threading/atomic_object.h | 63 |
2 files changed, 160 insertions, 0 deletions
diff --git a/library/cpp/yt/threading/atomic_object-inl.h b/library/cpp/yt/threading/atomic_object-inl.h new file mode 100644 index 00000000000..452f5a0bc77 --- /dev/null +++ b/library/cpp/yt/threading/atomic_object-inl.h @@ -0,0 +1,97 @@ +#ifndef ATOMIC_OBJECT_INL_H_ +#error "Direct inclusion of this file is not allowed, include atomic_object.h" +// For the sake of sane code completion. +#include "atomic_object.h" +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +template <class U> +TAtomicObject<T>::TAtomicObject(U&& u) + : Object_(std::forward<U>(u)) +{ } + +template <class T> +template <class U> +void TAtomicObject<T>::Store(U&& u) +{ + // NB: Using exchange to avoid destructing the old object while holding the lock. + std::ignore = Exchange(std::forward<U>(u)); +} + +template <class T> +template <class U> +T TAtomicObject<T>::Exchange(U&& u) +{ + T tmpObject = std::forward<U>(u); + { + auto guard = WriterGuard(Spinlock_); + std::swap(Object_, tmpObject); + } + return tmpObject; +} + +template <class T> +bool TAtomicObject<T>::CompareExchange(T& expected, const T& desired) +{ + auto guard = WriterGuard(Spinlock_); + if (Object_ == expected) { + auto oldObject = std::move(Object_); + Y_UNUSED(oldObject); + Object_ = desired; + guard.Release(); + return true; + } else { + auto oldExpected = std::move(expected); + Y_UNUSED(oldExpected); + expected = Object_; + guard.Release(); + return false; + } +} + +template <class T> +template <std::invocable<T&> F> +std::invoke_result_t<F, T&> TAtomicObject<T>::Transform(const F& func) +{ + auto guard = WriterGuard(Spinlock_); + return func(Object_); +} + +template <class T> +template <std::invocable<const T&> F> +std::invoke_result_t<F, const T&> TAtomicObject<T>::Read(const F& func) const +{ + auto guard = ReaderGuard(Spinlock_); + return func(Object_); +} + +template <class T> +T TAtomicObject<T>::Load() const +{ + auto guard = ReaderGuard(Spinlock_); + return Object_; +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class TOriginal, class TSerialized> +void ToProto(TSerialized* serialized, const TAtomicObject<TOriginal>& original) +{ + ToProto(serialized, original.Load()); +} + +template <class TOriginal, class TSerialized> +void FromProto(TAtomicObject<TOriginal>* original, const TSerialized& serialized) +{ + TOriginal data; + FromProto(&data, serialized); + original->Store(std::move(data)); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/threading/atomic_object.h b/library/cpp/yt/threading/atomic_object.h new file mode 100644 index 00000000000..e986f872a08 --- /dev/null +++ b/library/cpp/yt/threading/atomic_object.h @@ -0,0 +1,63 @@ +#pragma once + +#include <library/cpp/yt/threading/rw_spin_lock.h> + +#include <concepts> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +//! A synchronization object to load and store nontrivial object. +//! It looks like atomics but for objects. +template <class T> +class TAtomicObject +{ +public: + TAtomicObject() = default; + + template <class U> + TAtomicObject(U&& u); + + template <class U> + void Store(U&& u); + + //! Atomically replaces the old value with the new one and returns the old value. + template <class U> + T Exchange(U&& u); + + //! Atomically checks if then current value equals #expected. + //! If so, replaces it with #desired and returns |true|. + //! Otherwise, copies it into #expected and returns |false|. + bool CompareExchange(T& expected, const T& desired); + + //! Atomically transforms the value with function #func. + template <std::invocable<T&> F> + std::invoke_result_t<F, T&> Transform(const F& func); + + //! Atomicaly reads the value with function #func. + template <std::invocable<const T&> F> + std::invoke_result_t<F, const T&> Read(const F& func) const; + + T Load() const; + +private: + T Object_; + YT_DECLARE_SPIN_LOCK(NThreading::TReaderWriterSpinLock, Spinlock_); +}; + +//////////////////////////////////////////////////////////////////////////////// + +template <class TOriginal, class TSerialized> +void ToProto(TSerialized* serialized, const TAtomicObject<TOriginal>& original); + +template <class TOriginal, class TSerialized> +void FromProto(TAtomicObject<TOriginal>* original, const TSerialized& serialized); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define ATOMIC_OBJECT_INL_H_ +#include "atomic_object-inl.h" +#undef ATOMIC_OBJECT_INL_H_ |