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>
35 #include <cds/user_setup/cache_line.h>
39 /// C++11 Atomic library support
40 /** @anchor cds_cxx11_atomic
41 \p libcds can use the following implementations of the atomics:
42 - STL \p <atomic>. This is used by default
43 - \p boost.atomic for boost 1.54 and above. To use it you should define \p CDS_USE_BOOST_ATOMIC for
44 your compiler invocation, for example, for gcc specify \p -DCDS_USE_BOOST_ATOMIC
46 - \p libcds implementation of atomic operation according to C++11 standard as
47 specified in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">N3242, p.29</a>.
48 \p libcds implementation is not the full standard compliant, it provides only C++ part of standard,
49 for example, \p libcds has no static initialization of the atomic variables and some other C features.
50 However, that imlementation is enough for the library purposes. Supported architecture: x86, amd64,
51 ia64 (Itanium) 64bit, 64bit Sparc. To use \p libcds atomic you should define \p CDS_USE_LIBCDS_ATOMIC
52 in the compiler command line (\p -DCDS_USE_LIBCDS_ATOMIC for gcc/clang).
54 @note For Clang compiler \p libcds doesn't use native \p libc++ \p <atomic> due some problems.
55 Instead, \p libcds atomic is used by default, or you can try to use \p boost.atomic.
57 The library defines \p atomics alias for atomic namespace:
58 - <tt>namespace atomics = std</tt> for STL
59 - <tt>namespace atomics = boost</tt> for \p boost.atomic
60 - <tt>namespace atomics = cds::cxx11_atomic</tt> for library-provided atomic implementation
62 namespace cxx11_atomic {
63 }} // namespace cds::cxx11_atomic
66 #if defined(CDS_USE_BOOST_ATOMIC)
68 # include <boost/version.hpp>
69 # if BOOST_VERSION >= 105400
70 # include <boost/atomic.hpp>
71 namespace atomics = boost;
72 # define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
73 # define CDS_CXX11_ATOMIC_END_NAMESPACE }
75 # error "Boost version 1.54 or above is needed for boost.atomic"
77 #elif defined(CDS_USE_LIBCDS_ATOMIC)
79 # include <cds/compiler/cxx11_atomic.h>
80 namespace atomics = cds::cxx11_atomic;
81 # define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomic {
82 # define CDS_CXX11_ATOMIC_END_NAMESPACE }}
84 // Compiler provided C++11 atomic
86 namespace atomics = std;
87 # define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
88 # define CDS_CXX11_ATOMIC_END_NAMESPACE }
96 This namespace contains useful primitives derived from <tt>std::atomic</tt>.
100 /// Atomic event counter.
102 This class is based on <tt>std::atomic_size_t</tt>.
103 It uses relaxed memory ordering \p memory_order_relaxed and may be used as a statistic counter.
108 atomics::atomic_size_t m_counter;
112 typedef size_t value_type ; ///< Type of counter
115 // Initializes event counter with zero
116 event_counter() CDS_NOEXCEPT
117 : m_counter(size_t(0))
124 value_type operator =(
125 value_type n ///< new value of the counter
128 m_counter.exchange( n, atomics::memory_order_relaxed );
134 Returns new value of the atomic counter.
137 size_t n ///< addendum
140 return m_counter.fetch_add( n, atomics::memory_order_relaxed ) + n;
145 Returns new value of the atomic counter.
148 size_t n ///< subtrahend
151 return m_counter.fetch_sub( n, atomics::memory_order_relaxed ) - n;
154 /// Get current value of the counter
155 operator size_t () const CDS_NOEXCEPT
157 return m_counter.load( atomics::memory_order_relaxed );
161 size_t operator ++() CDS_NOEXCEPT
163 return m_counter.fetch_add( 1, atomics::memory_order_relaxed ) + 1;
166 size_t operator ++(int) CDS_NOEXCEPT
168 return m_counter.fetch_add( 1, atomics::memory_order_relaxed );
172 size_t operator --() CDS_NOEXCEPT
174 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed ) - 1;
177 size_t operator --(int) CDS_NOEXCEPT
179 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed );
182 /// Get current value of the counter
183 size_t get() const CDS_NOEXCEPT
185 return m_counter.load( atomics::memory_order_relaxed );
188 /// Resets the counter to 0
189 void reset() CDS_NOEXCEPT
191 m_counter.store( 0, atomics::memory_order_release );
195 /// Atomic item counter
197 This class is simplified interface around \p std::atomic_size_t.
198 The class supports getting current value of the counter and increment/decrement its value.
200 See also: improved version that eliminates false sharing - \p cache_friendly_item_counter.
205 typedef atomics::atomic_size_t atomic_type; ///< atomic type used
206 typedef size_t counter_type; ///< Integral item counter type (size_t)
210 atomic_type m_Counter; ///< Atomic item counter
214 /// Default ctor initializes the counter to zero.
216 : m_Counter(counter_type(0))
219 /// Returns current value of the counter
220 counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
222 return m_Counter.load( order );
225 /// Same as \ref value() with relaxed memory ordering
226 operator counter_type() const
231 /// Returns underlying atomic interface
232 atomic_type& getAtomic()
237 /// Returns underlying atomic interface (const)
238 const atomic_type& getAtomic() const
243 /// Increments the counter. Semantics: postincrement
244 counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
246 return m_Counter.fetch_add( 1, order );
249 /// Increments the counter. Semantics: postincrement
250 counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
252 return m_Counter.fetch_add( count, order );
255 /// Decrements the counter. Semantics: postdecrement
256 counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
258 return m_Counter.fetch_sub( 1, order );
261 /// Decrements the counter. Semantics: postdecrement
262 counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
264 return m_Counter.fetch_sub( count, order );
268 counter_type operator ++()
273 counter_type operator ++(int)
279 counter_type operator --()
284 counter_type operator --(int)
289 /// Increment by \p count
290 counter_type operator +=( counter_type count )
292 return inc( count ) + count;
295 /// Decrement by \p count
296 counter_type operator -=( counter_type count )
298 return dec( count ) - count;
301 /// Resets count to 0
302 void reset(atomics::memory_order order = atomics::memory_order_relaxed)
304 m_Counter.store( 0, order );
308 #if CDS_COMPILER == CDS_COMPILER_CLANG
309 // CLang unhappy: pad1_ and pad2_ - unused private field warning
310 # pragma GCC diagnostic push
311 # pragma GCC diagnostic ignored "-Wunused-private-field"
313 /// Atomic cache-friendly item counter
315 Atomic item counter with cache-line padding to avoid false sharing.
316 Adding cache-line padding before and after atomic counter eliminates the contention
317 in read path of many containers and can notably improve search operations in sets/maps.
319 class cache_friendly_item_counter
322 typedef atomics::atomic_size_t atomic_type; ///< atomic type used
323 typedef size_t counter_type; ///< Integral item counter type (size_t)
327 char pad1_[cds::c_nCacheLineSize];
328 atomic_type m_Counter; ///< Atomic item counter
329 char pad2_[cds::c_nCacheLineSize - sizeof( atomic_type )];
333 /// Default ctor initializes the counter to zero.
334 cache_friendly_item_counter()
335 : m_Counter(counter_type(0))
338 /// Returns current value of the counter
339 counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
341 return m_Counter.load( order );
344 /// Same as \ref value() with relaxed memory ordering
345 operator counter_type() const
350 /// Returns underlying atomic interface
351 atomic_type& getAtomic()
356 /// Returns underlying atomic interface (const)
357 const atomic_type& getAtomic() const
362 /// Increments the counter. Semantics: postincrement
363 counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
365 return m_Counter.fetch_add( 1, order );
368 /// Increments the counter. Semantics: postincrement
369 counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
371 return m_Counter.fetch_add( count, order );
374 /// Decrements the counter. Semantics: postdecrement
375 counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
377 return m_Counter.fetch_sub( 1, order );
380 /// Decrements the counter. Semantics: postdecrement
381 counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
383 return m_Counter.fetch_sub( count, order );
387 counter_type operator ++()
392 counter_type operator ++(int)
398 counter_type operator --()
403 counter_type operator --(int)
408 /// Increment by \p count
409 counter_type operator +=( counter_type count )
411 return inc( count ) + count;
414 /// Decrement by \p count
415 counter_type operator -=( counter_type count )
417 return dec( count ) - count;
420 /// Resets count to 0
421 void reset(atomics::memory_order order = atomics::memory_order_relaxed)
423 m_Counter.store( 0, order );
426 #if CDS_COMPILER == CDS_COMPILER_CLANG
427 # pragma GCC diagnostic pop
430 /// Empty item counter
432 This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
433 All methods of the class is empty and returns 0.
435 The object of this class should not be used in data structure that behavior significantly depends on item counting
436 (for example, in many hash map implementation).
438 class empty_item_counter {
440 typedef size_t counter_type ; ///< Counter type
443 static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
448 /// Same as \ref value(), always returns 0.
449 operator counter_type() const
454 /// Dummy increment. Always returns 0
455 static counter_type inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
460 /// Dummy increment. Always returns 0
461 static counter_type inc( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
466 /// Dummy increment. Always returns 0
467 static counter_type dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
472 /// Dummy increment. Always returns 0
473 static counter_type dec( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
478 /// Dummy pre-increment. Always returns 0
479 counter_type operator ++() const
483 /// Dummy post-increment. Always returns 0
484 counter_type operator ++(int) const
489 /// Dummy pre-decrement. Always returns 0
490 counter_type operator --() const
494 /// Dummy post-decrement. Always returns 0
495 counter_type operator --(int) const
500 /// Dummy increment by \p count, always returns 0
501 counter_type operator +=( counter_type count )
507 /// Dummy decrement by \p count, always returns 0
508 counter_type operator -=( counter_type count )
515 static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
518 } // namespace atomicity
521 #endif // #ifndef CDSLIB_CXX11_ATOMIC_H