Lunchbox  1.16.0
Multi-threaded C++ toolbox library for all application developers creating high-performance multi-threaded programs.
atomic.h
1 
2 // Copyright (C) 2007, 2008 Tim Blechmann & Thomas Grill
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
8 // Disclaimer: Not a Boost library.
9 
10 /* Copyright (c) 2008-2012, Stefan Eilemann <eile@equalizergraphics.com>
11  Modifications to use within lunchbox namespace and naming conventions.
12  Original at http://tim.klingt.org/git?p=boost_lockfree.git;a=tree
13 */
14 
15 #ifndef LUNCHBOX_ATOMIC_H
16 #define LUNCHBOX_ATOMIC_H
17 
18 #include <lunchbox/api.h>
19 #include <lunchbox/compiler.h> // GCC version
20 #include <lunchbox/types.h>
21 
22 #ifdef _MSC_VER
23 #pragma warning(push)
24 #pragma warning(disable : 4985) // inconsistent decl of ceil
25 #include <intrin.h>
26 #include <math.h> // include math.h early to avoid warning later
27 #pragma warning(pop)
28 #pragma intrinsic(_ReadWriteBarrier)
29 #elif defined(__xlC__)
30 #include <builtins.h>
31 #include <iostream>
32 #endif
33 
34 namespace lunchbox
35 {
37 inline void memoryBarrier()
38 {
39 #ifdef __GNUC__
40  __sync_synchronize();
41 #elif defined(_MSC_VER)
42  _ReadWriteBarrier();
43 #elif defined(__xlC__)
44  __fence();
45  __eieio();
46  __fence();
47 #else
48 #error "no memory barrier implemented for this platform"
49 #endif
50 }
51 
53 inline void memoryBarrierAcquire()
54 {
55 #ifdef __xlC__
56  __fence();
57  __eieio();
58 #else
59  memoryBarrier();
60 #endif
61 }
62 
64 inline void memoryBarrierRelease()
65 {
66 #ifdef __xlC__
67  __isync();
68  __fence();
69 #else
70  memoryBarrier();
71 #endif
72 }
73 
86 template <class T>
87 class Atomic
88 {
89 public:
91  LUNCHBOX_API static T getAndAdd(T& value, const T increment);
92 
94  LUNCHBOX_API static T getAndSub(T& value, const T increment);
95 
97  static T addAndGet(T& value, const T increment);
98 
100  static T subAndGet(T& value, const T increment);
101 
103  LUNCHBOX_API static T incAndGet(T& value);
104 
106  LUNCHBOX_API static T decAndGet(T& value);
107 
109  LUNCHBOX_API static bool compareAndSwap(T* value, const T expected,
110  const T newValue);
111 
113  explicit Atomic(const T v = 0);
114 
116  Atomic(const Atomic<T>& v);
117 
119  operator T(void) const;
120 
122  void operator=(const T v);
123 
125  void operator=(const Atomic<T>& v);
126 
128  T operator+=(T v);
129 
131  T operator-=(T v);
132 
134  T operator++(void);
135 
137  T operator--(void);
138 
140  T operator++(int);
141 
143  T operator--(int);
144 
146  bool operator==(const Atomic<T>& rhs) const;
147 
149  bool operator!=(const Atomic<T>& rhs) const;
150 
159  bool compareAndSwap(const T expected, const T newValue);
160 
161 private:
162 // https://github.com/Eyescale/Lunchbox/issues/8
163 #if _MSC_VER < 1700
164  mutable T _value;
165 #else
166  LB_ALIGN8(mutable T _value);
167 #endif
168 };
169 
170 // Implementation
171 #ifdef __GNUC__
172 template <class T>
173 T Atomic<T>::getAndAdd(T& value, const T increment)
174 {
175  return __sync_fetch_and_add(&value, increment);
176 }
177 
178 template <class T>
179 T Atomic<T>::getAndSub(T& value, const T increment)
180 {
181  return __sync_fetch_and_sub(&value, increment);
182 }
183 
184 template <class T>
185 T Atomic<T>::addAndGet(T& value, const T increment)
186 {
187  return __sync_add_and_fetch(&value, increment);
188 }
189 
190 template <class T>
191 T Atomic<T>::subAndGet(T& value, const T increment)
192 {
193  return __sync_sub_and_fetch(&value, increment);
194 }
195 
196 template <class T>
197 T Atomic<T>::incAndGet(T& value)
198 {
199  return addAndGet(value, 1);
200 }
201 
202 template <class T>
203 T Atomic<T>::decAndGet(T& value)
204 {
205  return subAndGet(value, 1);
206 }
207 
208 template <class T>
209 bool Atomic<T>::compareAndSwap(T* value, const T expected, const T newValue)
210 {
211  return __sync_bool_compare_and_swap(value, expected, newValue);
212 }
213 
214 #elif defined(_MSC_VER)
215 
216 // see also atomic.cpp
217 template <class T>
218 T Atomic<T>::addAndGet(T& value, const T increment)
219 {
220  return getAndAdd(value, increment) + increment;
221 }
222 
223 template <class T>
224 T Atomic<T>::subAndGet(T& value, const T increment)
225 {
226  return getAndSub(value, increment) - increment;
227 }
228 
229 #else
230 #ifdef __xlC__
231 template <class T>
232 bool Atomic<T>::compareAndSwap(T* value, const T expected, const T newValue)
233 {
234  return __compare_and_swap(value, const_cast<T*>(&expected), newValue);
235 }
236 #ifdef __64BIT__
237 template <>
238 inline bool Atomic<int64_t>::compareAndSwap(int64_t* value,
239  const int64_t expected,
240  const int64_t newValue)
241 {
242  return __compare_and_swaplp(value, const_cast<int64_t*>(&expected),
243  newValue);
244 }
245 #endif
246 #else
247 #error No compare-and-swap implementated for this platform
248 #endif
249 
250 template <class T>
251 T Atomic<T>::getAndAdd(T& value, const T increment)
252 {
253  for (;;)
254  {
256  const T oldv = value;
257  const T newv = oldv + increment;
258  if (!compareAndSwap(&value, oldv, newv))
259  continue;
260 
262  return oldv;
263  }
264 }
265 
266 template <class T>
267 T Atomic<T>::getAndSub(T& value, const T increment)
268 {
269  for (;;)
270  {
272  const T oldv = value;
273  const T newv = oldv - increment;
274  if (!compareAndSwap(&value, oldv, newv))
275  continue;
276 
278  return oldv;
279  }
280 }
281 
282 template <class T>
283 T Atomic<T>::addAndGet(T& value, const T increment)
284 {
285  for (;;)
286  {
288  const T oldv = value;
289  const T newv = oldv + increment;
290  if (!Atomic<T>::compareAndSwap(&value, oldv, newv))
291  continue;
292 
294  return newv;
295  }
296 }
297 
298 template <class T>
299 T Atomic<T>::subAndGet(T& value, const T increment)
300 {
301  for (;;)
302  {
304  const T oldv = value;
305  const T newv = oldv - increment;
306  if (!Atomic<T>::compareAndSwap(&value, oldv, newv))
307  continue;
308 
310  return newv;
311  }
312 }
313 
314 template <class T>
316 {
317  return addAndGet(value, 1);
318 }
319 
320 template <class T>
322 {
323  return subAndGet(value, 1);
324 }
325 #endif
326 
327 template <class T>
329  : _value(v)
330 {
331 }
332 
333 template <class T>
335  : _value(v._value)
336 {
337 }
338 
339 template <class T>
340 Atomic<T>::operator T(void) const
341 {
343  return _value;
344 }
345 
346 template <class T>
347 void Atomic<T>::operator=(const T v)
348 {
349  _value = v;
350  memoryBarrier();
351 }
352 
353 template <class T>
355 {
356  _value = v._value;
357  memoryBarrier();
358 }
359 
360 template <class T>
362 {
363  return addAndGet(_value, v);
364 }
365 
366 template <class T>
368 {
369  return subAndGet(_value, v);
370 }
371 
372 template <class T>
374 {
375  return incAndGet(_value);
376 }
377 
378 template <class T>
380 {
381  return decAndGet(_value);
382 }
383 
384 template <class T>
386 {
387  return getAndAdd(_value, 1);
388 }
389 
390 template <class T>
392 {
393  return getAndSub(_value, 1);
394 }
395 
396 template <class T>
397 bool Atomic<T>::operator==(const Atomic<T>& rhs) const
398 {
399  memoryBarrier();
400  return _value == rhs._value;
401 }
402 
403 template <class T>
404 bool Atomic<T>::operator!=(const Atomic<T>& rhs) const
405 {
406  memoryBarrier();
407  return _value != rhs._value;
408 }
409 
410 template <class T>
411 bool Atomic<T>::compareAndSwap(const T expected, const T newValue)
412 {
413  return compareAndSwap(&_value, expected, newValue);
414 }
415 }
416 #endif // LUNCHBOX_ATOMIC_H
static T decAndGet(T &value)
Definition: atomic.h:321
static T getAndSub(T &value, const T increment)
Definition: atomic.h:267
A variable with atomic semantics and standalone atomic operations.
Definition: atomic.h:87
Defines export visibility macros for library Lunchbox.
Basic type definitions not provided by the operating system.
void memoryBarrierRelease()
Perform a store-with-release memory barrier.
Definition: atomic.h:64
static T getAndAdd(T &value, const T increment)
Definition: atomic.h:251
static T addAndGet(T &value, const T increment)
Definition: atomic.h:283
static T incAndGet(T &value)
Definition: atomic.h:315
bool operator!=(const Atomic< T > &rhs) const
Definition: atomic.h:404
T operator--(void)
Atomically decrement by one and return the new value.
Definition: atomic.h:379
static T subAndGet(T &value, const T increment)
Definition: atomic.h:299
static bool compareAndSwap(T *value, const T expected, const T newValue)
Perform a compare-and-swap atomic operation.
void memoryBarrier()
Perform a full memory barrier.
Definition: atomic.h:37
bool operator==(const Atomic< T > &rhs) const
Definition: atomic.h:397
void operator=(const T v)
Assign a new value.
Definition: atomic.h:347
T operator+=(T v)
Atomically add a value and return the new value.
Definition: atomic.h:361
Atomic(const T v=0)
Construct a new atomic variable with an initial value.
Definition: atomic.h:328
void memoryBarrierAcquire()
Perform a load-with-acquire memory barrier.
Definition: atomic.h:53
Abstraction layer and common utilities for multi-threaded programming.
Definition: algorithm.h:29
T operator-=(T v)
Atomically substract a value and return the new value.
Definition: atomic.h:367
T operator++(void)
Atomically increment by one and return the new value.
Definition: atomic.h:373