56b54ef7e51960b41ccbe75bdda23e3474be2471
[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-2017
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         /// Atomic item counter
195         /**
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.
198         */
199         class item_counter
200         {
201         public:
202             typedef atomics::atomic_size_t   atomic_type;   ///< atomic type used
203             typedef size_t counter_type;                    ///< Integral item counter type (size_t)
204
205         private:
206             //@cond
207             atomic_type                         m_Counter   ;   ///< Atomic item counter
208             //@endcond
209
210         public:
211             /// Default ctor initializes the counter to zero.
212             item_counter()
213                 : m_Counter(counter_type(0))
214             {}
215
216             /// Returns current value of the counter
217             counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
218             {
219                 return m_Counter.load( order );
220             }
221
222             /// Same as \ref value() with relaxed memory ordering
223             operator counter_type() const
224             {
225                 return value();
226             }
227
228             /// Returns underlying atomic interface
229             atomic_type& getAtomic()
230             {
231                 return m_Counter;
232             }
233
234             /// Returns underlying atomic interface (const)
235             const atomic_type& getAtomic() const
236             {
237                 return m_Counter;
238             }
239
240             /// Increments the counter. Semantics: postincrement
241             counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
242             {
243                 return m_Counter.fetch_add( 1, order );
244             }
245
246             /// Increments the counter. Semantics: postincrement
247             counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
248             {
249                 return m_Counter.fetch_add( count, order );
250             }
251
252             /// Decrements the counter. Semantics: postdecrement
253             counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
254             {
255                 return m_Counter.fetch_sub( 1, order );
256             }
257
258             /// Decrements the counter. Semantics: postdecrement
259             counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
260             {
261                 return m_Counter.fetch_sub( count, order );
262             }
263
264             /// Preincrement
265             counter_type operator ++()
266             {
267                 return inc() + 1;
268             }
269             /// Postincrement
270             counter_type operator ++(int)
271             {
272                 return inc();
273             }
274
275             /// Predecrement
276             counter_type operator --()
277             {
278                 return dec() - 1;
279             }
280             /// Postdecrement
281             counter_type operator --(int)
282             {
283                 return dec();
284             }
285
286             /// Increment by \p count
287             counter_type operator +=( counter_type count )
288             {
289                 return inc( count ) + count;
290             }
291
292             /// Decrement by \p count
293             counter_type operator -=( counter_type count )
294             {
295                 return dec( count ) - count;
296             }
297
298             /// Resets count to 0
299             void reset(atomics::memory_order order = atomics::memory_order_relaxed)
300             {
301                 m_Counter.store( 0, order );
302             }
303         };
304
305         /// Empty item counter
306         /**
307             This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
308             All methods of the class is empty and returns 0.
309
310             The object of this class should not be used in data structure that behavior significantly depends on item counting
311             (for example, in many hash map implementation).
312         */
313         class empty_item_counter {
314         public:
315             typedef size_t counter_type    ;  ///< Counter type
316         public:
317             /// Returns 0
318             static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
319             {
320                 return 0;
321             }
322
323             /// Same as \ref value(), always returns 0.
324             operator counter_type() const
325             {
326                 return value();
327             }
328
329             /// Dummy increment. Always returns 0
330             static counter_type inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
331             {
332                 return 0;
333             }
334
335             /// Dummy increment. Always returns 0
336             static counter_type inc( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
337             {
338                 return 0;
339             }
340
341             /// Dummy increment. Always returns 0
342             static counter_type dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
343             {
344                 return 0;
345             }
346
347             /// Dummy increment. Always returns 0
348             static counter_type dec( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
349             {
350                 return 0;
351             }
352
353             /// Dummy pre-increment. Always returns 0
354             counter_type operator ++() const
355             {
356                 return 0;
357             }
358             /// Dummy post-increment. Always returns 0
359             counter_type operator ++(int) const
360             {
361                 return 0;
362             }
363
364             /// Dummy pre-decrement. Always returns 0
365             counter_type operator --() const
366             {
367                 return 0;
368             }
369             /// Dummy post-decrement. Always returns 0
370             counter_type operator --(int) const
371             {
372                 return 0;
373             }
374
375             /// Dummy increment by \p count, always returns 0
376             counter_type operator +=( counter_type count )
377             {
378                 CDS_UNUSED( count );
379                 return 0;
380             }
381
382             /// Dummy decrement by \p count, always returns 0
383             counter_type operator -=( counter_type count )
384             {
385                 CDS_UNUSED( count );
386                 return 0;
387             }
388
389             /// Dummy function
390             static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
391             {}
392         };
393     }   // namespace atomicity
394 }   // namespace cds
395
396 #endif // #ifndef CDSLIB_CXX11_ATOMIC_H