@@ -202,6 +202,18 @@ std::enable_if_t<std::is_arithmetic_v<T>, bool> AtomicCompareExchangeAcquire(T *
202202#endif
203203}
204204
205+ template <typename T>
206+ std::enable_if_t <std::is_arithmetic_v<T>, bool > AtomicCompareExchangeRelease (T *ptr, T *expected, T *desired)
207+ {
208+ #ifndef _MSC_VER
209+ return __atomic_compare_exchange (ptr, expected, desired, /* weak=*/ false , __ATOMIC_RELEASE, __ATOMIC_RELAXED);
210+ #else
211+ // Cannot specify the memory order directly, use an unconditional fence to avoid branching code.
212+ std::atomic_thread_fence (std::memory_order_release);
213+ return MSVC ::AtomicOps<sizeof (T)>::CompareExchange (ptr, expected, desired);
214+ #endif
215+ }
216+
205217template <typename T>
206218std::enable_if_t <std::is_arithmetic_v<T>> AtomicAddCompareExchangeLoop (T *ptr, T val)
207219{
@@ -214,6 +226,18 @@ std::enable_if_t<std::is_arithmetic_v<T>> AtomicAddCompareExchangeLoop(T *ptr, T
214226 }
215227}
216228
229+ template <typename T>
230+ std::enable_if_t <std::is_arithmetic_v<T>> AtomicAddCompareExchangeReleaseLoop (T *ptr, T val)
231+ {
232+ T expected;
233+ AtomicLoad (ptr, &expected);
234+ T desired = expected + val;
235+ while (!AtomicCompareExchangeRelease (ptr, &expected, &desired)) {
236+ // expected holds the new value; try again.
237+ desired = expected + val;
238+ }
239+ }
240+
217241#ifdef _MSC_VER
218242namespace MSVC {
219243inline void AtomicOps<8 >::Add(void *ptr, const void *val)
@@ -243,17 +267,35 @@ std::enable_if_t<std::is_floating_point_v<T>> AtomicAdd(T *ptr, T val)
243267 AtomicAddCompareExchangeLoop (ptr, val);
244268}
245269
270+ template <typename T>
271+ std::enable_if_t <std::is_integral_v<T>> AtomicAddRelease (T *ptr, T val)
272+ {
273+ #ifndef _MSC_VER
274+ __atomic_fetch_add (ptr, val, __ATOMIC_RELEASE);
275+ #else
276+ // Cannot specify the memory order directly, use a fence.
277+ std::atomic_thread_fence (std::memory_order_release);
278+ MSVC ::AtomicOps<sizeof (T)>::Add (ptr, &val);
279+ #endif
280+ }
281+
282+ template <typename T>
283+ std::enable_if_t <std::is_floating_point_v<T>> AtomicAddRelease (T *ptr, T val)
284+ {
285+ AtomicAddCompareExchangeReleaseLoop (ptr, val);
286+ }
287+
246288// For adding a double-precision weight to a single-precision bin content type, cast the argument once before the
247289// compare-exchange loop.
248- static inline void AtomicAdd (float *ptr, double val)
290+ static inline void AtomicAddRelease (float *ptr, double val)
249291{
250- AtomicAdd (ptr, static_cast <float >(val));
292+ AtomicAddRelease (ptr, static_cast <float >(val));
251293}
252294
253295template <typename T>
254- std::enable_if_t <std::is_arithmetic_v<T>> AtomicInc (T *ptr)
296+ std::enable_if_t <std::is_arithmetic_v<T>> AtomicIncRelease (T *ptr)
255297{
256- AtomicAdd (ptr, static_cast <T>(1 ));
298+ AtomicAddRelease (ptr, static_cast <T>(1 ));
257299}
258300
259301template <typename T, typename U>
@@ -262,10 +304,16 @@ auto AtomicAdd(T *ptr, const U &add) -> decltype(ptr->AtomicAdd(add))
262304 return ptr->AtomicAdd (add);
263305}
264306
307+ template <typename T, typename U>
308+ auto AtomicAddRelease (T *ptr, const U &add) -> decltype(ptr->AtomicAddRelease (add))
309+ {
310+ return ptr->AtomicAddRelease (add);
311+ }
312+
265313template <typename T>
266- auto AtomicInc (T *ptr) -> decltype(ptr->AtomicInc ())
314+ auto AtomicIncRelease (T *ptr) -> decltype(ptr->AtomicIncRelease ())
267315{
268- return ptr->AtomicInc ();
316+ return ptr->AtomicIncRelease ();
269317}
270318
271319} // namespace Internal
0 commit comments