diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2019-06-06 12:27:26 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2019-06-10 16:56:17 +0000 |
commit | 620f12120618ae548575c741a9dc54e405aefed4 (patch) | |
tree | 54ac78189cd5a35785e898e6aafb5bb90a3bd4cb /src | |
parent | efe1073e440fd7a179da8d19abc43fb9a745ac2f (diff) |
QAtomic: introduce loadRelaxed() / storeRelaxed()
Plain load() / store() have already relaxed semantics. This
can be surprising -- std::atomic::load()/store() are actually
sequentially consistent -- and introduce a pain point
if someone wants to move from Qt atomics to std:: atomics.
So just add a suffix to the functions to clarify what's the
memory ordering involved with them.
The Ops::load / ::store are temporarily left in, because other
modules depends on them. We need to port those modules away,
then they can go (it's private API anyhow).
Similarly, not deprecating anything yet, except for marking
obsolete in the docs; there's a lot of code around using
load() / store() that needs to be ported first.
[ChangeLog][QtCore][QAtomicInteger] Added loadRelaxed() and
storeRelaxed(), to be used as replacements of load() / store().
[ChangeLog][QtCore][QAtomicPointer] Added loadRelaxed() and
storeRelaxed(), to be used as replacements of load() / store().
Change-Id: Iab0a78885050379e3740f0b039ba2bef28ce3bd2
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/thread/qatomic.cpp | 75 | ||||
-rw-r--r-- | src/corelib/thread/qatomic.h | 4 | ||||
-rw-r--r-- | src/corelib/thread/qatomic_cxx11.h | 18 | ||||
-rw-r--r-- | src/corelib/thread/qbasicatomic.h | 14 | ||||
-rw-r--r-- | src/corelib/thread/qgenericatomic.h | 22 |
5 files changed, 113 insertions, 20 deletions
diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp index c161bec537..b1a7edad91 100644 --- a/src/corelib/thread/qatomic.cpp +++ b/src/corelib/thread/qatomic.cpp @@ -258,12 +258,26 @@ /*! \fn template <typename T> T QAtomicInteger<T>::load() const + \obsolete + + Use loadRelaxed() instead. Atomically loads the value of this QAtomicInteger using relaxed memory ordering. The value is not modified in any way, but note that there's no guarantee that it remains so. - \sa store(), loadAcquire() + \sa storeRelaxed(), loadAcquire() +*/ + +/*! + \fn template <typename T> T QAtomicInteger<T>::loadRelaxed() const + \since 5.14 + + Atomically loads the value of this QAtomicInteger using relaxed memory + ordering. The value is not modified in any way, but note that there's no + guarantee that it remains so. + + \sa storeRelaxed(), loadAcquire() */ /*! @@ -273,16 +287,29 @@ ordering. The value is not modified in any way, but note that there's no guarantee that it remains so. - \sa store(), load() + \sa storeRelaxed(), loadRelaxed() */ /*! \fn template <typename T> void QAtomicInteger<T>::store(T newValue) + \obsolete + + Use storeRelaxed() instead. Atomically stores the \a newValue value into this atomic type, using relaxed memory ordering. - \sa storeRelease(), load() + \sa storeRelease(), loadRelaxed() +*/ + +/*! + \fn template <typename T> void QAtomicInteger<T>::storeRelaxed(T newValue) + \since 5.14 + + Atomically stores the \a newValue value into this atomic type, using + relaxed memory ordering. + + \sa storeRelease(), loadRelaxed() */ /*! @@ -291,7 +318,7 @@ Atomically stores the \a newValue value into this atomic type, using the "Release" memory ordering. - \sa store(), load() + \sa store(), loadAcquire() */ /*! @@ -303,7 +330,7 @@ value is not modified in any way, but note that there's no guarantee that it remains so. - \sa load(), loadAcquire() + \sa loadRelaxed(), loadAcquire() */ /*! @@ -314,7 +341,7 @@ sequentially consistent memory ordering if possible; or "Release" ordering if not. This function returns a reference to this object. - \sa store(), storeRelease() + \sa storeRelaxed(), storeRelease() */ /*! \fn template <typename T> bool QAtomicInteger<T>::isReferenceCountingNative() @@ -1278,31 +1305,59 @@ /*! \fn template <typename T> T *QAtomicPointer<T>::load() const + \obsolete + + Use loadRelaxed() instead. Atomically loads the value of this QAtomicPointer using relaxed memory ordering. The value is not modified in any way, but note that there's no guarantee that it remains so. - \sa store(), loadAcquire() + \sa storeRelaxed(), loadAcquire() */ /*! + \fn template <typename T> T *QAtomicPointer<T>::loadRelaxed() const + \since 5.14 + + Atomically loads the value of this QAtomicPointer using relaxed memory + ordering. The value is not modified in any way, but note that there's no + guarantee that it remains so. + + \sa storeRelaxed(), loadAcquire() +*/ + + +/*! \fn template <typename T> T *QAtomicPointer<T>::loadAcquire() const Atomically loads the value of this QAtomicPointer using the "Acquire" memory ordering. The value is not modified in any way, but note that there's no guarantee that it remains so. - \sa store(), load() + \sa storeRelease(), loadRelaxed() */ /*! \fn template <typename T> void QAtomicPointer<T>::store(T *newValue) + \obsolete + + Use storeRelaxed() instead. + + Atomically stores the \a newValue value into this atomic type, using + relaxed memory ordering. + + \sa storeRelease(), loadRelaxed() +*/ + +/*! + \fn template <typename T> void QAtomicPointer<T>::storeRelaxed(T *newValue) + \since 5.14 Atomically stores the \a newValue value into this atomic type, using relaxed memory ordering. - \sa storeRelease(), load() + \sa storeRelease(), loadRelaxed() */ /*! @@ -1311,7 +1366,7 @@ Atomically stores the \a newValue value into this atomic type, using the "Release" memory ordering. - \sa store(), load() + \sa storeRelaxed(), loadRelaxed() */ /*! \fn template <typename T> bool QAtomicPointer<T>::isTestAndSetNative() diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h index 280ce96b76..7990db2fd9 100644 --- a/src/corelib/thread/qatomic.h +++ b/src/corelib/thread/qatomic.h @@ -81,8 +81,10 @@ public: #ifdef Q_CLANG_QDOC T load() const; + T loadRelaxed() const; T loadAcquire() const; void store(T newValue); + void storeRelaxed(T newValue); void storeRelease(T newValue); operator T() const; @@ -172,7 +174,7 @@ public: #else inline QAtomicPointer(T *value = nullptr) noexcept { - this->store(value); + this->storeRelaxed(value); } #endif inline QAtomicPointer(const QAtomicPointer<T> &other) noexcept diff --git a/src/corelib/thread/qatomic_cxx11.h b/src/corelib/thread/qatomic_cxx11.h index 2851bae73e..7386aee126 100644 --- a/src/corelib/thread/qatomic_cxx11.h +++ b/src/corelib/thread/qatomic_cxx11.h @@ -234,6 +234,18 @@ template <typename X> struct QAtomicOps } template <typename T> static inline + T loadRelaxed(const std::atomic<T> &_q_value) noexcept + { + return _q_value.load(std::memory_order_relaxed); + } + + template <typename T> static inline + T loadRelaxed(const volatile std::atomic<T> &_q_value) noexcept + { + return _q_value.load(std::memory_order_relaxed); + } + + template <typename T> static inline T loadAcquire(const std::atomic<T> &_q_value) noexcept { return _q_value.load(std::memory_order_acquire); @@ -252,6 +264,12 @@ template <typename X> struct QAtomicOps } template <typename T> static inline + void storeRelaxed(std::atomic<T> &_q_value, T newValue) noexcept + { + _q_value.store(newValue, std::memory_order_relaxed); + } + + template <typename T> static inline void storeRelease(std::atomic<T> &_q_value, T newValue) noexcept { _q_value.store(newValue, std::memory_order_release); diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index 7d2e06a499..dc976819ef 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -99,9 +99,11 @@ public: typename Ops::Type _q_value; // Everything below is either implemented in ../arch/qatomic_XXX.h or (as fallback) in qgenericatomic.h + T load() const noexcept { return loadRelaxed(); } + void store(T newValue) noexcept { storeRelaxed(newValue); } - T load() const noexcept { return Ops::load(_q_value); } - void store(T newValue) noexcept { Ops::store(_q_value, newValue); } + T loadRelaxed() const noexcept { return Ops::loadRelaxed(_q_value); } + void storeRelaxed(T newValue) noexcept { Ops::storeRelaxed(_q_value, newValue); } T loadAcquire() const noexcept { return Ops::loadAcquire(_q_value); } void storeRelease(T newValue) noexcept { Ops::storeRelease(_q_value, newValue); } @@ -236,8 +238,12 @@ public: AtomicType _q_value; - Type load() const noexcept { return Ops::load(_q_value); } - void store(Type newValue) noexcept { Ops::store(_q_value, newValue); } + Type load() const noexcept { return loadRelaxed(); } + void store(Type newValue) noexcept { storeRelaxed(newValue); } + + Type loadRelaxed() const noexcept { return Ops::loadRelaxed(_q_value); } + void storeRelaxed(Type newValue) noexcept { Ops::storeRelaxed(_q_value, newValue); } + operator Type() const noexcept { return loadAcquire(); } Type operator=(Type newValue) noexcept { storeRelease(newValue); return newValue; } diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h index f8333e7de6..e9e5f3c74b 100644 --- a/src/corelib/thread/qgenericatomic.h +++ b/src/corelib/thread/qgenericatomic.h @@ -97,6 +97,18 @@ template <typename BaseClass> struct QGenericAtomicOps } template <typename T> static Q_ALWAYS_INLINE + T loadRelaxed(const T &_q_value) noexcept + { + return _q_value; + } + + template <typename T, typename X> static Q_ALWAYS_INLINE + void storeRelaxed(T &_q_value, X newValue) noexcept + { + _q_value = newValue; + } + + template <typename T> static Q_ALWAYS_INLINE T loadAcquire(const T &_q_value) noexcept { T tmp = *static_cast<const volatile T *>(&_q_value); @@ -190,7 +202,7 @@ template <typename BaseClass> struct QGenericAtomicOps { // implement fetchAndStore on top of testAndSet Q_FOREVER { - T tmp = load(_q_value); + T tmp = loadRelaxed(_q_value); if (BaseClass::testAndSetRelaxed(_q_value, tmp, newValue)) return tmp; } @@ -225,7 +237,7 @@ template <typename BaseClass> struct QGenericAtomicOps { // implement fetchAndAdd on top of testAndSet Q_FOREVER { - T tmp = BaseClass::load(_q_value); + T tmp = BaseClass::loadRelaxed(_q_value); if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp + valueToAdd))) return tmp; } @@ -289,7 +301,7 @@ QT_WARNING_POP T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept { // implement fetchAndAnd on top of testAndSet - T tmp = BaseClass::load(_q_value); + T tmp = BaseClass::loadRelaxed(_q_value); Q_FOREVER { if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp & operand), &tmp)) return tmp; @@ -322,7 +334,7 @@ QT_WARNING_POP T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept { // implement fetchAndOr on top of testAndSet - T tmp = BaseClass::load(_q_value); + T tmp = BaseClass::loadRelaxed(_q_value); Q_FOREVER { if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp | operand), &tmp)) return tmp; @@ -355,7 +367,7 @@ QT_WARNING_POP T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) noexcept { // implement fetchAndXor on top of testAndSet - T tmp = BaseClass::load(_q_value); + T tmp = BaseClass::loadRelaxed(_q_value); Q_FOREVER { if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp ^ operand), &tmp)) return tmp; |