Lunchbox  1.15.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 <math.h> // include math.h early to avoid warning later
26 # include <intrin.h>
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 {
36 
38 inline void memoryBarrier()
39 {
40 #ifdef __GNUC__
41  __sync_synchronize();
42 #elif defined(_MSC_VER)
43  _ReadWriteBarrier();
44 #elif defined(__xlC__)
45  __fence();
46  __eieio();
47  __fence();
48 #else
49 # error "no memory barrier implemented for this platform"
50 #endif
51 }
52 
54 inline void memoryBarrierAcquire()
55 {
56 #ifdef __xlC__
57  __fence();
58  __eieio();
59 #else
60  memoryBarrier();
61 #endif
62 }
63 
65 inline void memoryBarrierRelease()
66 {
67 #ifdef __xlC__
68  __isync();
69  __fence();
70 #else
71  memoryBarrier();
72 #endif
73 }
74 
87 template< class T > 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 > T Atomic< T >::getAndAdd( T& value, const T increment )
173 {
174  return __sync_fetch_and_add( &value, increment );
175 }
176 
177 template< class T > T Atomic< T >::getAndSub( T& value, const T increment )
178 {
179  return __sync_fetch_and_sub( &value, increment );
180 }
181 
182 template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
183 {
184  return __sync_add_and_fetch( &value, increment );
185 }
186 
187 template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
188 {
189  return __sync_sub_and_fetch( &value, increment );
190 }
191 
192 template< class T > T Atomic< T >::incAndGet( T& value )
193 {
194  return addAndGet( value, 1 );
195 }
196 
197 template< class T > T Atomic< T >::decAndGet( T& value )
198 {
199  return subAndGet( value, 1 );
200 }
201 
202 template< class T >
203 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue )
204 {
205  return __sync_bool_compare_and_swap( value, expected, newValue );
206 }
207 
208 #elif defined (_MSC_VER)
209 
210 // see also atomic.cpp
211 template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
212 {
213  return getAndAdd( value, increment ) + increment;
214 }
215 
216 template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
217 {
218  return getAndSub( value, increment ) - increment;
219 }
220 
221 #else
222 # ifdef __xlC__
223 template< class T >
224 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue )
225 {
226  return __compare_and_swap( value, const_cast< T* >( &expected ), newValue );
227 }
228 # ifdef __64BIT__
229 template<> inline
230 bool Atomic< int64_t >::compareAndSwap( int64_t* value, const int64_t expected,
231  const int64_t newValue )
232 {
233  return __compare_and_swaplp( value, const_cast< int64_t* >( &expected ),
234  newValue );
235 }
236 # endif
237 # else
238 # error No compare-and-swap implementated for this platform
239 # endif
240 
241 template< class T > T Atomic< T >::getAndAdd( T& value, const T increment )
242 {
243  for(;;)
244  {
246  const T oldv = value;
247  const T newv = oldv + increment;
248  if( !compareAndSwap( &value, oldv, newv ))
249  continue;
250 
252  return oldv;
253  }
254 }
255 
256 template< class T > T Atomic< T >::getAndSub( T& value, const T increment )
257 {
258  for(;;)
259  {
261  const T oldv = value;
262  const T newv = oldv - increment;
263  if( !compareAndSwap( &value, oldv, newv ))
264  continue;
265 
267  return oldv;
268  }
269 }
270 
271 template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
272 {
273  for(;;)
274  {
276  const T oldv = value;
277  const T newv = oldv + increment;
278  if( !Atomic< T >::compareAndSwap( &value, oldv, newv ))
279  continue;
280 
282  return newv;
283  }
284 }
285 
286 template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
287 {
288  for(;;)
289  {
291  const T oldv = value;
292  const T newv = oldv - increment;
293  if( !Atomic< T >::compareAndSwap( &value, oldv, newv ))
294  continue;
295 
297  return newv;
298  }
299 }
300 
301 template< class T > T Atomic< T >::incAndGet( T& value )
302 {
303  return addAndGet( value, 1 );
304 }
305 
306 template< class T > T Atomic< T >::decAndGet( T& value )
307 {
308  return subAndGet( value, 1 );
309 }
310 #endif
311 
312 template< class T > Atomic< T >::Atomic ( const T v ) : _value(v) {}
313 
314 template <class T>
315 Atomic< T >::Atomic( const Atomic< T >& v ) : _value( v._value ) {}
316 
317 template <class T>
319 {
321  return _value;
322 }
323 
324 template< class T > void Atomic< T >::operator = ( const T v )
325 {
326  _value = v;
327  memoryBarrier();
328 }
329 
330 template< class T > void Atomic< T >::operator = ( const Atomic< T >& v)
331 {
332  _value = v._value;
333  memoryBarrier();
334 }
335 
336 template< class T > T Atomic< T >::operator += (T v)
337 {
338  return addAndGet( _value, v );
339 }
340 
341 template< class T > T Atomic< T >::operator -=(T v)
342 {
343  return subAndGet( _value, v );
344 }
345 
346 template< class T > T Atomic< T >::operator ++(void)
347 {
348  return incAndGet( _value );
349 }
350 
351 template< class T > T Atomic< T >::operator --(void)
352 {
353  return decAndGet( _value );
354 }
355 
356 template< class T > T Atomic< T >::operator ++(int)
357 {
358  return getAndAdd( _value, 1 );
359 }
360 
361 template< class T > T Atomic< T >::operator --(int)
362 {
363  return getAndSub( _value, 1 );
364 }
365 
366 template< class T > bool Atomic< T >::operator == ( const Atomic<T>& rhs ) const
367 {
368  memoryBarrier();
369  return _value == rhs._value;
370 }
371 
372 template< class T > bool Atomic< T >::operator != ( const Atomic<T>& rhs ) const
373 {
374  memoryBarrier();
375  return _value != rhs._value;
376 }
377 
378 template< class T >
379 bool Atomic< T >::compareAndSwap( const T expected, const T newValue )
380 {
381  return compareAndSwap( &_value, expected, newValue );
382 }
383 
384 }
385 #endif // LUNCHBOX_ATOMIC_H
static T decAndGet(T &value)
Definition: atomic.h:306
static T getAndSub(T &value, const T increment)
Definition: atomic.h:256
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:65
static T getAndAdd(T &value, const T increment)
Definition: atomic.h:241
static T addAndGet(T &value, const T increment)
Definition: atomic.h:271
static T incAndGet(T &value)
Definition: atomic.h:301
bool operator!=(const Atomic< T > &rhs) const
Definition: atomic.h:372
T operator--(void)
Atomically decrement by one and return the new value.
Definition: atomic.h:351
static T subAndGet(T &value, const T increment)
Definition: atomic.h:286
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:38
bool operator==(const Atomic< T > &rhs) const
Definition: atomic.h:366
void operator=(const T v)
Assign a new value.
Definition: atomic.h:324
T operator+=(T v)
Atomically add a value and return the new value.
Definition: atomic.h:336
Atomic(const T v=0)
Construct a new atomic variable with an initial value.
Definition: atomic.h:312
void memoryBarrierAcquire()
Perform a load-with-acquire memory barrier.
Definition: atomic.h:54
Abstraction layer and common utilities for multi-threaded programming.
Definition: algorithm.h:32
T operator-=(T v)
Atomically substract a value and return the new value.
Definition: atomic.h:341
T operator++(void)
Atomically increment by one and return the new value.
Definition: atomic.h:346