Loading...
Searching...
No Matches
G4atomic.hh
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26/// \file parallel/ThreadsafeScorers/include/G4atomic.hh
27/// \brief Definition of the G4atomic class
28//
29//
30//
31//
32/// This is an friendly implementation of the STL atomic class.
33/// This class has the same interface as the STL atomic but can be used
34/// in an extremely similar fashion to plain old data (POD) types.
35/// In other words, the copy constructor and assignment operators are
36/// defined, and a load() does not need to be called to get the POD
37/// value.
38///
39/// IMPORTANT: Care must be taken when using this class as a RHS term.
40/// The best use case scenario for this class is as a LHS term that is
41/// only used as a RHS term outside of the multithreaded operations on it.
42///
43/// FOR EXAMPLE:
44/// Proper use:
45/// Goal: sum energy deposited in run
46/// Impl: Is a member variable of derived
47/// G4VUserActionInitialization (of which there will
48/// always be just one instance). Accumulate
49/// thread-local energy deposit into EventAction,
50/// add to ActionInit at end of event, print sum
51/// on master EndOfRunAction
52/// Why: the sum is only a LHS term
53/// Improper use:
54/// Goal: compute error during event processing
55/// Impl: sum += x; sum_sq += x*x; counts++;
56/// error = sqrt(sum_sq/(sum*sum) - 1/counts;
57/// (where sum, sum_sq, counts are G4atomics)
58/// Why: This will work but error can/will be wrong when
59/// sum, sum_sq, and counts are updated by another thread
60/// while error is being calculated, i.e. they are used as
61/// RHS terms
62//
63//
64//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
65//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
66
67#ifndef G4atomic_hh_
68#define G4atomic_hh_
69
70//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
71
72#ifdef G4MULTITHREADED
73
74# include "G4atomic_defines.hh"
75
76//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
77
78template <typename _Tp>
79class G4atomic
80{
81 public:
82 typedef typename std::atomic<_Tp> base_type;
83 typedef _Tp value_type;
84
85 private:
86 using mem_ord = std::memory_order;
87
88 public:
89 // constructors
90 explicit G4atomic(mem_ord mo = std::memory_order_acq_rel)
91 : fMemOrder(mo)
92 {
93 atomics::set(&fvalue, value_type());
94 }
95
96 explicit G4atomic(const value_type& _init,
97 mem_ord mo = std::memory_order_acq_rel)
98 : fMemOrder(mo)
99 {
100 atomics::set(&fvalue, _init);
101 }
102
103 // copy-constructor from pure C++11 atomic
104 explicit G4atomic(const base_type& rhs,
105 mem_ord mo = std::memory_order_acq_rel)
106 : fMemOrder(mo)
107 {
108 atomics::set(&fvalue, rhs);
109 }
110
111 // copy-constructor
112 explicit G4atomic(const G4atomic& rhs)
113 : fMemOrder(rhs.fMemOrder)
114 {
115 atomics::set(&fvalue, rhs.base());
116 }
117
118 // assignment operators
119 G4atomic& operator=(const G4atomic& rhs)
120 {
121 if(this != &rhs)
122 atomics::set(&fvalue, rhs.fvalue);
123 return *this;
124 }
125
126 G4atomic& operator=(const value_type& rhs)
127 {
128 atomics::set(&fvalue, rhs);
129 return *this;
130 }
131
132 G4atomic& operator=(const base_type& rhs)
133 {
134 atomics::set(&fvalue, rhs);
135 return *this;
136 }
137
138 // destructor
139 ~G4atomic() { fvalue.~base_type(); }
140
141 // base version
142 base_type& base() { return fvalue; }
143 const base_type& base() const { return fvalue; }
144 base_type& base() volatile { return fvalue; }
145 const base_type& base() const volatile { return fvalue; }
146
147 // check if atomic is lock-free
148 bool is_lock_free() const { return fvalue.is_lock_free(); }
149 bool is_lock_free() const volatile { return fvalue.is_lock_free(); }
150
151 // store functions
152 void store(_Tp _desired, mem_ord mo = std::memory_order_seq_cst)
153 {
154 atomics::set(fvalue, _desired, mo);
155 }
156 void store(_Tp _desired, mem_ord mo = std::memory_order_seq_cst) volatile
157 {
158 atomics::set(fvalue, _desired, mo);
159 }
160
161 // load functions
162 _Tp load(mem_ord mo = std::memory_order_seq_cst) const
163 {
164 return atomics::get(fvalue, mo);
165 }
166 _Tp load(mem_ord mo = std::memory_order_seq_cst) const volatile
167 {
168 return atomics::get(fvalue, mo);
169 }
170
171 // implicit conversion functions
172 operator _Tp() const { return this->load(); }
173 operator _Tp() const volatile { return this->load(); }
174
175 operator base_type&() const { return fvalue; }
176
177 // compare-and-swap functions
178 bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _success,
179 mem_ord _failure)
180 {
181 return fvalue.compare_exchange_weak(_expected, _desired, _success,
182 _failure);
183 }
184 bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _success,
185 mem_ord _failure) volatile
186 {
187 return fvalue.compare_exchange_weak(_expected, _desired, _success,
188 _failure);
189 }
190
191 bool compare_exchange_weak(_Tp& _expected, _Tp _desired, mem_ord _order)
192 {
193 return fvalue.compare_exchange_weak(_expected, _desired, _order);
194 }
195 bool compare_exchange_weak(_Tp& _expected, _Tp _desired,
196 mem_ord _order) volatile
197 {
198 return fvalue.compare_exchange_weak(_expected, _desired, _order);
199 }
200
201 bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _success,
202 mem_ord _failure)
203 {
204 return fvalue.compare_exchange_weak(_expected, _desired, _success,
205 _failure);
206 }
207 bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _success,
208 mem_ord _failure) volatile
209 {
210 return fvalue.compare_exchange_weak(_expected, _desired, _success,
211 _failure);
212 }
213
214 bool compare_exchange_strong(_Tp& _expected, _Tp _desired, mem_ord _order)
215 {
216 return fvalue.compare_exchange_weak(_expected, _desired, _order);
217 }
218 bool compare_exchange_strong(_Tp& _expected, _Tp _desired,
219 mem_ord _order) volatile
220 {
221 return fvalue.compare_exchange_weak(_expected, _desired, _order);
222 }
223
224 // value_type operators
225 G4atomic& operator+=(const value_type& rhs)
226 {
227 atomics::increment(&fvalue, rhs, fMemOrder);
228 return *this;
229 }
230 G4atomic& operator-=(const value_type& rhs)
231 {
232 atomics::decrement(&fvalue, rhs, fMemOrder);
233 return *this;
234 }
235 G4atomic& operator*=(const value_type& rhs)
236 {
237 atomics::multiply(&fvalue, rhs, fMemOrder);
238 return *this;
239 }
240 G4atomic& operator/=(const value_type& rhs)
241 {
242 atomics::divide(&fvalue, rhs, fMemOrder);
243 return *this;
244 }
245
246 // atomic operators
247 G4atomic& operator+=(const G4atomic& rhs)
248 {
249 atomics::increment(&fvalue, rhs.fvalue);
250 return *this;
251 }
252 G4atomic& operator-=(const G4atomic& rhs)
253 {
254 atomics::decrement(&fvalue, rhs.fvalue);
255 return *this;
256 }
257 G4atomic& operator*=(const G4atomic& rhs)
258 {
259 atomics::multiply(&fvalue, rhs.fvalue);
260 return *this;
261 }
262 G4atomic& operator/=(const G4atomic& rhs)
263 {
264 atomics::divide(&fvalue, rhs.fvalue);
265 return *this;
266 }
267
268 G4atomic& operator+=(const G4atomic& rhs) volatile
269 {
270 atomics::increment(&fvalue, rhs.fvalue);
271 return *this;
272 }
273 G4atomic& operator-=(const G4atomic& rhs) volatile
274 {
275 atomics::decrement(&fvalue, rhs.fvalue);
276 return *this;
277 }
278 G4atomic& operator*=(const G4atomic& rhs) volatile
279 {
280 atomics::multiply(&fvalue, rhs.fvalue);
281 return *this;
282 }
283 G4atomic& operator/=(const G4atomic& rhs) volatile
284 {
285 atomics::divide(&fvalue, rhs.fvalue);
286 return *this;
287 }
288
289 // STL atomic operators
290 G4atomic& operator+=(const std::atomic<_Tp>& rhs)
291 {
292 atomics::increment(&fvalue, rhs, fMemOrder);
293 return *this;
294 }
295 G4atomic& operator-=(const std::atomic<_Tp>& rhs)
296 {
297 atomics::decrement(&fvalue, rhs, fMemOrder);
298 return *this;
299 }
300 G4atomic& operator*=(const std::atomic<_Tp>& rhs)
301 {
302 atomics::multiply(&fvalue, rhs, fMemOrder);
303 return *this;
304 }
305 G4atomic& operator/=(const std::atomic<_Tp>& rhs)
306 {
307 atomics::divide(&fvalue, rhs, fMemOrder);
308 return *this;
309 }
310
311 G4atomic& operator+=(const std::atomic<_Tp>& rhs) volatile
312 {
313 atomics::increment(&fvalue, rhs, fMemOrder);
314 return *this;
315 }
316 G4atomic& operator-=(const std::atomic<_Tp>& rhs) volatile
317 {
318 atomics::decrement(&fvalue, rhs, fMemOrder);
319 return *this;
320 }
321 G4atomic& operator*=(const std::atomic<_Tp>& rhs) volatile
322 {
323 atomics::multiply(&fvalue, rhs, fMemOrder);
324 return *this;
325 }
326 G4atomic& operator/=(const std::atomic<_Tp>& rhs) volatile
327 {
328 atomics::divide(&fvalue, rhs, fMemOrder);
329 return *this;
330 }
331
332 // increment operators
333 value_type operator++()
334 {
335 value_type _tmp = ++fvalue;
336 return _tmp;
337 }
338 value_type operator++(int)
339 {
340 value_type _tmp = fvalue++;
341 return _tmp;
342 }
343
344 value_type operator--()
345 {
346 value_type _tmp = --fvalue;
347 return _tmp;
348 }
349 value_type operator--(int)
350 {
351 value_type _tmp = fvalue--;
352 return _tmp;
353 }
354
355 protected:
356 base_type fvalue;
357 mem_ord fMemOrder;
358};
359
360//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
361
362#else // ! G4MULTITHREADED
363
364template <typename _Tp>
365using G4atomic = _Tp;
366
367#endif // G4MULTITHREADED
368
369//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
370
371#endif // G4atomic_hh_
Definition of the G4atomic_defines class.

Applications | User Support | Publications | Collaboration