alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
atomic.hpp
Go to the documentation of this file.
1/* Copyright 2022 Felice Pantaleo, Andrea Bocci, Jan Stephan
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
11#include "alpaka/operation.hpp"
12
13#include <array>
14#include <atomic>
15#include <type_traits>
16
17
18#ifdef ALPAKA_DISABLE_STD_ATOMIC_REF
19# include <boost/atomic.hpp>
20#endif
21
22namespace alpaka::onAcc
23{
24 namespace detail
25 {
26#if defined(ALPAKA_DISABLE_STD_ATOMIC_REF)
27 template<typename T>
28 using atomic_ref = boost::atomic_ref<T>;
29 constexpr auto memory_order_relaxed = boost::memory_order_relaxed;
30#else
31 template<typename T>
32 using atomic_ref = std::atomic_ref<T>;
33 constexpr auto memory_order_relaxed = std::memory_order_relaxed;
34#endif
35 } // namespace detail
36
37 //! The atomic ops based on atomic_ref for CPU accelerators.
38 //
39 // Atomics can be used in the grids, blocks and threads hierarchy levels.
40 //
41
43 {
44 };
45
46 template<typename T>
48 {
49 static_assert(
50 std::is_trivially_copyable_v<T> && detail::atomic_ref<T>::required_alignment <= alignof(T),
51 "Type not supported by AtomicAtomicRef, please recompile defining "
52 "ALPAKA_DISABLE_ATOMIC_ATOMICREF.");
53 }
54
55 namespace internalCompute
56 {
57 //! The CPU accelerators operation::Add.
58 template<typename T, typename T_Scope>
59 struct Atomic::Op<operation::Add, internal::StlAtomic, T, T_Scope>
60 {
61 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
62 {
64 detail::atomic_ref<T> ref(*addr);
65 return ref.fetch_add(value, detail::memory_order_relaxed);
66 }
67 };
68
69 //! The CPU accelerators operation::Sub.
70 template<typename T, typename T_Scope>
71 struct Atomic::Op<alpaka::operation::Sub, internal::StlAtomic, T, T_Scope>
72 {
73 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
74 {
76 detail::atomic_ref<T> ref(*addr);
77 return ref.fetch_sub(value, detail::memory_order_relaxed);
78 }
79 };
80
81 //! The CPU accelerators operation::Min.
82 template<typename T, typename T_Scope>
83 struct Atomic::Op<alpaka::operation::Min, internal::StlAtomic, T, T_Scope>
84 {
85 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
86 {
88 detail::atomic_ref<T> ref(*addr);
89 T old = ref;
90 T result = old;
91 result = std::min(result, value);
92 while(!ref.compare_exchange_weak(old, result, detail::memory_order_relaxed))
93 {
94 result = old;
95 result = std::min(result, value);
96 }
97 return old;
98 }
99 };
100
101 //! The CPU accelerators operation::Max.
102 template<typename T, typename T_Scope>
103 struct Atomic::Op<alpaka::operation::Max, internal::StlAtomic, T, T_Scope>
104 {
105 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
106 {
108 detail::atomic_ref<T> ref(*addr);
109 T old = ref;
110 T result = old;
111 result = std::max(result, value);
112 while(!ref.compare_exchange_weak(old, result, detail::memory_order_relaxed))
113 {
114 result = old;
115 result = std::max(result, value);
116 }
117 return old;
118 }
119 };
120
121 //! The CPU accelerators operation::Exch.
122 template<typename T, typename T_Scope>
123 struct Atomic::Op<alpaka::operation::Exch, internal::StlAtomic, T, T_Scope>
124 {
125 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
126 {
128 detail::atomic_ref<T> ref(*addr);
129 T old = ref;
130 T result = value;
131 while(!ref.compare_exchange_weak(old, result, detail::memory_order_relaxed))
132 {
133 result = value;
134 }
135 return old;
136 }
137 };
138
139 //! The CPU accelerators operation::Inc.
140 template<typename T, typename T_Scope>
141 struct Atomic::Op<alpaka::operation::Inc, internal::StlAtomic, T, T_Scope>
142 {
143 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
144 {
146 detail::atomic_ref<T> ref(*addr);
147 T old = ref;
148 T result;
149 do
150 {
151 result = ((old >= value) ? T{0} : old + T{1});
152 } while(!ref.compare_exchange_weak(old, result, detail::memory_order_relaxed));
153 return old;
154 }
155 };
156
157 //! The CPU accelerators operation::Dec.
158 template<typename T, typename T_Scope>
159 struct Atomic::Op<alpaka::operation::Dec, internal::StlAtomic, T, T_Scope>
160 {
161 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
162 {
164 detail::atomic_ref<T> ref(*addr);
165 T old = ref;
166 T result;
167 do
168 {
169 result = (old == T{0} || old > value) ? value : (old - T{1});
170 } while(!ref.compare_exchange_weak(old, result, detail::memory_order_relaxed));
171 return old;
172 }
173 };
174
175 //! The CPU accelerators operation::And.
176 template<typename T, typename T_Scope>
177 struct Atomic::Op<alpaka::operation::And, internal::StlAtomic, T, T_Scope>
178 {
179 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
180 {
182 detail::atomic_ref<T> ref(*addr);
183 return ref.fetch_and(value, detail::memory_order_relaxed);
184 }
185 };
186
187 //! The CPU accelerators operation::Or.
188 template<typename T, typename T_Scope>
189 struct Atomic::Op<alpaka::operation::Or, internal::StlAtomic, T, T_Scope>
190 {
191 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
192 {
194 detail::atomic_ref<T> ref(*addr);
195 return ref.fetch_or(value, detail::memory_order_relaxed);
196 }
197 };
198
199 //! The CPU accelerators operation::Xor.
200 template<typename T, typename T_Scope>
201 struct Atomic::Op<alpaka::operation::Xor, internal::StlAtomic, T, T_Scope>
202 {
203 ALPAKA_FN_HOST static auto atomicOp(internal::StlAtomic const&, T* const addr, T const& value) -> T
204 {
206 detail::atomic_ref<T> ref(*addr);
207 return ref.fetch_xor(value, detail::memory_order_relaxed);
208 }
209 };
210
211 //! The CPU accelerators operation::Cas.
212 template<typename T, typename T_Scope>
213 struct Atomic::Op<alpaka::operation::Cas, internal::StlAtomic, T, T_Scope>
214 {
215 ALPAKA_FN_HOST static auto atomicOp(
216 internal::StlAtomic const&,
217 T* const addr,
218 T const& compare,
219 T const& value) -> T
220 {
222 detail::atomic_ref<T> ref(*addr);
223 T old = ref;
224 T result;
225 do
226 {
227#if ALPAKA_COMP_GNUC || ALPAKA_COMP_CLANG
228# pragma GCC diagnostic push
229# pragma GCC diagnostic ignored "-Wfloat-equal"
230#endif
231 result = ((old == compare) ? value : old);
232#if ALPAKA_COMP_GNUC || ALPAKA_COMP_CLANG
233# pragma GCC diagnostic pop
234#endif
235 } while(!ref.compare_exchange_weak(old, result, detail::memory_order_relaxed));
236 return old;
237 }
238 };
239 } // namespace internalCompute
240} // namespace alpaka::onAcc
The atomic ops based on atomic_ref for CPU accelerators.
Definition atomic.hpp:43
#define ALPAKA_FN_HOST
All functions that can be used on an accelerator have to be attributed with ALPAKA_FN_ACC or ALPAKA_F...
Definition common.hpp:33
constexpr auto alpaka
Definition fn.hpp:66
functionality which is usable on the accelerator compute device from within a kernel.
Definition executor.hpp:38
constexpr auto atomicOp(auto const &acc, T *const addr, T const &value, T_Scope const scope=T_Scope()) -> T
Executes the given operation atomically.
Definition atomic.hpp:26
void isSupportedByAtomicAtomicRef()
Definition atomic.hpp:47
Contains functors with operation following the atomic operation semantics.
Definition operation.hpp:20