@@ -79,6 +79,9 @@ BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32(volatile boost::uin
7979// ! Atomically read an boost::uint32_t from memory with acquire semantics
8080BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32_acquire (volatile boost::uint32_t *mem);
8181
82+ // ! Atomically read an boost::uint32_t from memory with relaxed semantics.
83+ BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32_relaxed (volatile boost::uint32_t *mem);
84+
8285// ! Atomically set an boost::uint32_t in memory
8386// ! "mem": pointer to the object
8487// ! "param": val value that the object will assume
@@ -294,6 +297,26 @@ BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32_acquire(volatile bo
294297 #endif
295298}
296299
300+ // ! Same as atomic_read32, but with relaxed semantics
301+ BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32_relaxed (volatile boost::uint32_t *mem)
302+ {
303+ #if defined(__ATOMIC_RELAXED)
304+ // Clang (clang-cl included) and GCC: the same plain load instruction a
305+ // volatile read would give, but one that participates in the memory model,
306+ // so ThreadSanitizer does not flag it as racing other threads' writes
307+ return __atomic_load_n (mem, __ATOMIC_RELAXED);
308+ #elif defined(_M_ARM64EC) || defined(_M_ARM64) || defined(_M_ARM)
309+ // A plain 32 bit load the compiler cannot tear or widen and, unlike a
310+ // volatile read under /volatile:ms, one that carries no barrier
311+ return (boost::uint32_t )__iso_volatile_load32 (reinterpret_cast <const volatile __int32*>(mem));
312+ #else
313+ // x86/x64: an aligned volatile load is a single MOV, and a relaxed load
314+ // needs no barrier, not even a compiler-only one: the value is a hint
315+ // that only a later acquire operation may act on
316+ return *mem;
317+ #endif
318+ }
319+
297320// ! Atomically set an boost::uint32_t in memory
298321// ! "mem": pointer to the object
299322// ! "param": val value that the object will assume
@@ -599,6 +622,22 @@ BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32_acquire(volatile bo
599622 #endif
600623}
601624
625+ // ! Same as atomic_read32, but with relaxed semantics
626+ BOOST_INTERPROCESS_FORCEINLINE boost::uint32_t atomic_read32_relaxed (volatile boost::uint32_t *mem)
627+ {
628+ #if defined(__ATOMIC_RELAXED)
629+ // GCC 4.7 and later, Clang: the same plain load instruction a volatile
630+ // read would give, but one that participates in the memory model, so
631+ // ThreadSanitizer does not flag it as racing other threads' writes
632+ return __atomic_load_n (mem, __ATOMIC_RELAXED);
633+ #else
634+ // GCC 4.1 to 4.6: no __atomic builtins and no ThreadSanitizer either. An
635+ // aligned volatile load is a single load instruction on every supported
636+ // target, and a relaxed load needs no barrier around it
637+ return *mem;
638+ #endif
639+ }
640+
602641// ! Atomically set an boost::uint32_t in memory
603642// ! "mem": pointer to the object
604643// ! "param": val value that the object will assume
0 commit comments