c2306e860d3d6fbbfcc6bf73ebaa990274d1b4b4
[libcds.git] / cds / algo / atomic.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
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.
18
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.     
29 */
30
31 #ifndef CDSLIB_CXX11_ATOMIC_H
32 #define CDSLIB_CXX11_ATOMIC_H
33
34 #include <cds/details/defs.h>
35
36 namespace cds {
37
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 &lt;atomic&gt;. 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
44       in command line
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).
52
53       @note For Clang compiler \p libcds doesn't use native \p libc++ \p &lt;atomic&gt; due some problems.
54       Instead, \p libcds atomic is used by default, or you can try to use \p boost.atomic.
55
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
60 */
61 namespace cxx11_atomic {
62 }} // namespace cds::cxx11_atomic
63
64 //@cond
65 #if defined(CDS_USE_BOOST_ATOMIC)
66     // 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 }
73 #   else
74 #       error "Boost version 1.54 or above is needed for boost.atomic"
75 #   endif
76 #elif defined(CDS_USE_LIBCDS_ATOMIC)
77     // 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 }}
82 #else
83     // Compiler provided C++11 atomic
84 #   include <atomic>
85     namespace atomics = std;
86 #   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
87 #   define CDS_CXX11_ATOMIC_END_NAMESPACE }
88 #endif
89 //@endcond
90
91 namespace cds {
92
93     /// Atomic primitives
94     /**
95         This namespace contains useful primitives derived from <tt>std::atomic</tt>.
96     */
97     namespace atomicity {
98
99         /// Atomic event counter.
100         /**
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.
103         */
104         class event_counter
105         {
106             //@cond
107             atomics::atomic_size_t   m_counter;
108             //@endcond
109
110         public:
111             typedef size_t      value_type  ;       ///< Type of counter
112
113         public:
114             // Initializes event counter with zero
115             event_counter() CDS_NOEXCEPT
116                 : m_counter(size_t(0))
117             {}
118
119             /// Assign operator
120             /**
121                 Returns \p n.
122             */
123             value_type operator =(
124                 value_type n    //< new value of the counter
125             ) CDS_NOEXCEPT
126             {
127                 m_counter.exchange( n, atomics::memory_order_relaxed );
128                 return n;
129             }
130
131             /// Addition
132             /**
133                 Returns new value of the atomic counter.
134             */
135             size_t operator +=(
136                 size_t n    ///< addendum
137             ) CDS_NOEXCEPT
138             {
139                 return m_counter.fetch_add( n, atomics::memory_order_relaxed ) + n;
140             }
141
142             /// Substraction
143             /**
144                 Returns new value of the atomic counter.
145             */
146             size_t operator -=(
147                 size_t n    ///< subtrahend
148             ) CDS_NOEXCEPT
149             {
150                 return m_counter.fetch_sub( n, atomics::memory_order_relaxed ) - n;
151             }
152
153             /// Get current value of the counter
154             operator size_t () const CDS_NOEXCEPT
155             {
156                 return m_counter.load( atomics::memory_order_relaxed );
157             }
158
159             /// Preincrement
160             size_t operator ++() CDS_NOEXCEPT
161             {
162                 return m_counter.fetch_add( 1, atomics::memory_order_relaxed ) + 1;
163             }
164             /// Postincrement
165             size_t operator ++(int) CDS_NOEXCEPT
166             {
167                 return m_counter.fetch_add( 1, atomics::memory_order_relaxed );
168             }
169
170             /// Predecrement
171             size_t operator --() CDS_NOEXCEPT
172             {
173                 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed ) - 1;
174             }
175             /// Postdecrement
176             size_t operator --(int) CDS_NOEXCEPT
177             {
178                 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed );
179             }
180
181             /// Get current value of the counter
182             size_t get() const CDS_NOEXCEPT
183             {
184                 return m_counter.load( atomics::memory_order_relaxed );
185             }
186
187             /// Resets the counter to 0
188             void reset() CDS_NOEXCEPT
189             {
190                 m_counter.store( 0, atomics::memory_order_release );
191             }
192
193         };
194
195         /// Atomic item counter
196         /**
197             This class is simplified interface around <tt>std::atomic_size_t</tt>.
198             The class supports getting of current value of the counter and increment/decrement its value.
199         */
200         class item_counter
201         {
202         public:
203             typedef atomics::atomic_size_t   atomic_type ;   ///< atomic type used
204             typedef size_t counter_type    ;   ///< Integral item counter type (size_t)
205
206         private:
207             //@cond
208             atomic_type                         m_Counter   ;   ///< Atomic item counter
209             //@endcond
210
211         public:
212             /// Default ctor initializes the counter to zero.
213             item_counter()
214                 : m_Counter(counter_type(0))
215             {}
216
217             /// Returns current value of the counter
218             counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
219             {
220                 return m_Counter.load( order );
221             }
222
223             /// Same as \ref value() with relaxed memory ordering
224             operator counter_type() const
225             {
226                 return value();
227             }
228
229             /// Returns underlying atomic interface
230             atomic_type& getAtomic()
231             {
232                 return m_Counter;
233             }
234
235             /// Returns underlying atomic interface (const)
236             const atomic_type& getAtomic() const
237             {
238                 return m_Counter;
239             }
240
241             /// Increments the counter. Semantics: postincrement
242             counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
243             {
244                 return m_Counter.fetch_add( 1, order );
245             }
246
247             /// Decrements the counter. Semantics: postdecrement
248             counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
249             {
250                 return m_Counter.fetch_sub( 1, order );
251             }
252
253             /// Preincrement
254             counter_type operator ++()
255             {
256                 return inc() + 1;
257             }
258             /// Postincrement
259             counter_type operator ++(int)
260             {
261                 return inc();
262             }
263
264             /// Predecrement
265             counter_type operator --()
266             {
267                 return dec() - 1;
268             }
269             /// Postdecrement
270             counter_type operator --(int)
271             {
272                 return dec();
273             }
274
275             /// Resets count to 0
276             void reset(atomics::memory_order order = atomics::memory_order_relaxed)
277             {
278                 m_Counter.store( 0, order );
279             }
280         };
281
282         /// Empty item counter
283         /**
284             This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
285             All methods of the class is empty and returns 0.
286
287             The object of this class should not be used in data structure that behavior significantly depends on item counting
288             (for example, in many hash map implementation).
289         */
290         class empty_item_counter {
291         public:
292             typedef size_t counter_type    ;  ///< Counter type
293         public:
294             /// Returns 0
295             static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
296             {
297                 return 0;
298             }
299
300             /// Same as \ref value(), always returns 0.
301             operator counter_type() const
302             {
303                 return value();
304             }
305
306             /// Dummy increment. Always returns 0
307             static size_t inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
308             {
309                 return 0;
310             }
311
312             /// Dummy increment. Always returns 0
313             static size_t dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
314             {
315                 return 0;
316             }
317
318             /// Dummy pre-increment. Always returns 0
319             size_t operator ++() const
320             {
321                 return 0;
322             }
323             /// Dummy post-increment. Always returns 0
324             size_t operator ++(int) const
325             {
326                 return 0;
327             }
328
329             /// Dummy pre-decrement. Always returns 0
330             size_t operator --() const
331             {
332                 return 0;
333             }
334             /// Dummy post-decrement. Always returns 0
335             size_t operator --(int) const
336             {
337                 return 0;
338             }
339
340             /// Dummy function
341             static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
342             {}
343         };
344     }   // namespace atomicity
345 }   // namespace cds
346
347 #endif // #ifndef CDSLIB_CXX11_ATOMIC_H