-//$$CDS-header$$
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
#ifndef CDSLIB_CXX11_ATOMIC_H
#define CDSLIB_CXX11_ATOMIC_H
#include <cds/details/defs.h>
+#include <cds/user_setup/cache_line.h>
namespace cds {
Returns \p n.
*/
value_type operator =(
- value_type n //< new value of the counter
+ value_type n ///< new value of the counter
) CDS_NOEXCEPT
{
m_counter.exchange( n, atomics::memory_order_relaxed );
{
m_counter.store( 0, atomics::memory_order_release );
}
-
};
/// Atomic item counter
/**
- This class is simplified interface around <tt>std::atomic_size_t</tt>.
- The class supports getting of current value of the counter and increment/decrement its value.
+ This class is simplified interface around \p std::atomic_size_t.
+ The class supports getting current value of the counter and increment/decrement its value.
+
+ See alûo improved version that eliminates false sharing: \p cache_friendly_item_counter.
*/
class item_counter
{
public:
- typedef atomics::atomic_size_t atomic_type ; ///< atomic type used
- typedef size_t counter_type ; ///< Integral item counter type (size_t)
+ typedef atomics::atomic_size_t atomic_type; ///< atomic type used
+ typedef size_t counter_type; ///< Integral item counter type (size_t)
private:
//@cond
- atomic_type m_Counter ; ///< Atomic item counter
+ atomic_type m_Counter; ///< Atomic item counter
//@endcond
public:
{}
/// Returns current value of the counter
- counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
+ counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
+ {
+ return m_Counter.load( order );
+ }
+
+ /// Same as \ref value() with relaxed memory ordering
+ operator counter_type() const
+ {
+ return value();
+ }
+
+ /// Returns underlying atomic interface
+ atomic_type& getAtomic()
+ {
+ return m_Counter;
+ }
+
+ /// Returns underlying atomic interface (const)
+ const atomic_type& getAtomic() const
+ {
+ return m_Counter;
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( 1, order );
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( count, order );
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
+ {
+ return m_Counter.fetch_sub( 1, order );
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_sub( count, order );
+ }
+
+ /// Preincrement
+ counter_type operator ++()
+ {
+ return inc() + 1;
+ }
+ /// Postincrement
+ counter_type operator ++(int)
+ {
+ return inc();
+ }
+
+ /// Predecrement
+ counter_type operator --()
+ {
+ return dec() - 1;
+ }
+ /// Postdecrement
+ counter_type operator --(int)
+ {
+ return dec();
+ }
+
+ /// Increment by \p count
+ counter_type operator +=( counter_type count )
+ {
+ return inc( count ) + count;
+ }
+
+ /// Decrement by \p count
+ counter_type operator -=( counter_type count )
+ {
+ return dec( count ) - count;
+ }
+
+ /// Resets count to 0
+ void reset(atomics::memory_order order = atomics::memory_order_relaxed)
+ {
+ m_Counter.store( 0, order );
+ }
+ };
+
+ /// Atomic cache-friendly item counter
+ /**
+ Atomic item counter with cache-line padding to avoid false sharing.
+ Adding cache-line padding before and after atomic counter eliminates the contention
+ in read path of many containers and can notably improve search operations in sets/maps.
+ */
+ class cache_friendly_item_counter
+ {
+ public:
+ typedef atomics::atomic_size_t atomic_type; ///< atomic type used
+ typedef size_t counter_type; ///< Integral item counter type (size_t)
+
+ private:
+ //@cond
+ char pad1_[cds::c_nCacheLineSize];
+ atomic_type m_Counter; ///< Atomic item counter
+ char pad2_[cds::c_nCacheLineSize - sizeof( atomic_type )];
+ //@endcond
+
+ public:
+ /// Default ctor initializes the counter to zero.
+ cache_friendly_item_counter()
+ : m_Counter(counter_type(0))
+ {}
+
+ /// Returns current value of the counter
+ counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
{
return m_Counter.load( order );
}
}
/// Returns underlying atomic interface
- atomic_type& getAtomic()
+ atomic_type& getAtomic()
{
return m_Counter;
}
/// Returns underlying atomic interface (const)
- const atomic_type& getAtomic() const
+ const atomic_type& getAtomic() const
{
return m_Counter;
}
return m_Counter.fetch_add( 1, order );
}
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( count, order );
+ }
+
/// Decrements the counter. Semantics: postdecrement
counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
{
return m_Counter.fetch_sub( 1, order );
}
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_sub( count, order );
+ }
+
/// Preincrement
counter_type operator ++()
{
return dec();
}
+ /// Increment by \p count
+ counter_type operator +=( counter_type count )
+ {
+ return inc( count ) + count;
+ }
+
+ /// Decrement by \p count
+ counter_type operator -=( counter_type count )
+ {
+ return dec( count ) - count;
+ }
+
/// Resets count to 0
void reset(atomics::memory_order order = atomics::memory_order_relaxed)
{
}
};
+
/// Empty item counter
/**
This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
typedef size_t counter_type ; ///< Counter type
public:
/// Returns 0
- counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed) const
+ static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{
return 0;
}
}
/// Dummy increment. Always returns 0
- size_t inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ static counter_type inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{
return 0;
}
/// Dummy increment. Always returns 0
- size_t dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ static counter_type inc( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
+ {
+ return 0;
+ }
+
+ /// Dummy increment. Always returns 0
+ static counter_type dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ {
+ return 0;
+ }
+
+ /// Dummy increment. Always returns 0
+ static counter_type dec( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
{
return 0;
}
/// Dummy pre-increment. Always returns 0
- size_t operator ++()
+ counter_type operator ++() const
{
return 0;
}
/// Dummy post-increment. Always returns 0
- size_t operator ++(int)
+ counter_type operator ++(int) const
{
return 0;
}
/// Dummy pre-decrement. Always returns 0
- size_t operator --()
+ counter_type operator --() const
{
return 0;
}
/// Dummy post-decrement. Always returns 0
- size_t operator --(int)
+ counter_type operator --(int) const
+ {
+ return 0;
+ }
+
+ /// Dummy increment by \p count, always returns 0
+ counter_type operator +=( counter_type count )
+ {
+ CDS_UNUSED( count );
+ return 0;
+ }
+
+ /// Dummy decrement by \p count, always returns 0
+ counter_type operator -=( counter_type count )
{
+ CDS_UNUSED( count );
return 0;
}
/// Dummy function
- void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
{}
};
} // namespace atomicity