- Aldebaran documentation |
- C++ Libraries |
- index

libqi-api 2.8.7.4

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Examples

- File List
- File Members

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 #include <boost/predef.h>
12
13
14 #if BOOST_OS_WINDOWS
15 // We need to "scope" our usage of windows.h to avoid
16 // clients to end up with issues at compile time.
17 // TODO: remove all this when we switch totally to std::atomic
18 # pragma push_macro("NOMINMAX")
19 # pragma push_macro("WIN32_LEAN_AND_MEAN")
20 #
21 # ifndef NOMINMAX
22 # define NOMINMAX // Deactivates min/max macros from windows.h
23 # endif
24 #
25 # ifndef WIN32_LEAN_AND_MEAN
26 # define WIN32_LEAN_AND_MEAN // Deactivates unnecessary parts of windows.h
27 # endif
28 #
29 # include <windows.h>
30 # include <intrin.h>
31 #
32 # pragma pop_macro("WIN32_LEAN_AND_MEAN")
33 # pragma pop_macro("NOMINMAX")
34 #endif
35
36
37 #include <atomic>
38 #include <qi/config.hpp>
39 #include <qi/macro.hpp>
40
41 namespace qi
42 {
43
48 inline long testAndSet(long* cond)
49 {
50 #if defined __GNUC__
51 return __sync_bool_compare_and_swap(cond, 0, 1);
52 #elif defined _MSC_VER
53 return 1 - InterlockedCompareExchange(cond, 1, 0);
54 #else
55 #error "Unknown platform, testAndSet not implemented"
56 #endif
57 }
58
59 namespace detail
60 {
61 /* /!\ WARNING
62 * The 'volatile' is needed even though we use atomic compiler builtins.
63 * Without the volatile, a thread doing
64 * while (!setIfEquals(1,1))
65 * Is never unstuck by a thread doing
66 * setIfEquals(0,1)
67 *
68 * StaticAtomicInt has public member so that it can be initialized at
69 * static-initialization time (to make thread-safe static initialization
70 * inside functions)
71 */
72 struct StaticAtomicInt
73 {
74 public:
75 /* prefix operators */
76 inline int operator++();
77 inline int operator--();
78 inline StaticAtomicInt& operator=(int value);
79 inline bool setIfEquals(int testValue, int setValue);
80
81 inline int swap(int value);
82
83 inline int operator*() const
84 {
85 return _value;
86 }
87
88 public:
89 volatile
90 #ifdef _MSC_VER
91 long
92 #else
93 int
94 #endif
95 _value;
96 };
97
98 #ifdef __GNUC__
99 inline int StaticAtomicInt::operator++()
100 {
101 return __sync_add_and_fetch(&_value, 1);
102 }
103 inline int StaticAtomicInt::operator--()
104 {
105 return __sync_sub_and_fetch(&_value, 1);
106 }
107 inline StaticAtomicInt& StaticAtomicInt::operator=(int value)
108 {
109 __sync_lock_test_and_set(&_value, value);
110 return *this;
111 }
112 inline int StaticAtomicInt::swap(int value)
113 {
114 return __sync_lock_test_and_set(&_value, value);
115 }
116 inline bool StaticAtomicInt::setIfEquals(int testValue, int setValue)
117 {
118 return __sync_bool_compare_and_swap(&_value, testValue, setValue);
119 }
120 #elif defined(_MSC_VER)
121 inline int StaticAtomicInt::operator++()
122 {
123 return _InterlockedIncrement(&_value);
124 }
125 inline int StaticAtomicInt::operator--()
126 {
127 return _InterlockedDecrement(&_value);
128 }
129 inline StaticAtomicInt& StaticAtomicInt::operator=(int value)
130 {
131 InterlockedExchange(&_value, value);
132 return *this;
133 }
134 inline int StaticAtomicInt::swap(int value)
135 {
136 return InterlockedExchange(&_value, value);
137 }
138 inline bool StaticAtomicInt::setIfEquals(int testValue, int setValue)
139 {
140 return _InterlockedCompareExchange(&_value, setValue, testValue) == testValue;
141 }
142 #endif
143 }
144
155 template <typename T>
156 struct Atomic
157 {
158 std::atomic<T> _value;
159 public:
160 /* Default atomic constructor, setting value to 0.
161 */
162 Atomic()
163 : _value{}
164 {}
168 Atomic(T value)
169 : _value(std::move(value))
170 {}
171 // This is needed in c++03 for lines like:
172 // Atomic<int> i = 0;
173 // There is no copy there, but the constructor *must* exist
174 Atomic(const Atomic& other)
175 : _value(other._value.load())
176 {}
177
179 T operator++()
180 { return ++_value; }
182 T operator--()
183 { return --_value; }
184
186 T operator++(int)
187 {
188 return _value++;
189 }
191 T operator--(int)
192 {
193 return _value--;
194 }
195
196 Atomic<T>& operator=(T value)
197 { _value = std::move(value); return *this; }
198 Atomic<T>& operator=(const Atomic<T>& value)
199 { _value = value.load(); return *this; }
200
204 bool setIfEquals(T testValue, T setValue)
205 { return _value.compare_exchange_strong(testValue, setValue); }
206
210 T swap(T value)
211 { return _value.exchange(value); }
212
217 QI_API_DEPRECATED_MSG(Use 'load' instead)
218 T operator*() const
219 { return _value.load(); }
220
221 T load() const
222 { return _value.load(); }
223 };
224
225 namespace detail
226 {
227 template<typename T> void newAndAssign(T** ptr)
228 {
229 *ptr = new T();
230 }
231 } // namespace detail
232
238 inline bool tryRaiseAtomicFlag(std::atomic<bool>& b)
239 {
240 bool expected = false;
241 const bool desired = true;
242 return b.compare_exchange_strong(expected, desired);
243 }
244
251 inline bool tryLowerAtomicFlag(std::atomic<bool>& b)
252 {
253 bool expected = true;
254 const bool desired = false;
255 return b.compare_exchange_strong(expected, desired);
256 }
257
258 class AtomicFlagLock
259 {
260 std::atomic_flag* _flag = nullptr;
261 bool _locked = false;
262
263 void cleanup() QI_NOEXCEPT(true)
264 {
265 if (_flag && _locked)
266 {
267 _flag->clear();
268 _locked = false;
269 }
270 }
271
272 public:
273 explicit AtomicFlagLock(std::atomic_flag& f)
274 : _flag{ &f }
275 , _locked{ !f.test_and_set() } // locked if the flag was not already set
276 {}
277
278 AtomicFlagLock(const AtomicFlagLock&) = delete;
279 AtomicFlagLock& operator=(const AtomicFlagLock&) = delete;
280
281 AtomicFlagLock(AtomicFlagLock&& o)
282 : _flag{ o._flag }
283 , _locked{ o._locked }
284 {
285 o._flag = nullptr;
286 o._locked = false;
287 }
288
289 AtomicFlagLock& operator=(AtomicFlagLock&& o)
290 {
291 cleanup();
292
293 _flag = o._flag;
294 _locked = o._locked;
295 o._flag = nullptr;
296 o._locked = false;
297 return *this;
298 }
299
300 ~AtomicFlagLock()
301 {
302 cleanup();
303 }
304
305 explicit operator bool() const
306 {
307 return _locked;
308 }
309 };
310
312 inline AtomicFlagLock scopelock(std::atomic_flag& f)
313 {
314 return AtomicFlagLock{ f };
315 }
316
317 template<typename T>
318 T src(const std::atomic<T>& x)
319 {
320 return x.load();
321 }
322
323 } // namespace qi
324
325 #define _QI_INSTANCIATE(_, a, elem) ::qi::detail::newAndAssign(&elem);
326
327 /* The code below relies on the fact that initialisation of the qi::Atomic
328 * can happen at static initialization time, and that proper memory barriers
329 * are setup by its ++, swap and get operations.
330 */
331
374 #define QI_THREADSAFE_NEW(...) \
375 QI_ONCE(QI_VAARGS_APPLY(_QI_INSTANCIATE, _, __VA_ARGS__);)
376
420 #define QI_ONCE(code) \
421 static qi::detail::StaticAtomicInt QI_UNIQ_DEF(atomic_guard_a) = {0}; \
422 static qi::detail::StaticAtomicInt QI_UNIQ_DEF(atomic_guard_b) = {0}; \
423 while (!QI_UNIQ_DEF(atomic_guard_a).setIfEquals(1, 1)) \
424 { \
425 bool tok = QI_UNIQ_DEF(atomic_guard_b).setIfEquals(0, 1); \
426 if (tok) \
427 { \
428 try \
429 { \
430 code; \
431 } \
432 catch (...) \
433 { \
434 QI_UNIQ_DEF(atomic_guard_b) = 0; \
435 throw; \
436 } \
437 ++QI_UNIQ_DEF(atomic_guard_a); \
438 } \
439 }
440
441 #endif // QI_ATOMIC_HPP_
qi::detail::setValue
void setValue(qi::Promise< R > &p, const boost::function< R()> &f)
Definition: executioncontext.hpp:148
qi::Atomic::Atomic
Atomic(T value)
Definition: atomic.hpp:168
qi::Atomic::swap
T swap(T value)
Definition: atomic.hpp:210
qi::Atomic::operator--
T operator--()
Atomic pre-decrement of the value.
Definition: atomic.hpp:182
qi::Atomic::setIfEquals
bool setIfEquals(T testValue, T setValue)
Definition: atomic.hpp:204
qi::detail::StaticAtomicInt::setIfEquals
bool setIfEquals(int testValue, int setValue)
qi::detail::StaticAtomicInt::operator*
int operator*() const
Definition: atomic.hpp:83
qi::Atomic::operator=
Atomic< T > & operator=(T value)
Definition: atomic.hpp:196
qi::Atomic::Atomic
Atomic()
Definition: atomic.hpp:162
qi::detail::StaticAtomicInt::operator=
StaticAtomicInt & operator=(int value)
qi::tryLowerAtomicFlag
bool tryLowerAtomicFlag(std::atomic< bool > &b)
Definition: atomic.hpp:251
qi::detail::StaticAtomicInt
Definition: atomic.hpp:72
qi::AtomicFlagLock::AtomicFlagLock
AtomicFlagLock(std::atomic_flag &f)
Definition: atomic.hpp:273
qi::testAndSet
long testAndSet(long *cond)
Definition: atomic.hpp:48
qi::detail::StaticAtomicInt::operator++
int operator++()
qi::Atomic
Definition: atomic.hpp:156
qi::tryRaiseAtomicFlag
bool tryRaiseAtomicFlag(std::atomic< bool > &b)
Definition: atomic.hpp:238
QI_NOEXCEPT
#define QI_NOEXCEPT(cond)
Specify that a function may throw or not. Do nothing if noexcept is not available.
Definition: macro.hpp:318
qi::AtomicFlagLock::~AtomicFlagLock
~AtomicFlagLock()
Definition: atomic.hpp:300
qi::Atomic::Atomic
Atomic(const Atomic &other)
Definition: atomic.hpp:174
qi::detail::newAndAssign
void newAndAssign(T **ptr)
Definition: atomic.hpp:227
qi::Atomic::operator++
T operator++()
Atomic pre-increment of the value.
Definition: atomic.hpp:179
qi::Atomic::operator++
T operator++(int)
Atomic post-increment of the value.
Definition: atomic.hpp:186
QI_API_DEPRECATED_MSG
#define QI_API_DEPRECATED_MSG(msg__)
Compiler flags to mark a function as deprecated. It will generate a compiler warning.
Definition: macro.hpp:55
qi::detail::StaticAtomicInt::operator--
int operator--()
qi::Atomic::_value
std::atomic< T > _value
Definition: atomic.hpp:158
qi::Atomic::operator=
Atomic< T > & operator=(const Atomic< T > &value)
Definition: atomic.hpp:198
qi::Atomic::operator--
T operator--(int)
Atomic post-decrement of the value.
Definition: atomic.hpp:191
qi::AtomicFlagLock::AtomicFlagLock
AtomicFlagLock(AtomicFlagLock &&o)
Definition: atomic.hpp:281
macro.hpp
Various macros for qi. (deprecated, export API, disallow copy, ..) <includename>qi/macro.hpp</includename> .
qi::AtomicFlagLock::operator=
AtomicFlagLock & operator=(AtomicFlagLock &&o)
Definition: atomic.hpp:289
qi::detail::StaticAtomicInt::swap
int swap(int value)
qi::AtomicFlagLock::operator=
AtomicFlagLock & operator=(const AtomicFlagLock &)=delete
qi::src
T src(const std::atomic< T > &x)
Definition: atomic.hpp:318
qi::detail::StaticAtomicInt::_value
volatile int _value
Definition: atomic.hpp:95
qi::scopelock
AtomicFlagLock scopelock(std::atomic_flag &f)
model ScopeLockable std::atomic_flag:
Definition: atomic.hpp:312
qi::Atomic::load
T load() const
Definition: atomic.hpp:221
qi::AtomicFlagLock
Definition: atomic.hpp:258