libqi-api  release-2.5.3-2016-11-18
 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 <atomic>
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 
142 template <typename T>
143 struct Atomic
144 {
145  std::atomic<T> _value;
146 public:
147  /* Default atomic constructor, setting value to 0.
148  */
150  : _value{}
151  {}
155  Atomic(T value)
156  : _value(std::move(value))
157  {}
158  // This is needed in c++03 for lines like:
159  // Atomic<int> i = 0;
160  // There is no copy there, but the constructor *must* exist
161  Atomic(const Atomic& other)
162  : _value(other._value.load())
163  {}
164 
167  { return ++_value; }
170  { return --_value; }
171 
173  T operator++(int)
174  {
175  return _value++;
176  }
178  T operator--(int)
179  {
180  return _value--;
181  }
182 
184  { _value = std::move(value); return *this; }
186  { _value = value.load(); return *this; }
187 
191  bool setIfEquals(T testValue, T setValue)
192  { return _value.compare_exchange_strong(testValue, setValue); }
193 
197  T swap(T value)
198  { return _value.exchange(value); }
199 
204  QI_API_DEPRECATED_MSG(Use 'load' instead)
205  T operator*() const
206  { return _value.load(); }
207 
208  T load() const
209  { return _value.load(); }
210 };
211 
212 namespace detail
213 {
214 template<typename T> void newAndAssign(T** ptr)
215 {
216  *ptr = new T();
217 }
218 }
219 
220 }
221 
222 #define _QI_INSTANCIATE(_, a, elem) ::qi::detail::newAndAssign(&elem);
223 
224 /* The code below relies on the fact that initialisation of the qi::Atomic
225  * can happen at static initialization time, and that proper memory barriers
226  * are setup by its ++, swap and get operations.
227  */
228 
271 #define QI_THREADSAFE_NEW(...) \
272  QI_ONCE(QI_VAARGS_APPLY(_QI_INSTANCIATE, _, __VA_ARGS__);)
273 
317 #define QI_ONCE(code) \
318  static qi::detail::StaticAtomicInt QI_UNIQ_DEF(atomic_guard_a) = {0}; \
319  static qi::detail::StaticAtomicInt QI_UNIQ_DEF(atomic_guard_b) = {0}; \
320  while (!QI_UNIQ_DEF(atomic_guard_a).setIfEquals(1, 1)) \
321  { \
322  bool tok = QI_UNIQ_DEF(atomic_guard_b).setIfEquals(0, 1); \
323  if (tok) \
324  { \
325  try \
326  { \
327  code; \
328  } \
329  catch (...) \
330  { \
331  QI_UNIQ_DEF(atomic_guard_b) = 0; \
332  throw; \
333  } \
334  ++QI_UNIQ_DEF(atomic_guard_a); \
335  } \
336  }
337 
338 #endif // QI_ATOMIC_HPP_
void setValue(qi::Promise< R > &p, const boost::function< R()> &f)
Atomic(T value)
Definition: atomic.hpp:155
T swap(T value)
Definition: atomic.hpp:197
T operator--()
Atomic pre-decrement of the value.
Definition: atomic.hpp:169
bool setIfEquals(T testValue, T setValue)
Definition: atomic.hpp:191
bool setIfEquals(int testValue, int setValue)
int operator*() const
Definition: atomic.hpp:70
Atomic< T > & operator=(T value)
Definition: atomic.hpp:183
StaticAtomicInt & operator=(int value)
long testAndSet(long *cond)
Definition: atomic.hpp:35
Atomic(const Atomic &other)
Definition: atomic.hpp:161
void newAndAssign(T **ptr)
Definition: atomic.hpp:214
T operator++()
Atomic pre-increment of the value.
Definition: atomic.hpp:166
T operator++(int)
Atomic post-increment of the value.
Definition: atomic.hpp:173
#define QI_API_DEPRECATED_MSG(msg__)
Compiler flags to mark a function as deprecated. It will generate a compiler warning.
Definition: macro.hpp:53
std::atomic< T > _value
Definition: atomic.hpp:145
Atomic< T > & operator=(const Atomic< T > &value)
Definition: atomic.hpp:185
T operator--(int)
Atomic post-decrement of the value.
Definition: atomic.hpp:178
Various macros for qi. (deprecated, export API, disallow copy, ..) <includename>qi/macro.hpp</includename> .
T load() const
Definition: atomic.hpp:208