MSPriorityQueue: removed monotonic_counter due its horrible performance
[libcds.git] / cds / intrusive / tsigas_cycle_queue.h
index 42349395208c7a49a5a0f26cfca81f4aa06fbcd3..b667f39cab32d5dff070eeddea2f3cc65878d596 100644 (file)
@@ -1,7 +1,35 @@
-//$$CDS-header$$
-
-#ifndef __CDS_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H
-#define __CDS_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    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_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H
+#define CDSLIB_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H
 
 #include <cds/intrusive/details/base.h>
 #include <cds/algo/atomic.h>
@@ -24,8 +52,10 @@ namespace cds { namespace intrusive {
                 buffer for required type via \p rebind metafunction.
 
                 For \p TsigasCycleQueue queue the buffer size should have power-of-2 size.
+
+                You should use any initialized buffer type, see \p opt::buffer.
             */
-            typedef cds::opt::v::dynamic_buffer< void * > buffer;
+            typedef cds::opt::v::initialized_dynamic_buffer< void * > buffer;
 
             /// Back-off strategy
             typedef cds::backoff::empty         back_off;
@@ -43,22 +73,22 @@ namespace cds { namespace intrusive {
             */
             typedef opt::v::relaxed_ordering    memory_model;
 
-            /// Alignment for internal queue data. Default is \p opt::cache_line_alignment
-            enum { alignment = opt::cache_line_alignment };
+            /// Padding for internal critical atomic data. Default is \p opt::cache_line_padding
+            enum { padding = opt::cache_line_padding };
         };
 
         /// Metafunction converting option list to \p tsigas_queue::traits
         /**
             Supported \p Options are:
             - \p opt::buffer - the buffer type for internal cyclic array. Possible types are:
-                \p opt::v::dynamic_buffer (the default), \p opt::v::static_buffer. The type of
+                \p opt::v::initialized_dynamic_buffer (the default), \p opt::v::initialized_static_buffer. The type of
                 element in the buffer is not important: it will be changed via \p rebind metafunction.
             - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty.
             - \p opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used
                 when dequeuing.
             - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled)
                 To enable item counting use \p cds::atomicity::item_counter
-            - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment
+            - \p opt::padding - padding for internal critical atomic data. Default is \p opt::cache_line_padding
             - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
                 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
 
@@ -66,7 +96,7 @@ namespace cds { namespace intrusive {
             \code
             typedef cds::intrusive::TsigasCycleQueue< Foo,
                 typename cds::intrusive::tsigas_queue::make_traits<
-                    cds::opt::buffer< cds::opt::v::static_buffer< void *, 1024 >,
+                    cds::opt::buffer< cds::opt::v::initialized_static_buffer< void *, 1024 >,
                     cds::opt::item_counte< cds::atomicity::item_counter >
                 >::type
             > myQueue;
@@ -128,7 +158,7 @@ namespace cds { namespace intrusive {
         // Queue of Foo pointers, capacity is 1024, statically allocated buffer:
         struct queue_traits: public cds::intrusive::tsigas_queue::traits
         {
-            typedef cds::opt::v::static_buffer< Foo, 1024 > buffer;
+            typedef cds::opt::v::initialized_static_buffer< Foo, 1024 > buffer;
         };
         typedef cds::intrusive::TsigasCycleQueue< Foo, queue_traits > static_queue;
         static_queue    stQueue;
@@ -136,7 +166,7 @@ namespace cds { namespace intrusive {
         // Queue of Foo pointers, capacity is 1024, dynamically allocated buffer, with item counting:
         typedef cds::intrusive::TsigasCycleQueue< Foo,
             typename cds::intrusive::tsigas_queue::make_traits<
-                cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > >,
+                cds::opt::buffer< cds::opt::v::initialized_dynamic_buffer< Foo > >,
                 cds::opt::item_counter< cds::atomicity::item_counter >
             >::type
         > dynamic_queue;
@@ -164,17 +194,18 @@ namespace cds { namespace intrusive {
 
     protected:
         //@cond
-        typedef typename opt::details::alignment_setter< buffer, traits::alignment >::type aligned_buffer;
         typedef size_t index_type;
-        typedef typename opt::details::alignment_setter< atomics::atomic<index_type>, traits::alignment >::type aligned_index;
         //@endcond
 
     protected:
         //@cond
-        buffer          m_buffer    ;   ///< array of pointer T *, array size is equal to m_nCapacity+1
-        aligned_index   m_nHead     ;   ///< index of queue's head
-        aligned_index   m_nTail     ;   ///< index of queue's tail
-        item_counter    m_ItemCounter   ;   ///< item counter
+        buffer       m_buffer    ;   ///< array of pointer T *, array size is equal to m_nCapacity+1
+        typename opt::details::apply_padding< index_type, traits::padding >::padding_type pad1_;
+        atomics::atomic<index_type>   m_nHead     ;   ///< index of queue's head
+        typename opt::details::apply_padding< index_type, traits::padding >::padding_type pad2_;
+        atomics::atomic<index_type>   m_nTail     ;   ///< index of queue's tail
+        typename opt::details::apply_padding< index_type, traits::padding >::padding_type pad3_;
+        item_counter m_ItemCounter;  ///< item counter
         //@endcond
 
     protected:
@@ -184,7 +215,7 @@ namespace cds { namespace intrusive {
 
         static bool is_free( const value_type * p ) CDS_NOEXCEPT
         {
-            return p == reinterpret_cast<value_type *>(free0) || p == reinterpret_cast<value_type *>(free1);
+            return (reinterpret_cast<intptr_t>(p) & ~intptr_t(1)) == 0;
         }
 
         size_t CDS_CONSTEXPR buffer_capacity() const CDS_NOEXCEPT
@@ -201,7 +232,7 @@ namespace cds { namespace intrusive {
     public:
         /// Initialize empty queue of capacity \p nCapacity
         /**
-            If internal buffer type is \p cds::opt::v::static_buffer, the \p nCapacity parameter is ignored.
+            If internal buffer type is \p cds::opt::v::initialized_static_buffer, the \p nCapacity parameter is ignored.
 
             Note that the real capacity of queue is \p nCapacity - 2.
         */
@@ -248,7 +279,7 @@ namespace cds { namespace intrusive {
                     temp = (temp + 1) & nModulo;
                 }
 
-                if ( te != m_nTail.load(memory_model::memory_order_relaxed) )
+                if ( te != m_nTail.load(memory_model::memory_order_acquire) )
                     continue;
 
                 // Check whether queue is full
@@ -266,7 +297,7 @@ namespace cds { namespace intrusive {
 
                 if ( tt == reinterpret_cast<value_type *>(free1) )
                     pNewNode = reinterpret_cast<value_type *>(reinterpret_cast<intptr_t>( pNewNode ) | 1);
-                if ( te != m_nTail.load(memory_model::memory_order_relaxed) )
+                if ( te != m_nTail.load(memory_model::memory_order_acquire) )
                     continue;
 
                 // get actual tail and try to enqueue new node
@@ -423,4 +454,4 @@ namespace cds { namespace intrusive {
 
 }}  // namespace cds::intrusive
 
-#endif  // #ifndef __CDS_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H
+#endif  // #ifndef CDSLIB_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H