2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef CDSLIB_CXX11_ATOMIC_H
32 #define CDSLIB_CXX11_ATOMIC_H
34 #include <cds/details/defs.h>
38 /// C++11 Atomic library support
39 /** @anchor cds_cxx11_atomic
40 \p libcds can use the following implementations of the atomics:
41 - STL \p <atomic>. This is used by default
42 - \p boost.atomic for boost 1.54 and above. To use it you should define \p CDS_USE_BOOST_ATOMIC for
43 your compiler invocation, for example, for gcc specify \p -DCDS_USE_BOOST_ATOMIC
45 - \p libcds implementation of atomic operation according to C++11 standard as
46 specified in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">N3242, p.29</a>.
47 \p libcds implementation is not the full standard compliant, it provides only C++ part of standard,
48 for example, \p libcds has no static initialization of the atomic variables and some other C features.
49 However, that imlementation is enough for the library purposes. Supported architecture: x86, amd64,
50 ia64 (Itanium) 64bit, 64bit Sparc. To use \p libcds atomic you should define \p CDS_USE_LIBCDS_ATOMIC
51 in the compiler command line (\p -DCDS_USE_LIBCDS_ATOMIC for gcc/clang).
53 @note For Clang compiler \p libcds doesn't use native \p libc++ \p <atomic> due some problems.
54 Instead, \p libcds atomic is used by default, or you can try to use \p boost.atomic.
56 The library defines \p atomics alias for atomic namespace:
57 - <tt>namespace atomics = std</tt> for STL
58 - <tt>namespace atomics = boost</tt> for \p boost.atomic
59 - <tt>namespace atomics = cds::cxx11_atomic</tt> for library-provided atomic implementation
61 namespace cxx11_atomic {
62 }} // namespace cds::cxx11_atomic
65 #if defined(CDS_USE_BOOST_ATOMIC)
67 # include <boost/version.hpp>
68 # if BOOST_VERSION >= 105400
69 # include <boost/atomic.hpp>
70 namespace atomics = boost;
71 # define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
72 # define CDS_CXX11_ATOMIC_END_NAMESPACE }
74 # error "Boost version 1.54 or above is needed for boost.atomic"
76 #elif defined(CDS_USE_LIBCDS_ATOMIC)
78 # include <cds/compiler/cxx11_atomic.h>
79 namespace atomics = cds::cxx11_atomic;
80 # define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomic {
81 # define CDS_CXX11_ATOMIC_END_NAMESPACE }}
83 // Compiler provided C++11 atomic
85 namespace atomics = std;
86 # define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
87 # define CDS_CXX11_ATOMIC_END_NAMESPACE }
95 This namespace contains useful primitives derived from <tt>std::atomic</tt>.
99 /// Atomic event counter.
101 This class is based on <tt>std::atomic_size_t</tt>.
102 It uses relaxed memory ordering \p memory_order_relaxed and may be used as a statistic counter.
107 atomics::atomic_size_t m_counter;
111 typedef size_t value_type ; ///< Type of counter
114 // Initializes event counter with zero
115 event_counter() CDS_NOEXCEPT
116 : m_counter(size_t(0))
123 value_type operator =(
124 value_type n ///< new value of the counter
127 m_counter.exchange( n, atomics::memory_order_relaxed );
133 Returns new value of the atomic counter.
136 size_t n ///< addendum
139 return m_counter.fetch_add( n, atomics::memory_order_relaxed ) + n;
144 Returns new value of the atomic counter.
147 size_t n ///< subtrahend
150 return m_counter.fetch_sub( n, atomics::memory_order_relaxed ) - n;
153 /// Get current value of the counter
154 operator size_t () const CDS_NOEXCEPT
156 return m_counter.load( atomics::memory_order_relaxed );
160 size_t operator ++() CDS_NOEXCEPT
162 return m_counter.fetch_add( 1, atomics::memory_order_relaxed ) + 1;
165 size_t operator ++(int) CDS_NOEXCEPT
167 return m_counter.fetch_add( 1, atomics::memory_order_relaxed );
171 size_t operator --() CDS_NOEXCEPT
173 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed ) - 1;
176 size_t operator --(int) CDS_NOEXCEPT
178 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed );
181 /// Get current value of the counter
182 size_t get() const CDS_NOEXCEPT
184 return m_counter.load( atomics::memory_order_relaxed );
187 /// Resets the counter to 0
188 void reset() CDS_NOEXCEPT
190 m_counter.store( 0, atomics::memory_order_release );
194 /// Atomic item counter
196 This class is simplified interface around \p std::atomic_size_t.
197 The class supports getting of current value of the counter and increment/decrement its value.
202 typedef atomics::atomic_size_t atomic_type ; ///< atomic type used
203 typedef size_t counter_type ; ///< Integral item counter type (size_t)
207 atomic_type m_Counter ; ///< Atomic item counter
211 /// Default ctor initializes the counter to zero.
213 : m_Counter(counter_type(0))
216 /// Returns current value of the counter
217 counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
219 return m_Counter.load( order );
222 /// Same as \ref value() with relaxed memory ordering
223 operator counter_type() const
228 /// Returns underlying atomic interface
229 atomic_type& getAtomic()
234 /// Returns underlying atomic interface (const)
235 const atomic_type& getAtomic() const
240 /// Increments the counter. Semantics: postincrement
241 counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
243 return m_Counter.fetch_add( 1, order );
246 /// Decrements the counter. Semantics: postdecrement
247 counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
249 return m_Counter.fetch_sub( 1, order );
253 counter_type operator ++()
258 counter_type operator ++(int)
264 counter_type operator --()
269 counter_type operator --(int)
274 /// Resets count to 0
275 void reset(atomics::memory_order order = atomics::memory_order_relaxed)
277 m_Counter.store( 0, order );
281 /// Empty item counter
283 This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
284 All methods of the class is empty and returns 0.
286 The object of this class should not be used in data structure that behavior significantly depends on item counting
287 (for example, in many hash map implementation).
289 class empty_item_counter {
291 typedef size_t counter_type ; ///< Counter type
294 static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
299 /// Same as \ref value(), always returns 0.
300 operator counter_type() const
305 /// Dummy increment. Always returns 0
306 static size_t inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
311 /// Dummy increment. Always returns 0
312 static size_t dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
317 /// Dummy pre-increment. Always returns 0
318 size_t operator ++() const
322 /// Dummy post-increment. Always returns 0
323 size_t operator ++(int) const
328 /// Dummy pre-decrement. Always returns 0
329 size_t operator --() const
333 /// Dummy post-decrement. Always returns 0
334 size_t operator --(int) const
340 static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
343 } // namespace atomicity
346 #endif // #ifndef CDSLIB_CXX11_ATOMIC_H