@@ -204,6 +204,18 @@ std::enable_if_t<std::is_arithmetic_v<T>, bool> AtomicCompareExchangeAcquire(T *
204204#endif
205205}
206206
207+ template <typename T>
208+ std::enable_if_t <std::is_arithmetic_v<T>, bool > AtomicCompareExchangeRelease (T *ptr, T *expected, T *desired)
209+ {
210+ #ifndef _MSC_VER
211+ return __atomic_compare_exchange (ptr, expected, desired, /* weak=*/ false , __ATOMIC_RELEASE, __ATOMIC_RELAXED);
212+ #else
213+ // Cannot specify the memory order directly, use an unconditional fence to avoid branching code.
214+ std::atomic_thread_fence (std::memory_order_release);
215+ return MSVC ::AtomicOps<sizeof (T)>::CompareExchange (ptr, expected, desired);
216+ #endif
217+ }
218+
207219template <typename T>
208220std::enable_if_t <std::is_arithmetic_v<T>> AtomicAddCompareExchangeLoop (T *ptr, T val)
209221{
@@ -216,6 +228,18 @@ std::enable_if_t<std::is_arithmetic_v<T>> AtomicAddCompareExchangeLoop(T *ptr, T
216228 }
217229}
218230
231+ template <typename T>
232+ std::enable_if_t <std::is_arithmetic_v<T>> AtomicAddCompareExchangeReleaseLoop (T *ptr, T val)
233+ {
234+ T expected;
235+ AtomicLoad (ptr, &expected);
236+ T desired = expected + val;
237+ while (!AtomicCompareExchangeRelease (ptr, &expected, &desired)) {
238+ // expected holds the new value; try again.
239+ desired = expected + val;
240+ }
241+ }
242+
219243#ifdef _MSC_VER
220244namespace MSVC {
221245inline void AtomicOps<8 >::Add(void *ptr, const void *val)
@@ -245,17 +269,35 @@ std::enable_if_t<std::is_floating_point_v<T>> AtomicAdd(T *ptr, T val)
245269 AtomicAddCompareExchangeLoop (ptr, val);
246270}
247271
272+ template <typename T>
273+ std::enable_if_t <std::is_integral_v<T>> AtomicAddRelease (T *ptr, T val)
274+ {
275+ #ifndef _MSC_VER
276+ __atomic_fetch_add (ptr, val, __ATOMIC_RELEASE);
277+ #else
278+ // Cannot specify the memory order directly, use a fence.
279+ std::atomic_thread_fence (std::memory_order_release);
280+ MSVC ::AtomicOps<sizeof (T)>::Add (ptr, &val);
281+ #endif
282+ }
283+
284+ template <typename T>
285+ std::enable_if_t <std::is_floating_point_v<T>> AtomicAddRelease (T *ptr, T val)
286+ {
287+ AtomicAddCompareExchangeReleaseLoop (ptr, val);
288+ }
289+
248290// For adding a double-precision weight to a single-precision bin content type, cast the argument once before the
249291// compare-exchange loop.
250- static inline void AtomicAdd (float *ptr, double val)
292+ static inline void AtomicAddRelease (float *ptr, double val)
251293{
252- AtomicAdd (ptr, static_cast <float >(val));
294+ AtomicAddRelease (ptr, static_cast <float >(val));
253295}
254296
255297template <typename T>
256- std::enable_if_t <std::is_arithmetic_v<T>> AtomicInc (T *ptr)
298+ std::enable_if_t <std::is_arithmetic_v<T>> AtomicIncRelease (T *ptr)
257299{
258- AtomicAdd (ptr, static_cast <T>(1 ));
300+ AtomicAddRelease (ptr, static_cast <T>(1 ));
259301}
260302
261303template <typename T, typename U>
@@ -264,10 +306,16 @@ auto AtomicAdd(T *ptr, const U &add) -> decltype(ptr->AtomicAdd(add))
264306 return ptr->AtomicAdd (add);
265307}
266308
309+ template <typename T, typename U>
310+ auto AtomicAddRelease (T *ptr, const U &add) -> decltype(ptr->AtomicAddRelease (add))
311+ {
312+ return ptr->AtomicAddRelease (add);
313+ }
314+
267315template <typename T>
268- auto AtomicInc (T *ptr) -> decltype(ptr->AtomicInc ())
316+ auto AtomicIncRelease (T *ptr) -> decltype(ptr->AtomicIncRelease ())
269317{
270- return ptr->AtomicInc ();
318+ return ptr->AtomicIncRelease ();
271319}
272320
273321} // namespace Internal
0 commit comments