libqi-api  2.4.3.28
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
atomic.hpp
Go to the documentation of this file.
1 #pragma once
2 /*
3  * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the COPYING file.
6  */
7 
8 #ifndef QI_ATOMIC_HPP_
9 #define QI_ATOMIC_HPP_
10 
11 #ifdef _MSC_VER
12 
13 #include <windows.h>
14 #include <intrin.h>
15 
16 extern "C" long __cdecl _InterlockedIncrement(long volatile *);
17 extern "C" long __cdecl _InterlockedDecrement(long volatile *);
18 
19 #pragma intrinsic(_InterlockedIncrement)
20 #pragma intrinsic(_InterlockedDecrement)
21 
22 #endif
23 
24 #include <boost/atomic.hpp>
25 #include <qi/config.hpp>
26 #include <qi/macro.hpp>
27 
28 namespace qi
29 {
30 
35 inline long testAndSet(long* cond)
36 {
37 #if defined __GNUC__
38  return __sync_bool_compare_and_swap(cond, 0, 1);
39 #elif defined _MSC_VER
40  return 1 - InterlockedCompareExchange(cond, 1, 0);
41 #else
42  #error "Unknown platform, testAndSet not implemented"
43 #endif
44 }
45 
46 namespace detail
47 {
48 /* /!\ WARNING
49  * The 'volatile' is needed even though we use atomic compiler builtins.
50  * Without the volatile, a thread doing
51  * while (!setIfEquals(1,1))
52  * Is never unstuck by a thread doing
53  * setIfEquals(0,1)
54  *
55  * StaticAtomicInt has public member so that it can be initialized at
56  * static-initialization time (to make thread-safe static initialization
57  * inside functions)
58  */
60 {
61 public:
62  /* prefix operators */
63  inline int operator++();
64  inline int operator--();
65  inline StaticAtomicInt& operator=(int value);
66  inline bool setIfEquals(int testValue, int setValue);
67 
68  inline int swap(int value);
69 
70  inline int operator*() const
71  {
72  return _value;
73  }
74 
75 public:
76  volatile
77 #ifdef _MSC_VER
78  long
79 #else
80  int
81 #endif
83 };
84 
85 #ifdef __GNUC__
86 inline int StaticAtomicInt::operator++()
87 {
88  return __sync_add_and_fetch(&_value, 1);
89 }
90 inline int StaticAtomicInt::operator--()
91 {
92  return __sync_sub_and_fetch(&_value, 1);
93 }
94 inline StaticAtomicInt& StaticAtomicInt::operator=(int value)
95 {
96  __sync_lock_test_and_set(&_value, value);
97  return *this;
98 }
99 inline int StaticAtomicInt::swap(int value)
100 {
101  return __sync_lock_test_and_set(&_value, value);
102 }
103 inline bool StaticAtomicInt::setIfEquals(int testValue, int setValue)
104 {
105  return __sync_bool_compare_and_swap(&_value, testValue, setValue);
106 }
107 #elif defined(_MSC_VER)
108 inline int StaticAtomicInt::operator++()
109 {
110  return _InterlockedIncrement(&_value);
111 }
112 inline int StaticAtomicInt::operator--()
113 {
114  return _InterlockedDecrement(&_value);
115 }
116 inline StaticAtomicInt& StaticAtomicInt::operator=(int value)
117 {
118  InterlockedExchange(&_value, value);
119  return *this;
120 }
121 inline int StaticAtomicInt::swap(int value)
122 {
123  return InterlockedExchange(&_value, value);
124 }
125 inline bool StaticAtomicInt::setIfEquals(int testValue, int setValue)
126 {
127  return _InterlockedCompareExchange(&_value, setValue, testValue) == testValue;
128 }
129 #endif
130 }
131 
139 template <typename T>
140 struct Atomic
141 {
142 public:
143  boost::atomic<T> _value;
144 
145  /* Default atomic constructor, setting value to 0.
146  */
148  : _value(0)
149  {}
153  Atomic(T value)
154  : _value(value)
155  {}
156  // This is needed in c++03 for lines like:
157  // Atomic<int> i = 0;
158  // There is no copy there, but the constructor *must* exist
159  Atomic(const Atomic& other)
160  : _value(*other)
161  {}
162 
165  { return ++_value; }
168  { return --_value; }
169 
171  { _value = value; return *this; }
173  { _value = *value; return *this; }
174 
178  bool setIfEquals(T testValue, T setValue)
179  { return _value.compare_exchange_strong(testValue, setValue); }
180 
184  T swap(T value)
185  { return _value.exchange(value); }
186 
189  T operator*() const
190  { return _value.load(); }
191 };
192 
193 namespace detail
194 {
195 template<typename T> void newAndAssign(T** ptr)
196 {
197  *ptr = new T();
198 }
199 }
200 
201 }
202 
203 #define _QI_INSTANCIATE(_, a, elem) ::qi::detail::newAndAssign(&elem);
204 
205 /* The code below relies on the fact that initialisation of the qi::Atomic
206  * can happen at static initialization time, and that proper memory barriers
207  * are setup by its ++, swap and get operations.
208  */
209 
252 #define QI_THREADSAFE_NEW(...) \
253  QI_ONCE(QI_VAARGS_APPLY(_QI_INSTANCIATE, _, __VA_ARGS__);)
254 
298 #define QI_ONCE(code) \
299  static qi::detail::StaticAtomicInt QI_UNIQ_DEF(atomic_guard_a) = {0}; \
300  static qi::detail::StaticAtomicInt QI_UNIQ_DEF(atomic_guard_b) = {0}; \
301  while (!QI_UNIQ_DEF(atomic_guard_a).setIfEquals(1, 1)) \
302  { \
303  bool tok = QI_UNIQ_DEF(atomic_guard_b).setIfEquals(0, 1); \
304  if (tok) \
305  { \
306  code; \
307  ++QI_UNIQ_DEF(atomic_guard_a); \
308  } \
309  }
310 
311 #endif // QI_ATOMIC_HPP_
Atomic(T value)
Definition: atomic.hpp:153
T swap(T value)
Definition: atomic.hpp:184
T operator--()
Atomic decement of the value.
Definition: atomic.hpp:167
bool setIfEquals(T testValue, T setValue)
Definition: atomic.hpp:178
bool setIfEquals(int testValue, int setValue)
int operator*() const
Definition: atomic.hpp:70
Atomic< T > & operator=(T value)
Definition: atomic.hpp:170
StaticAtomicInt & operator=(int value)
long testAndSet(long *cond)
Definition: atomic.hpp:35
boost::atomic< T > _value
Definition: atomic.hpp:143
Atomic(const Atomic &other)
Definition: atomic.hpp:159
void newAndAssign(T **ptr)
Definition: atomic.hpp:195
T operator++()
Atomic increment of the value.
Definition: atomic.hpp:164
Atomic< T > & operator=(const Atomic< T > &value)
Definition: atomic.hpp:172
Various macros for qi. (deprecated, export API, disallow copy, ..) <includename>qi/macro.hpp</includename> .
T operator*() const
Definition: atomic.hpp:189