From 07b8d006909dfa9c13874f578138d55c7a9b9bf8 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Wed, 27 Dec 2017 10:56:07 +0300 Subject: [PATCH 01/46] Valois list (unfinished) --- cds/intrusive/impl/valois_list.h | 258 ++++++++++++++++++ test/unit/intrusive-list/CMakeLists.txt | 16 +- .../intrusive-list/intrusive_valois_dhp.cpp | 39 +++ .../intrusive-list/intrusive_valois_hp.cpp | 39 +++ 4 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 cds/intrusive/impl/valois_list.h create mode 100644 test/unit/intrusive-list/intrusive_valois_dhp.cpp create mode 100644 test/unit/intrusive-list/intrusive_valois_hp.cpp diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h new file mode 100644 index 000000000..f0db733ae --- /dev/null +++ b/cds/intrusive/impl/valois_list.h @@ -0,0 +1,258 @@ +// + +#ifndef CDS_VALOIS_LIST_H +#define CDS_VALOIS_LIST_H + +#include +#include +#include + +namespace cds +{ + namespace intrusive{ + namespace valois_list{ + + struct traits + { + /// Key comparison functor + /** + No default functor is provided. If the option is not specified, the \p less is used. + */ + typedef opt::none compare; + + /// Specifies binary predicate used for key compare. + /** + Default is \p std::less + */ + typedef opt::none less; + + /// Node allocator + typedef CDS_DEFAULT_ALLOCATOR node_allocator; + + /// Back-off strategy + typedef cds::backoff::Default back_off; + + /// Disposer for removing items + typedef opt::v::empty_disposer disposer; + + + /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter or \p atomicity::cache_friendly_item_counter to enable item counting + typedef atomicity::empty_item_counter item_counter; + + /// 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). + */ + typedef opt::v::relaxed_ordering memory_model; + }; + + template + struct node + { + typedef T value_type; ///< Value type + typedef cds::details::marked_ptr marked_data_ptr; ///< marked pointer to the value + + atomics::atomic< node* > next; ///< pointer to next node in the list + atomics::atomic< node* > prev; ///< pointer to previous node in the list + atomics::atomic< marked_data_ptr > data; ///< pointer to user data, \p nullptr if the node is free + + node() + { + next.store( nullptr, atomics::memory_order_release ); + prev.store( nullptr, atomics::memory_order_release ); + data.store( marked_data_ptr(), atomics::memory_order_release ); + } + + node( value_type * pVal ) + { + next.store( nullptr, atomics::memory_order_release ); + prev.store( nullptr, atomics::memory_order_release ); + data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); + } + + }; + + template + class ValoisList{ + public: + + typedef T value_type; ///< type of value stored in the list + typedef Traits traits; ///< Traits template parameter + + typedef valois_list::node< value_type > node_type; ///< node type + + typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; + + typedef typename traits::disposer disposer; ///< disposer for \p value_type + + typedef GC gc; ///< Garbage collector + typedef typename traits::back_off back_off; ///< back-off strategy + typedef typename traits::item_counter item_counter; ///< Item counting policy used + typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option + typedef typename traits::node_allocator node_allocator; ///< Node allocator + typedef typename traits::stat stat; ///< Internal statistics + + typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer + + static constexpr const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm + + protected: + node_type *head; + node_type *tail; + + typedef atomics::atomic< node_type* > atomic_node_ptr; ///< Atomic node pointer + typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support) + typedef typename node_type::marked_data_ptr marked_data_ptr; + + item_counter m_ItemCounter; ///< Item counter + + typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator; + + /// Position pointer for item search + struct position { + node_type const* pHead; + node_type * pPrev; ///< Previous node + node_type * pCur; ///< Current node + + value_type * pFound; ///< Value of \p pCur->data, valid only if data found + + typename gc::Guard guard; ///< guard for \p pFound + }; + + struct insert_position: public position + { + value_type * pPrevVal; ///< Value of \p pPrev->data, can be \p nullptr + typename gc::Guard prevGuard; ///< guard for \p pPrevVal + }; + + protected: + class iterator + { + friend class ValoisList; + protected: + node_type * consider_node; + + iterator(node_type * consider_node){ + if (!m_Guard.protect(consider_node->data, []( marked_data_ptr p ) {return p.ptr(); }).ptr()) + next(); + } + + void next() + { + for ( node_type* p = consider_node->next.load( memory_model::memory_order_relaxed ); p != m_pNode; p = p->next.load( memory_model::memory_order_relaxed )) + { + m_pNode = p; + if ( m_Guard.protect( p->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr()) + return; + } + m_Guard.clear(); + } + + value_type* data() const + { + return m_Guard.template get(); + } + + }; + + public: + ValoisList(){ + head.next.store( &tail, memory_model::memory_order_relaxed ); + tail.next.store( NULL, memory_model::memory_order_release ); + } + ~ValoisList(){ + node_type * consider_node = m_Head.next.load( memory_model::memory_order_relaxed ); + while ( consider_node != consider_node->next.load( memory_model::memory_order_relaxed )) { + value_type * pVal = consider_node->data.load( memory_model::memory_order_relaxed ).ptr(); + if ( pVal ) + retire_data( pVal ); + node_type * pNext = consider_node->next.load( memory_model::memory_order_relaxed ); + delete_node( consider_node ); + consider_node = pNext; + } + } + + iterator begin(){ + return iterator(&head); + } + + iterator end(){ + return iterator(&tail); + } + + bool insert( node_type * consider_node ){ + + assert( consider_node != nullptr ); + assert( consider_node->data.load( memory_model::memory_order_relaxed ) != nullptr ); + + insert_position pos; + + pos.pHead = pHead; + node_type* pPrev = const_cast(pHead); + value_type* pPrevVal = pPrev->data.load( memory_model::memory_order_relaxed ).ptr(); + + node_type * pCur = pPrev->next.load( memory_model::memory_order_relaxed ); + + + value_type * pVal = pos.guard.protect( pCur->data, + []( marked_data_ptr p ) -> value_type* + { + return p.ptr(); + } ).ptr(); + + + pPrev = pCur; + pPrevVal = pVal; + pos.prevGuard.copy( pos.guard ); + +// if ( connect_node(consider_node) ) { + ++m_ItemCounter; + return true; +// } + } + + bool update(){ + return true; + } + + bool erase(node_type * consider_node){ + + assert( consider_node != nullptr ); + assert( consider_node->data.load( memory_model::memory_order_relaxed ) != nullptr ); + + return true; + } + + + protected: + + node_type* head(){ + return head; + } + + node_type* tail(){ + return tail; + } + + private: + + node_type * alloc_node( value_type * pVal ){ + return cxx_node_allocator().New( pVal ); + } + + void delete_node( node_type * consider_node ){ + cxx_node_allocator().Delete( consider_node ); + } + + void retire_data( value_type * pVal ){ + assert( pVal != nullptr ); + gc::template retire( pVal ); + } + + }; + } + } +} + +#endif //CDS_VALOIS_LIST_H diff --git a/test/unit/intrusive-list/CMakeLists.txt b/test/unit/intrusive-list/CMakeLists.txt index 3e588164b..0b24eca65 100644 --- a/test/unit/intrusive-list/CMakeLists.txt +++ b/test/unit/intrusive-list/CMakeLists.txt @@ -47,9 +47,21 @@ target_link_libraries(${UNIT_ILIST_ITERABLE} ${CDS_TEST_LIBRARIES}) add_test(NAME ${UNIT_ILIST_ITERABLE} COMMAND ${UNIT_ILIST_ITERABLE} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) +# intrusive::ValoisList +set(UNIT_ILIST_VALOIS unit-ilist-valois) +set(UNIT_ILIST_VALOIS_SOURCES + ../main.cpp + intrusive_valois_hp.cpp + intrusive_valois_dhp.cpp + ) +add_executable(${UNIT_ILIST_VALOIS} ${UNIT_ILIST_VALOIS_SOURCES}) +target_link_libraries(${UNIT_ILIST_VALOIS} ${CDS_TEST_LIBRARIES}) +add_test(NAME ${UNIT_ILIST_VALOIS} COMMAND ${UNIT_ILIST_VALOIS} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) + add_custom_target( unit-ilist - DEPENDS + DEPENDS ${UNIT_ILIST_ITERABLE} ${UNIT_ILIST_LAZY} ${UNIT_ILIST_MICHAEL} -) + ${UNIT_ILIST_VALOIS} + ) diff --git a/test/unit/intrusive-list/intrusive_valois_dhp.cpp b/test/unit/intrusive-list/intrusive_valois_dhp.cpp new file mode 100644 index 000000000..8d8de3774 --- /dev/null +++ b/test/unit/intrusive-list/intrusive_valois_dhp.cpp @@ -0,0 +1,39 @@ +/* + 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. +*/ + +#include "test_intrusive_iterable_list_hp.h" +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + +} // namespace diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp new file mode 100644 index 000000000..67e2c42b2 --- /dev/null +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -0,0 +1,39 @@ +/* + 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. +*/ + +#include "test_intrusive_iterable_list_hp.h" +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + +} // namespace From 1b0be1832eb39b55495458dbed86687c4ff8afb3 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Thu, 4 Jan 2018 13:33:57 +0300 Subject: [PATCH 02/46] Cleaned --- cds/intrusive/impl/valois_list.h | 150 +++++++++++++++---------------- 1 file changed, 72 insertions(+), 78 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index f0db733ae..943cb5005 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -60,71 +60,77 @@ namespace cds node() { next.store( nullptr, atomics::memory_order_release ); - prev.store( nullptr, atomics::memory_order_release ); data.store( marked_data_ptr(), atomics::memory_order_release ); } node( value_type * pVal ) { next.store( nullptr, atomics::memory_order_release ); - prev.store( nullptr, atomics::memory_order_release ); data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); } }; - template + template class ValoisList{ public: typedef T value_type; ///< type of value stored in the list typedef Traits traits; ///< Traits template parameter +// typedef typename traits::hook hook; ///< hook type typedef valois_list::node< value_type > node_type; ///< node type typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; - typedef typename traits::disposer disposer; ///< disposer for \p value_type + typedef typename traits::disposer disposer; ///< disposer used +// typedef typename traits::stat stat; ///< Internal statistics +// typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits +// typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker typedef GC gc; ///< Garbage collector typedef typename traits::back_off back_off; ///< back-off strategy typedef typename traits::item_counter item_counter; ///< Item counting policy used typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option - typedef typename traits::node_allocator node_allocator; ///< Node allocator - typedef typename traits::stat stat; ///< Internal statistics +// typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer - static constexpr const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm + static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm protected: - node_type *head; - node_type *tail; - - typedef atomics::atomic< node_type* > atomic_node_ptr; ///< Atomic node pointer - typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support) - typedef typename node_type::marked_data_ptr marked_data_ptr; - +// typedef typename node_type::atomic_marked_ptr atomic_node_ptr; ///< Atomic node pointer +// typedef typename node_type::marked_ptr marked_node_ptr; ///< Node marked pointer +// +// atomic_node_ptr m_pHead; ///< Head pointer item_counter m_ItemCounter; ///< Item counter +// +// node_type *head; +// node_type *tail; - typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator; - - /// Position pointer for item search - struct position { - node_type const* pHead; - node_type * pPrev; ///< Previous node - node_type * pCur; ///< Current node +// typedef atomics::atomic< node_type* > atomic_node_ptr; ///< Atomic node pointer +// typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support) +// typedef typename node_type::marked_data_ptr marked_data_ptr; - value_type * pFound; ///< Value of \p pCur->data, valid only if data found - typename gc::Guard guard; ///< guard for \p pFound - }; +// typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator; - struct insert_position: public position - { - value_type * pPrevVal; ///< Value of \p pPrev->data, can be \p nullptr - typename gc::Guard prevGuard; ///< guard for \p pPrevVal - }; + /// Position pointer for item search +// struct position { +// node_type const* pHead; +// node_type * pPrev; ///< Previous node +// node_type * pCur; ///< Current node +// +// value_type * pFound; ///< Value of \p pCur->data, valid only if data found +// +// typename gc::Guard guard; ///< guard for \p pFound +// }; +// +// struct insert_position: public position +// { +// value_type * pPrevVal; ///< Value of \p pPrev->data, can be \p nullptr +// typename gc::Guard prevGuard; ///< guard for \p pPrevVal +// }; protected: class iterator @@ -158,72 +164,38 @@ namespace cds public: ValoisList(){ - head.next.store( &tail, memory_model::memory_order_relaxed ); - tail.next.store( NULL, memory_model::memory_order_release ); + init_list(); } + ~ValoisList(){ - node_type * consider_node = m_Head.next.load( memory_model::memory_order_relaxed ); - while ( consider_node != consider_node->next.load( memory_model::memory_order_relaxed )) { - value_type * pVal = consider_node->data.load( memory_model::memory_order_relaxed ).ptr(); - if ( pVal ) - retire_data( pVal ); - node_type * pNext = consider_node->next.load( memory_model::memory_order_relaxed ); - delete_node( consider_node ); - consider_node = pNext; - } + destroy(); } iterator begin(){ - return iterator(&head); + return iterator( &head ); } iterator end(){ - return iterator(&tail); + return iterator( &tail ); } - bool insert( node_type * consider_node ){ - - assert( consider_node != nullptr ); - assert( consider_node->data.load( memory_model::memory_order_relaxed ) != nullptr ); - - insert_position pos; - - pos.pHead = pHead; - node_type* pPrev = const_cast(pHead); - value_type* pPrevVal = pPrev->data.load( memory_model::memory_order_relaxed ).ptr(); + bool insert( value_type &val ){ - node_type * pCur = pPrev->next.load( memory_model::memory_order_relaxed ); - - - value_type * pVal = pos.guard.protect( pCur->data, - []( marked_data_ptr p ) -> value_type* - { - return p.ptr(); - } ).ptr(); - - - pPrev = pCur; - pPrevVal = pVal; - pos.prevGuard.copy( pos.guard ); - -// if ( connect_node(consider_node) ) { - ++m_ItemCounter; - return true; -// } + return true; } +//TODO: template Q - key + bool erase( ){ - bool update(){ return true; } - bool erase(node_type * consider_node){ - - assert( consider_node != nullptr ); - assert( consider_node->data.load( memory_model::memory_order_relaxed ) != nullptr ); - - return true; + bool empty(){ + return size() == 0; } + size_t size() const{ + return m_ItemCounter.value(); + } protected: @@ -237,7 +209,29 @@ namespace cds private: - node_type * alloc_node( value_type * pVal ){ + void init_list(){ + head.next.store( &tail, memory_model::memory_order_relaxed ); + tail.next.store( NULL, memory_model::memory_order_release ); + } + + void destroy(){ + typename gc::Guard guard; + marked_node_ptr head; + while ( true ) { + head = m_pHead.load(memory_model::memory_order_relaxed); + if ( head.ptr()) + guard.assign( node_traits::to_value_ptr( *head.ptr())); + if ( cds_likely( m_pHead.load(memory_model::memory_order_acquire) == head )) { + if ( head.ptr() == nullptr ) + break; + value_type& val = *node_traits::to_value_ptr( *head.ptr()); + unlink( val ); + } + } + } + + + node_type * alloc_node( value_type * pVal ){ return cxx_node_allocator().New( pVal ); } From 2a3e725faeab2944b9d6da8d755a21f78b36f5b6 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Fri, 5 Jan 2018 09:12:10 +0300 Subject: [PATCH 03/46] Implemented insert, erase, empty, iterator. --- cds/intrusive/details/valois_list_base.h | 104 +++++++ cds/intrusive/impl/valois_list.h | 361 +++++++++++------------ 2 files changed, 275 insertions(+), 190 deletions(-) create mode 100644 cds/intrusive/details/valois_list_base.h diff --git a/cds/intrusive/details/valois_list_base.h b/cds/intrusive/details/valois_list_base.h new file mode 100644 index 000000000..c5cb739b6 --- /dev/null +++ b/cds/intrusive/details/valois_list_base.h @@ -0,0 +1,104 @@ +/* + 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. +*/ + +#include +#include +#include +#include +#include +#include + +#ifndef CDSLIB_INTRUSIVE_DETAILS_VALOIS_LIST_BASE_H +#define CDSLIB_INTRUSIVE_DETAILS_VALOIS_LIST_BASE_H + +namespace cds { namespace intrusive { + + namespace valois_list{ + struct traits + { + /// Key comparison functor + /** + No default functor is provided. If the option is not specified, the \p less is used. + */ + typedef opt::none compare; + + /// Specifies binary predicate used for key compare. + /** + Default is \p std::less + */ + typedef opt::none less; + + /// Node allocator + typedef CDS_DEFAULT_ALLOCATOR node_allocator; + + /// Back-off strategy + typedef cds::backoff::Default back_off; + + /// Disposer for removing items + typedef opt::v::empty_disposer disposer; + + + /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter or \p atomicity::cache_friendly_item_counter to enable item counting + typedef atomicity::empty_item_counter item_counter; + + /// 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). + */ + typedef opt::v::relaxed_ordering memory_model; + }; + + template + struct node + { + typedef T value_type; ///< Value type + typedef cds::details::marked_ptr marked_data_ptr; ///< marked pointer to the value + + atomics::atomic< node* > next; ///< pointer to next node in the list + atomics::atomic< marked_data_ptr > data; ///< pointer to user data, \p nullptr if the node is free + + node() + { + next.store( nullptr, atomics::memory_order_release ); + data.store( marked_data_ptr(), atomics::memory_order_release ); + } + + node( value_type * pVal ) + { + next.store( nullptr, atomics::memory_order_release ); + data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); + } + + }; + } +}} + +#endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_VALOIS_LIST_BASE_H diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 943cb5005..8db6e1a9a 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -3,250 +3,231 @@ #ifndef CDS_VALOIS_LIST_H #define CDS_VALOIS_LIST_H -#include -#include -#include - -namespace cds -{ - namespace intrusive{ - namespace valois_list{ - - struct traits - { - /// Key comparison functor - /** - No default functor is provided. If the option is not specified, the \p less is used. - */ - typedef opt::none compare; - - /// Specifies binary predicate used for key compare. - /** - Default is \p std::less - */ - typedef opt::none less; - - /// Node allocator - typedef CDS_DEFAULT_ALLOCATOR node_allocator; - - /// Back-off strategy - typedef cds::backoff::Default back_off; - - /// Disposer for removing items - typedef opt::v::empty_disposer disposer; - - - /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter or \p atomicity::cache_friendly_item_counter to enable item counting - typedef atomicity::empty_item_counter item_counter; - - /// 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). - */ - typedef opt::v::relaxed_ordering memory_model; - }; +#include +#include - template - struct node - { - typedef T value_type; ///< Value type - typedef cds::details::marked_ptr marked_data_ptr; ///< marked pointer to the value +namespace cds { namespace intrusive { + namespace valois_list{ - atomics::atomic< node* > next; ///< pointer to next node in the list - atomics::atomic< node* > prev; ///< pointer to previous node in the list - atomics::atomic< marked_data_ptr > data; ///< pointer to user data, \p nullptr if the node is free + template + class ValoisList{ - node() - { - next.store( nullptr, atomics::memory_order_release ); - data.store( marked_data_ptr(), atomics::memory_order_release ); - } + public: + typedef GC gc; + typedef T value_type; ///< type of value stored in the list + typedef Traits traits; ///< Traits template parameter + typedef valois_list::node< value_type > node_type; ///< node type - node( value_type * pVal ) - { - next.store( nullptr, atomics::memory_order_release ); - data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); - } + typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; - }; + typedef typename traits::disposer disposer; ///< disposer for \p value_type - template - class ValoisList{ - public: + typedef GC gc; ///< Garbage collector + typedef typename traits::back_off back_off; ///< back-off strategy + typedef typename traits::item_counter item_counter; ///< Item counting policy used + typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option + typedef typename traits::node_allocator node_allocator; ///< Node allocator + typedef typename traits::stat stat; ///< Internal statistics - typedef T value_type; ///< type of value stored in the list - typedef Traits traits; ///< Traits template parameter + typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer -// typedef typename traits::hook hook; ///< hook type - typedef valois_list::node< value_type > node_type; ///< node type + static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm - typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; + protected: + typedef typename atomics::atomic< node_type* > atomic_node_ptr; + typedef typename node_type::marked_data_ptr marked_data_ptr; - typedef typename traits::disposer disposer; ///< disposer used -// typedef typename traits::stat stat; ///< Internal statistics -// typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits -// typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker + atomic_node_ptr m_pHead; ///< Head pointer + atomic_node_ptr m_pTail; ///< Tail pointer + item_counter m_ItemCounter; ///< Item counter - typedef GC gc; ///< Garbage collector - typedef typename traits::back_off back_off; ///< back-off strategy - typedef typename traits::item_counter item_counter; ///< Item counting policy used - typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option -// typedef typename traits::node_allocator node_allocator; ///< Node allocator + node_type * m_Head; + node_type * m_Tail; - typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer + protected: + class iterator { + friend class ValoisList; - static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm + public: + node_type *m_pNode; // Valois target - current real node + node_type *aux_pNode; // Valois pre_aux - aux node before the real node + node_type *cell_pNode; // Valois pre_cell - real node before the current real node + typename gc::Guard m_Guard; + + bool next() { + if (m_pNode->next == nullptr) { //if tail + return false; + } - protected: -// typedef typename node_type::atomic_marked_ptr atomic_node_ptr; ///< Atomic node pointer -// typedef typename node_type::marked_ptr marked_node_ptr; ///< Node marked pointer -// -// atomic_node_ptr m_pHead; ///< Head pointer - item_counter m_ItemCounter; ///< Item counter -// -// node_type *head; -// node_type *tail; + cell_pNode->next.store(&m_pNode, memory_model::memory_order_consume); + aux_pNode->next.store(m_pNode->next, memory_model::memory_order_relaxed); -// typedef atomics::atomic< node_type* > atomic_node_ptr; ///< Atomic node pointer -// typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support) -// typedef typename node_type::marked_data_ptr marked_data_ptr; + update_iterator(); + return true; + } + public: + typedef typename cds::details::make_const_type::pointer value_ptr; + typedef typename cds::details::make_const_type::reference value_ref; -// typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator; + iterator() + : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} - /// Position pointer for item search -// struct position { -// node_type const* pHead; -// node_type * pPrev; ///< Previous node -// node_type * pCur; ///< Current node -// -// value_type * pFound; ///< Value of \p pCur->data, valid only if data found -// -// typename gc::Guard guard; ///< guard for \p pFound -// }; -// -// struct insert_position: public position -// { -// value_type * pPrevVal; ///< Value of \p pPrev->data, can be \p nullptr -// typename gc::Guard prevGuard; ///< guard for \p pPrevVal -// }; - - protected: - class iterator - { - friend class ValoisList; - protected: - node_type * consider_node; - - iterator(node_type * consider_node){ - if (!m_Guard.protect(consider_node->data, []( marked_data_ptr p ) {return p.ptr(); }).ptr()) - next(); - } + //TODO: implement iterator( node_type ) - void next() - { - for ( node_type* p = consider_node->next.load( memory_model::memory_order_relaxed ); p != m_pNode; p = p->next.load( memory_model::memory_order_relaxed )) - { - m_pNode = p; - if ( m_Guard.protect( p->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr()) - return; - } - m_Guard.clear(); - } +// iterator( node_type & node ) +// :m_pNode( node ), aux_pNode( node.next ), cell_pNode( ){ +// } - value_type* data() const - { - return m_Guard.template get(); + void update_iterator(){ + if ( aux_pNode->next == target ){ + return; } + node_type * p = aux_pNode; + node_type * n = p->next; - }; + while( n != m_Tail && n->data == NULL ){ //while not last and is aux node + cell_pNode->next.compare_exchange_strong( p, n, memory_model::memory_order_release, atomics::memory_order_relaxed ); + p = n; + n = p->next.load( memory_order_consume ); + } - public: - ValoisList(){ - init_list(); + aux_pNode = p; + m_pNode = n; } - ~ValoisList(){ - destroy(); + value_ptr operator ->() const { + return m_Guard.template get(); } - iterator begin(){ - return iterator( &head ); + value_ref operator *() const { + assert( m_Guard.get_native() != nullptr ); + return * m_Guard.template get(); } - iterator end(){ - return iterator( &tail ); + iterator& operator ++(){ + iterator temp = *this; + next(); + return temp; } - bool insert( value_type &val ){ - - return true; + iterator& operator =( iterator & second ){ + m_pNode = second.m_pNode; + aux_pNode = second.aux_pNode; + cell_pNode = second.cell_pNode; + m_Guard.copy( second.m_Guard ); + return * this; } -//TODO: template Q - key - bool erase( ){ - return true; + bool operator ==( const iterator & second ) const { + return (m_pNode->data == second.m_pNode->data ); } - bool empty(){ - return size() == 0; + bool operator !=( const iterator & second ) const { + return (m_pNode->data != second.m_pNode->data ); } + }; - size_t size() const{ - return m_ItemCounter.value(); - } + public: + ValoisList(){ + init_list(); + } - protected: + ~ValoisList(){ + destroy(); + } - node_type* head(){ - return head; - } +// FIX: begin(), end() + iterator begin() const { + return iterator( &m_Head ); + } - node_type* tail(){ - return tail; - } +// iterator end(){ +// return iterator( &m_Tail ); +// } + + bool insert( iterator i, value_type & val ){ + i.update_iterator(); + + node_type * real_node = new node_type(val); + node_type * aux_node = new node_type(); - private: + real_node->next = aux_node; + aux_node->next = i.m_pNode; - void init_list(){ - head.next.store( &tail, memory_model::memory_order_relaxed ); - tail.next.store( NULL, memory_model::memory_order_release ); + bool insert_status = i.aux_pNode->next.compare_exchange_strong(i.m_pNode, real_node, memory_model::memory_order_release, memory_model::memory_order_relaxed ); + if( insert_status ){ + ++m_ItemCounter; } + return insert_status; + } - void destroy(){ - typename gc::Guard guard; - marked_node_ptr head; - while ( true ) { - head = m_pHead.load(memory_model::memory_order_relaxed); - if ( head.ptr()) - guard.assign( node_traits::to_value_ptr( *head.ptr())); - if ( cds_likely( m_pHead.load(memory_model::memory_order_acquire) == head )) { - if ( head.ptr() == nullptr ) - break; - value_type& val = *node_traits::to_value_ptr( *head.ptr()); - unlink( val ); + bool erase( iterator & i ){ + if( i.cell_pNode != nullptr ){ //if not Head + while( true ){ + i.update_iterator(); + if( delete_node( i ) ){ + return true; } + i.update_iterator(); } } + return false; + } +// TODO: implement contains( value_type ) +// bool contains( value_type & val ){ +// +// return true; +// } - node_type * alloc_node( value_type * pVal ){ - return cxx_node_allocator().New( pVal ); - } +// TODO: implement find() +// TODO: make functions overloading - void delete_node( node_type * consider_node ){ - cxx_node_allocator().Delete( consider_node ); + bool empty() const { + return size() == 0; + } + + size_t size() const { + return m_ItemCounter.value(); + } + + private: + + void init_list(){ + m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node + m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); + m_Tail->next.store( nullptr, memory_model::memory_order_release ); + } + + void destroy(){ + + node_type * pNode = m_Head.next.load( memory_model::memory_order_relaxed ); + + while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) { + value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr(); + if ( pVal ) + node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed ); + erase( pNode ); + pNode = pNext; } + } + + bool delete_node( iterator i ){ + + node_type * for_delete = i.m_pNode; + node_type * adjacent = i.m_pNode->next; - void retire_data( value_type * pVal ){ - assert( pVal != nullptr ); - gc::template retire( pVal ); + bool delete_status = i.aux_pNode->next.compare_exchange_strong( for_delete, adjacent, memory_order_relaxed, memory_order_release ); + + if ( delete_status ){ + --m_ItemCounter; } - }; - } + return delete_status; + } + }; } -} +}} #endif //CDS_VALOIS_LIST_H From a084900b8eec4eae6cf977f931ff4d0aff160c81 Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 6 Jan 2018 06:40:55 +0300 Subject: [PATCH 04/46] add small test --- cds/intrusive/valois_list_dhp.h | 11 ++++++ cds/intrusive/valois_list_hp.h | 13 +++++++ .../intrusive-list/intrusive_valois_hp.cpp | 34 +++++++++++++++++-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 cds/intrusive/valois_list_dhp.h create mode 100644 cds/intrusive/valois_list_hp.h diff --git a/cds/intrusive/valois_list_dhp.h b/cds/intrusive/valois_list_dhp.h new file mode 100644 index 000000000..57dc366dc --- /dev/null +++ b/cds/intrusive/valois_list_dhp.h @@ -0,0 +1,11 @@ +// +// Created by denis on 06.01.18. +// + +#ifndef CDSLIB_INTRUSIVE_VALOIS_LIST_DHP_H +#define CDSLIB_INTRUSIVE_VALOIS_LIST_DHP_H + +#include +#include + +#endif //CDSLIB_INTRUSIVE_VALOIS_LIST_DHP_H diff --git a/cds/intrusive/valois_list_hp.h b/cds/intrusive/valois_list_hp.h new file mode 100644 index 000000000..2e0d3642e --- /dev/null +++ b/cds/intrusive/valois_list_hp.h @@ -0,0 +1,13 @@ +// +// Created by denis on 06.01.18. +// + +#ifndef CDSLIB_INTRUSIVE_VALOIS_LIST_HP_H +#define CDSLIB_INTRUSIVE_VALOIS_LIST_HP_H + + + +#include +#include + +#endif //CDSLIB_INTRUSIVE_VALOIS_LIST_HP_H diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 67e2c42b2..d33b7b24c 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -28,12 +28,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "test_intrusive_iterable_list_hp.h" -#include +#include "test_intrusive_list_hp.h" +#include namespace { namespace ci = cds::intrusive; typedef cds::gc::HP gc_type; + class IntrusiveValoisList_HP : public cds_test::intrusive_list_hp + { + public: + typedef cds_test::intrusive_list_hp::base_item< ci::valois_list::node< gc_type>> base_item; + typedef cds_test::intrusive_list_hp::member_item< ci::valois_list::node< gc_type>> member_item; + + protected: + void SetUp() + { + /* + struct traits: public ci::michael_list::traits + { + typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; + }; + typedef ci::MichaelList< gc_type, base_item, traits > list_type; + + // +1 - for guarded_ptr + cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 1, 1, 16 ); + cds::threading::Manager::attachThread(); + */ + } + + void TearDown() + { + /* + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + */ + } + }; } // namespace From e56579c58a3a7ac7aaf6ec7958ec576de08624a3 Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 6 Jan 2018 07:12:55 +0300 Subject: [PATCH 05/46] fix small bug --- cds/intrusive/impl/valois_list.h | 303 +++++++++++++++---------------- 1 file changed, 151 insertions(+), 152 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 8db6e1a9a..c2ef6982f 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -7,173 +7,170 @@ #include namespace cds { namespace intrusive { - namespace valois_list{ - template - class ValoisList{ + template + class ValoisList{ - public: - typedef GC gc; - typedef T value_type; ///< type of value stored in the list - typedef Traits traits; ///< Traits template parameter - typedef valois_list::node< value_type > node_type; ///< node type - - typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; - - typedef typename traits::disposer disposer; ///< disposer for \p value_type + public: + typedef GC gc; ///< Garbage collector + typedef T value_type; ///< type of value stored in the list + typedef Traits traits; ///< Traits template parameter + typedef valois_list::node< value_type > node_type; ///< node type - typedef GC gc; ///< Garbage collector - typedef typename traits::back_off back_off; ///< back-off strategy - typedef typename traits::item_counter item_counter; ///< Item counting policy used - typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option - typedef typename traits::node_allocator node_allocator; ///< Node allocator - typedef typename traits::stat stat; ///< Internal statistics + typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; - typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer + typedef typename traits::disposer disposer; ///< disposer for \p value_type + typedef typename traits::back_off back_off; ///< back-off strategy + typedef typename traits::item_counter item_counter; ///< Item counting policy used + typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option + typedef typename traits::node_allocator node_allocator; ///< Node allocator + typedef typename traits::stat stat; ///< Internal statistics - static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm + typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer - protected: - typedef typename atomics::atomic< node_type* > atomic_node_ptr; - typedef typename node_type::marked_data_ptr marked_data_ptr; + static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm - atomic_node_ptr m_pHead; ///< Head pointer - atomic_node_ptr m_pTail; ///< Tail pointer - item_counter m_ItemCounter; ///< Item counter + protected: + typedef typename atomics::atomic< node_type* > atomic_node_ptr; + typedef typename node_type::marked_data_ptr marked_data_ptr; - node_type * m_Head; - node_type * m_Tail; + atomic_node_ptr m_pHead; ///< Head pointer + atomic_node_ptr m_pTail; ///< Tail pointer + item_counter m_ItemCounter; ///< Item counter - protected: - class iterator { - friend class ValoisList; + node_type * m_Head; + node_type * m_Tail; - public: - node_type *m_pNode; // Valois target - current real node - node_type *aux_pNode; // Valois pre_aux - aux node before the real node - node_type *cell_pNode; // Valois pre_cell - real node before the current real node - typename gc::Guard m_Guard; + protected: + class iterator { + friend class ValoisList; - bool next() { - if (m_pNode->next == nullptr) { //if tail - return false; - } + public: + node_type *m_pNode; // Valois target - current real node + node_type *aux_pNode; // Valois pre_aux - aux node before the real node + node_type *cell_pNode; // Valois pre_cell - real node before the current real node + typename gc::Guard m_Guard; + + bool next() { + if (m_pNode->next == nullptr) { //if tail + return false; + } - cell_pNode->next.store(&m_pNode, memory_model::memory_order_consume); - aux_pNode->next.store(m_pNode->next, memory_model::memory_order_relaxed); + cell_pNode->next.store(&m_pNode, memory_model::memory_order_consume); + aux_pNode->next.store(m_pNode->next, memory_model::memory_order_relaxed); - update_iterator(); - return true; - } + update_iterator(); + return true; + } - public: - typedef typename cds::details::make_const_type::pointer value_ptr; - typedef typename cds::details::make_const_type::reference value_ref; + public: + typedef typename cds::details::make_const_type::pointer value_ptr; + typedef typename cds::details::make_const_type::reference value_ref; - iterator() - : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} + iterator() + : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} - //TODO: implement iterator( node_type ) + //TODO: implement iterator( node_type ) // iterator( node_type & node ) // :m_pNode( node ), aux_pNode( node.next ), cell_pNode( ){ // } - void update_iterator(){ - if ( aux_pNode->next == target ){ - return; - } - node_type * p = aux_pNode; - node_type * n = p->next; - - while( n != m_Tail && n->data == NULL ){ //while not last and is aux node - cell_pNode->next.compare_exchange_strong( p, n, memory_model::memory_order_release, atomics::memory_order_relaxed ); - p = n; - n = p->next.load( memory_order_consume ); - } - - aux_pNode = p; - m_pNode = n; + void update_iterator(){ + if ( aux_pNode->next == m_pNode ){ + return; } + node_type * p = aux_pNode; + node_type * n = p->next; - value_ptr operator ->() const { - return m_Guard.template get(); + while( n != m_Tail && n->data == NULL ){ //while not last and is aux node + cell_pNode->next.compare_exchange_strong( p, n, memory_model::memory_order_release, atomics::memory_order_relaxed ); + p = n; + n = p->next.load( atomics::memory_order_consume ); } - value_ref operator *() const { - assert( m_Guard.get_native() != nullptr ); - return * m_Guard.template get(); - } + aux_pNode = p; + m_pNode = n; + } - iterator& operator ++(){ - iterator temp = *this; - next(); - return temp; - } + value_ptr operator ->() const { + return m_Guard.template get(); + } - iterator& operator =( iterator & second ){ - m_pNode = second.m_pNode; - aux_pNode = second.aux_pNode; - cell_pNode = second.cell_pNode; - m_Guard.copy( second.m_Guard ); - return * this; - } + value_ref operator *() const { + assert( m_Guard.get_native() != nullptr ); + return * m_Guard.template get(); + } - bool operator ==( const iterator & second ) const { - return (m_pNode->data == second.m_pNode->data ); - } + iterator& operator ++(){ + iterator temp = *this; + next(); + return temp; + } - bool operator !=( const iterator & second ) const { - return (m_pNode->data != second.m_pNode->data ); - } - }; + iterator& operator =( iterator & second ){ + m_pNode = second.m_pNode; + aux_pNode = second.aux_pNode; + cell_pNode = second.cell_pNode; + m_Guard.copy( second.m_Guard ); + return * this; + } - public: - ValoisList(){ - init_list(); + bool operator ==( const iterator & second ) const { + return (m_pNode->data == second.m_pNode->data ); } - ~ValoisList(){ - destroy(); + bool operator !=( const iterator & second ) const { + return (m_pNode->data != second.m_pNode->data ); } + }; + + public: + ValoisList(){ + init_list(); + } + + ~ValoisList(){ + destroy(); + } // FIX: begin(), end() - iterator begin() const { - return iterator( &m_Head ); - } + iterator begin() const { + return iterator( &m_Head ); + } // iterator end(){ // return iterator( &m_Tail ); // } - bool insert( iterator i, value_type & val ){ - i.update_iterator(); + bool insert( iterator i, value_type & val ){ + i.update_iterator(); - node_type * real_node = new node_type(val); - node_type * aux_node = new node_type(); + node_type * real_node = new node_type(val); + node_type * aux_node = new node_type(); - real_node->next = aux_node; - aux_node->next = i.m_pNode; + real_node->next = aux_node; + aux_node->next = i.m_pNode; - bool insert_status = i.aux_pNode->next.compare_exchange_strong(i.m_pNode, real_node, memory_model::memory_order_release, memory_model::memory_order_relaxed ); - if( insert_status ){ - ++m_ItemCounter; - } - return insert_status; + bool insert_status = i.aux_pNode->next.compare_exchange_strong(i.m_pNode, real_node, memory_model::memory_order_release, memory_model::memory_order_relaxed ); + if( insert_status ){ + ++m_ItemCounter; } - - bool erase( iterator & i ){ - if( i.cell_pNode != nullptr ){ //if not Head - while( true ){ - i.update_iterator(); - if( delete_node( i ) ){ - return true; - } - i.update_iterator(); + return insert_status; + } + + bool erase( iterator & i ){ + if( i.cell_pNode != nullptr ){ //if not Head + while( true ){ + i.update_iterator(); + if( delete_node( i ) ){ + return true; } + i.update_iterator(); } - return false; } + return false; + } // TODO: implement contains( value_type ) // bool contains( value_type & val ){ @@ -184,50 +181,52 @@ namespace cds { namespace intrusive { // TODO: implement find() // TODO: make functions overloading - bool empty() const { - return size() == 0; - } + bool empty() const { + return size() == 0; + } - size_t size() const { - return m_ItemCounter.value(); - } + size_t size() const { + return m_ItemCounter.value(); + } - private: + private: - void init_list(){ - m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node - m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); - m_Tail->next.store( nullptr, memory_model::memory_order_release ); - } + void init_list(){ + m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node + m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); + m_Tail->next.store( nullptr, memory_model::memory_order_release ); + } - void destroy(){ + void destroy(){ - node_type * pNode = m_Head.next.load( memory_model::memory_order_relaxed ); + node_type * pNode = m_Head.next.load( memory_model::memory_order_relaxed ); - while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) { - value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr(); - if ( pVal ) - node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed ); - erase( pNode ); - pNode = pNext; - } + while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) { + value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr(); + if ( pVal ) + node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed ); + erase( pNode ); + pNode = pNext; } + } - bool delete_node( iterator i ){ + bool delete_node( iterator i ){ - node_type * for_delete = i.m_pNode; - node_type * adjacent = i.m_pNode->next; + node_type * for_delete = i.m_pNode; + node_type * adjacent = i.m_pNode->next; - bool delete_status = i.aux_pNode->next.compare_exchange_strong( for_delete, adjacent, memory_order_relaxed, memory_order_release ); + bool delete_status = i.aux_pNode->next.compare_exchange_strong( for_delete, adjacent, + memory_model::memory_order_relaxed, + memory_model::memory_order_release ); - if ( delete_status ){ - --m_ItemCounter; - } - - return delete_status; + if ( delete_status ){ + --m_ItemCounter; } - }; - } + + return delete_status; + } + }; + }} #endif //CDS_VALOIS_LIST_H From 0edb6060b9b73f64d0eb97d91a69615bc7111806 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Sat, 6 Jan 2018 13:38:48 +0300 Subject: [PATCH 06/46] error fixes --- cds/intrusive/impl/valois_list.h | 50 +++++++++++++++++--------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index c2ef6982f..63a373a89 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -1,4 +1,4 @@ -// +//TODO: maybe add DOXYGEN docs #ifndef CDS_VALOIS_LIST_H #define CDS_VALOIS_LIST_H @@ -12,7 +12,7 @@ namespace cds { namespace intrusive { class ValoisList{ public: - typedef GC gc; ///< Garbage collector + typedef GC gc; ///< Garbage collector typedef T value_type; ///< type of value stored in the list typedef Traits traits; ///< Traits template parameter typedef valois_list::node< value_type > node_type; ///< node type @@ -42,6 +42,7 @@ namespace cds { namespace intrusive { node_type * m_Tail; protected: + //template class iterator { friend class ValoisList; @@ -64,17 +65,17 @@ namespace cds { namespace intrusive { } public: - typedef typename cds::details::make_const_type::pointer value_ptr; - typedef typename cds::details::make_const_type::reference value_ref; + typedef typename cds::details::make_const_type::pointer value_ptr; + typedef typename cds::details::make_const_type::reference value_ref; iterator() : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} //TODO: implement iterator( node_type ) -// iterator( node_type & node ) -// :m_pNode( node ), aux_pNode( node.next ), cell_pNode( ){ -// } + //iterator( node_type & node ) + // :m_pNode( node ), aux_pNode( node.next ), cell_pNode( ){ + //} void update_iterator(){ if ( aux_pNode->next == m_pNode ){ @@ -134,14 +135,14 @@ namespace cds { namespace intrusive { destroy(); } -// FIX: begin(), end() - iterator begin() const { - return iterator( &m_Head ); - } - -// iterator end(){ -// return iterator( &m_Tail ); -// } + //FIX: begin(), end() + //iterator begin() const { + // return iterator( &m_Head ); + //} + // + //iterator end(){ + // return iterator( &m_Tail ); + //} bool insert( iterator i, value_type & val ){ i.update_iterator(); @@ -172,14 +173,15 @@ namespace cds { namespace intrusive { return false; } -// TODO: implement contains( value_type ) -// bool contains( value_type & val ){ -// -// return true; -// } + //TODO: implement contains( value_type ) + // bool contains( value_type & val ){ + // + // return true; + // } -// TODO: implement find() -// TODO: make functions overloading + //TODO: implement find() + //TODO: after find() make list realy ordered + //TODO: make functions overloading bool empty() const { return size() == 0; @@ -192,7 +194,7 @@ namespace cds { namespace intrusive { private: void init_list(){ - m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node + m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); m_Tail->next.store( nullptr, memory_model::memory_order_release ); } @@ -204,8 +206,8 @@ namespace cds { namespace intrusive { while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) { value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr(); if ( pVal ) - node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed ); erase( pNode ); + node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed ); pNode = pNext; } } From 1b9695a16b05269242447c1a02ba3096716be76a Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Sat, 6 Jan 2018 15:45:42 +0300 Subject: [PATCH 07/46] Have implemented contains(), iterator begin() --- cds/intrusive/impl/valois_list.h | 82 ++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 63a373a89..b85709479 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -6,11 +6,15 @@ #include #include +//CRITICAL: cheak all functions use safe read/write +//CRITICAL: cheak nullptr/NULL values for aux, Head, Tail nodes + namespace cds { namespace intrusive { - template + template class ValoisList{ + friend class iterator; public: typedef GC gc; ///< Garbage collector typedef T value_type; ///< type of value stored in the list @@ -46,24 +50,29 @@ namespace cds { namespace intrusive { class iterator { friend class ValoisList; - public: - node_type *m_pNode; // Valois target - current real node - node_type *aux_pNode; // Valois pre_aux - aux node before the real node - node_type *cell_pNode; // Valois pre_cell - real node before the current real node + protected: + node_type *m_pNode; // Valois target - current real node + node_type *aux_pNode; // Valois pre_aux - aux node before the real node + node_type *cell_pNode; // Valois pre_cell - real node before the current real node typename gc::Guard m_Guard; bool next() { - if (m_pNode->next == nullptr) { //if tail + if ( m_pNode->next == nullptr ) { // if tail return false; } - cell_pNode->next.store(&m_pNode, memory_model::memory_order_consume); - aux_pNode->next.store(m_pNode->next, memory_model::memory_order_relaxed); - + cell_pNode->next.store( &m_pNode, memory_model::memory_order_consume ); + aux_pNode->next.store( m_pNode->next, memory_model::memory_order_consume ); update_iterator(); return true; } + iterator begin(){ + m_pNode->next.store( NULL, memory_model::memory_order_consume ); + aux_pNode->next.store( m_Head->next.load( memory_model::memory_order_seq_cst ), memory_model::memory_order_consume ); + cell_pNode->next.store( m_pHead.load( memory_model::memory_order_seq_cst ), memory_model::memory_order_comsume ); + } + public: typedef typename cds::details::make_const_type::pointer value_ptr; typedef typename cds::details::make_const_type::reference value_ref; @@ -71,18 +80,12 @@ namespace cds { namespace intrusive { iterator() : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} - //TODO: implement iterator( node_type ) - - //iterator( node_type & node ) - // :m_pNode( node ), aux_pNode( node.next ), cell_pNode( ){ - //} - void update_iterator(){ if ( aux_pNode->next == m_pNode ){ return; } node_type * p = aux_pNode; - node_type * n = p->next; + node_type * n = p->next.load( atomics::memory_order_consume ); while( n != m_Tail && n->data == NULL ){ //while not last and is aux node cell_pNode->next.compare_exchange_strong( p, n, memory_model::memory_order_release, atomics::memory_order_relaxed ); @@ -135,14 +138,11 @@ namespace cds { namespace intrusive { destroy(); } - //FIX: begin(), end() - //iterator begin() const { - // return iterator( &m_Head ); - //} - // - //iterator end(){ - // return iterator( &m_Tail ); - //} + iterator begin(){ + return iterator().begin(); + } + + //TODO: implement insert( value_type & val ), which will make sorted insert bool insert( iterator i, value_type & val ){ i.update_iterator(); @@ -161,7 +161,7 @@ namespace cds { namespace intrusive { } bool erase( iterator & i ){ - if( i.cell_pNode != nullptr ){ //if not Head + if( i.cell_pNode != nullptr ){ // if not Head while( true ){ i.update_iterator(); if( delete_node( i ) ){ @@ -173,15 +173,27 @@ namespace cds { namespace intrusive { return false; } - //TODO: implement contains( value_type ) - // bool contains( value_type & val ){ - // - // return true; - // } + bool contains( value_type & val ){ + return find( iterator().begin(), val ); + } + + bool find( iterator * i, value_type & val ) { + while ( i->m_pNode != nullptr ){ + //FIX: safe read + if ( i->m_pNode.data == val ){ + return true; + } + else if ( i->m_pNode.data > val ){ + return false; + } + else{ + i->next(); + } + } + return false; + } - //TODO: implement find() - //TODO: after find() make list realy ordered - //TODO: make functions overloading + //TODO: implement get_iterator( val ) bool empty() const { return size() == 0; @@ -195,8 +207,8 @@ namespace cds { namespace intrusive { void init_list(){ m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node - m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); - m_Tail->next.store( nullptr, memory_model::memory_order_release ); + m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); //link aux node to tail + m_Tail->next.store( nullptr, memory_model::memory_order_release ); //link tail to nullptr } void destroy(){ From 9fc144a9261cec1262d8d25d0115ecdef1c28b8f Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 8 Jan 2018 01:47:22 +0300 Subject: [PATCH 08/46] Add stat in base file --- cds/intrusive/details/valois_list_base.h | 154 +++++++++++++++--- .../intrusive-list/intrusive_valois_hp.cpp | 33 +++- 2 files changed, 157 insertions(+), 30 deletions(-) diff --git a/cds/intrusive/details/valois_list_base.h b/cds/intrusive/details/valois_list_base.h index c5cb739b6..c342f0a87 100644 --- a/cds/intrusive/details/valois_list_base.h +++ b/cds/intrusive/details/valois_list_base.h @@ -41,6 +41,123 @@ namespace cds { namespace intrusive { namespace valois_list{ + + template + struct node + { + typedef T value_type; ///< Value type + typedef cds::details::marked_ptr marked_data_ptr; ///< marked pointer to the value + + atomics::atomic< node* > next; ///< pointer to next node in the list + atomics::atomic< marked_data_ptr > data; ///< pointer to user data, \p nullptr if the node is free + + node() + { + next.store( nullptr, atomics::memory_order_release ); + data.store( marked_data_ptr(), atomics::memory_order_release ); + } + + node( value_type * pVal ) + { + next.store( nullptr, atomics::memory_order_release ); + data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); + } + + }; + + + template + struct stat { + typedef EventCounter event_counter; ///< Event counter type + + event_counter m_nInsertSuccess; ///< Number of success \p insert() operations + event_counter m_nInsertFailed; ///< Number of failed \p insert() operations + event_counter m_nInsertRetry; ///< Number of attempts to insert new item + event_counter m_nUpdateNew; ///< Number of new item inserted for \p update() + event_counter m_nUpdateExisting; ///< Number of existing item updates + event_counter m_nUpdateFailed; ///< Number of failed \p update() call + event_counter m_nUpdateRetry; ///< Number of attempts to \p update() the item + event_counter m_nUpdateMarked; ///< Number of attempts to \p update() logically deleted (marked) items + event_counter m_nEraseSuccess; ///< Number of successful \p erase(), \p unlink(), \p extract() operations + event_counter m_nEraseFailed; ///< Number of failed \p erase(), \p unlink(), \p extract() operations + event_counter m_nEraseRetry; ///< Number of attempts to \p erase() an item + event_counter m_nFindSuccess; ///< Number of successful \p find() and \p get() operations + event_counter m_nFindFailed; ///< Number of failed \p find() and \p get() operations + + event_counter m_nHelpingSuccess; ///< Number of successful help attempts to remove marked item during searching + event_counter m_nHelpingFailed; ///< Number if failed help attempts to remove marked item during searching + + //@cond + void onInsertSuccess() { ++m_nInsertSuccess; } + void onInsertFailed() { ++m_nInsertFailed; } + void onInsertRetry() { ++m_nInsertRetry; } + void onUpdateNew() { ++m_nUpdateNew; } + void onUpdateExisting() { ++m_nUpdateExisting; } + void onUpdateFailed() { ++m_nUpdateFailed; } + void onUpdateRetry() { ++m_nUpdateRetry; } + void onUpdateMarked() { ++m_nUpdateMarked; } + void onEraseSuccess() { ++m_nEraseSuccess; } + void onEraseFailed() { ++m_nEraseFailed; } + void onEraseRetry() { ++m_nEraseRetry; } + void onFindSuccess() { ++m_nFindSuccess; } + void onFindFailed() { ++m_nFindFailed; } + + void onHelpingSuccess() { ++m_nHelpingSuccess; } + void onHelpingFailed() { ++m_nHelpingFailed; } + //@endcond + }; + + /// \p MichaelList empty internal statistics + struct empty_stat { + //@cond + void onInsertSuccess() const {} + void onInsertFailed() const {} + void onInsertRetry() const {} + void onUpdateNew() const {} + void onUpdateExisting() const {} + void onUpdateFailed() const {} + void onUpdateRetry() const {} + void onUpdateMarked() const {} + void onEraseSuccess() const {} + void onEraseFailed() const {} + void onEraseRetry() const {} + void onFindSuccess() const {} + void onFindFailed() const {} + + void onHelpingSuccess() const {} + void onHelpingFailed() const {} + //@endcond + }; + + //@cond + template > + struct wrapped_stat { + typedef Stat stat_type; + + wrapped_stat( stat_type& st ) + : m_stat( st ) + {} + + void onInsertSuccess() { m_stat.onInsertSuccess(); } + void onInsertFailed() { m_stat.onInsertFailed(); } + void onInsertRetry() { m_stat.onInsertRetry(); } + void onUpdateNew() { m_stat.onUpdateNew(); } + void onUpdateExisting() { m_stat.onUpdateExisting(); } + void onUpdateFailed() { m_stat.onUpdateFailed(); } + void onUpdateRetry() { m_stat.onUpdateRetry(); } + void onUpdateMarked() { m_stat.onUpdateMarked(); } + void onEraseSuccess() { m_stat.onEraseSuccess(); } + void onEraseFailed() { m_stat.onEraseFailed(); } + void onEraseRetry() { m_stat.onEraseRetry(); } + void onFindSuccess() { m_stat.onFindSuccess(); } + void onFindFailed() { m_stat.onFindFailed(); } + + void onHelpingSuccess() { m_stat.onHelpingSuccess(); } + void onHelpingFailed() { m_stat.onHelpingFailed(); } + + stat_type& m_stat; + }; + struct traits { /// Key comparison functor @@ -64,6 +181,11 @@ namespace cds { namespace intrusive { /// Disposer for removing items typedef opt::v::empty_disposer disposer; + /// Internal statistics + /** + It's disabled + */ + typedef empty_stat stat; /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter or \p atomicity::cache_friendly_item_counter to enable item counting typedef atomicity::empty_item_counter item_counter; @@ -76,28 +198,18 @@ namespace cds { namespace intrusive { typedef opt::v::relaxed_ordering memory_model; }; - template - struct node - { - typedef T value_type; ///< Value type - typedef cds::details::marked_ptr marked_data_ptr; ///< marked pointer to the value - - atomics::atomic< node* > next; ///< pointer to next node in the list - atomics::atomic< marked_data_ptr > data; ///< pointer to user data, \p nullptr if the node is free - - node() - { - next.store( nullptr, atomics::memory_order_release ); - data.store( marked_data_ptr(), atomics::memory_order_release ); - } - - node( value_type * pVal ) - { - next.store( nullptr, atomics::memory_order_release ); - data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); - } - + template + struct make_traits { +# ifdef CDS_DOXYGEN_INVOKED + typedef implementation_defined type ; ///< Metafunction result +# else + typedef typename cds::opt::make_options< + typename cds::opt::find_type_traits< traits, Options... >::type + ,Options... + >::type type; +# endif }; + } }} diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index d33b7b24c..00fa70cd4 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -44,26 +44,41 @@ namespace { protected: void SetUp() { - /* - struct traits: public ci::michael_list::traits - { - typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook; - }; - typedef ci::MichaelList< gc_type, base_item, traits > list_type; + struct traits: public ci::valois_list::traits{}; + + typedef ci::ValoisList< gc_type, base_item, traits > list_type; // +1 - for guarded_ptr cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 1, 1, 16 ); + cds::threading::Manager::attachThread(); - */ + } void TearDown() { - /* + cds::threading::Manager::detachThread(); cds::gc::hp::GarbageCollector::Destruct( true ); - */ } }; + TEST_F( IntrusiveValoisList_HP, base_hook ) + { + /* + typedef ci::ValoisList< gc_type, base_item, + typename ci::valois_list::make_traits< + ci::opt::hook< ci::valois_list::base_hook< cds::opt::gc< gc_type >>> + ,ci::opt::disposer< mock_disposer > + ,cds::opt::less< less< base_item >> + >::type + > list_type; +/* + list_type l; + test_common( l ); + test_ordered_iterator( l ); + test_hp( l ); +*/ + } + } // namespace From 86aabaddfe4d1264073bf349a8808d38e6d64dd3 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 8 Jan 2018 05:11:48 +0300 Subject: [PATCH 09/46] add methods with comments --- cds/intrusive/details/valois_list_base.h | 4 +- cds/intrusive/impl/valois_list.h | 450 ++++++++++++++--------- 2 files changed, 285 insertions(+), 169 deletions(-) diff --git a/cds/intrusive/details/valois_list_base.h b/cds/intrusive/details/valois_list_base.h index c342f0a87..00011b6fe 100644 --- a/cds/intrusive/details/valois_list_base.h +++ b/cds/intrusive/details/valois_list_base.h @@ -53,13 +53,13 @@ namespace cds { namespace intrusive { node() { - next.store( nullptr, atomics::memory_order_release ); + next.store( nullptr, atomics::memory_order_relaxed ); data.store( marked_data_ptr(), atomics::memory_order_release ); } node( value_type * pVal ) { - next.store( nullptr, atomics::memory_order_release ); + next.store( nullptr, atomics::memory_order_relaxed ); data.store( marked_data_ptr( pVal ), atomics::memory_order_release ); } diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index b85709479..87ce544a7 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -9,238 +9,354 @@ //CRITICAL: cheak all functions use safe read/write //CRITICAL: cheak nullptr/NULL values for aux, Head, Tail nodes -namespace cds { namespace intrusive { +namespace cds { + namespace intrusive { template - class ValoisList{ + class ValoisList { - friend class iterator; - public: - typedef GC gc; ///< Garbage collector - typedef T value_type; ///< type of value stored in the list - typedef Traits traits; ///< Traits template parameter - typedef valois_list::node< value_type > node_type; ///< node type + friend class iterator; - typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator; + public: + typedef GC gc; ///< Garbage collector + typedef T value_type; ///< type of value stored in the list + typedef Traits traits; ///< Traits template parameter + typedef valois_list::node node_type; ///< node type - typedef typename traits::disposer disposer; ///< disposer for \p value_type - typedef typename traits::back_off back_off; ///< back-off strategy - typedef typename traits::item_counter item_counter; ///< Item counting policy used - typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option - typedef typename traits::node_allocator node_allocator; ///< Node allocator - typedef typename traits::stat stat; ///< Internal statistics + typedef typename opt::details::make_comparator::type key_comparator; - typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer + typedef typename traits::disposer disposer; ///< disposer for \p value_type + typedef typename traits::back_off back_off; ///< back-off strategy + typedef typename traits::item_counter item_counter; ///< Item counting policy used + typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option + typedef typename traits::node_allocator node_allocator; ///< Node allocator + typedef typename traits::stat stat; ///< Internal statistics - static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm + typedef typename gc::template guarded_ptr guarded_ptr; ///< Guarded pointer - protected: - typedef typename atomics::atomic< node_type* > atomic_node_ptr; - typedef typename node_type::marked_data_ptr marked_data_ptr; + static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm - atomic_node_ptr m_pHead; ///< Head pointer - atomic_node_ptr m_pTail; ///< Tail pointer - item_counter m_ItemCounter; ///< Item counter + protected: + typedef typename atomics::atomic atomic_node_ptr; + typedef typename node_type::marked_data_ptr marked_data_ptr; - node_type * m_Head; - node_type * m_Tail; + atomic_node_ptr m_pHead; ///< Head pointer + atomic_node_ptr m_pTail; ///< Tail pointer + item_counter m_ItemCounter; ///< Item counter - protected: - //template - class iterator { - friend class ValoisList; + node_type *m_Head; + node_type *m_Tail; protected: - node_type *m_pNode; // Valois target - current real node - node_type *aux_pNode; // Valois pre_aux - aux node before the real node - node_type *cell_pNode; // Valois pre_cell - real node before the current real node - typename gc::Guard m_Guard; + //template + class iterator { + friend class ValoisList; + + protected: + node_type *m_pNode; // Valois target - current real node + node_type *aux_pNode; // Valois pre_aux - aux node before the real node + node_type *cell_pNode; // Valois pre_cell - real node before the current real node + typename gc::Guard m_Guard; + + bool next() { + if (m_pNode->next == nullptr) { // if tail + return false; + } - bool next() { - if ( m_pNode->next == nullptr ) { // if tail - return false; + cell_pNode->next.store(&m_pNode, memory_model::memory_order_consume); + aux_pNode->next.store(m_pNode->next, memory_model::memory_order_consume); + update_iterator(); + return true; } - cell_pNode->next.store( &m_pNode, memory_model::memory_order_consume ); - aux_pNode->next.store( m_pNode->next, memory_model::memory_order_consume ); - update_iterator(); - return true; - } + iterator begin() { + m_pNode->next.store(NULL, memory_model::memory_order_consume); + aux_pNode->next.store( + m_Head->next.load(memory_model::memory_order_seq_cst), + memory_model::memory_order_consume + ); + cell_pNode->next.store( + m_pHead.load(memory_model::memory_order_seq_cst), + memory_model::memory_order_comsume + ); + return this; + } - iterator begin(){ - m_pNode->next.store( NULL, memory_model::memory_order_consume ); - aux_pNode->next.store( m_Head->next.load( memory_model::memory_order_seq_cst ), memory_model::memory_order_consume ); - cell_pNode->next.store( m_pHead.load( memory_model::memory_order_seq_cst ), memory_model::memory_order_comsume ); - } + public: + typedef typename cds::details::make_const_type::pointer value_ptr; + typedef typename cds::details::make_const_type::reference value_ref; - public: - typedef typename cds::details::make_const_type::pointer value_ptr; - typedef typename cds::details::make_const_type::reference value_ref; + iterator() + : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} - iterator() - : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} + void update_iterator() { + if (aux_pNode->next == m_pNode) { + return; + } + node_type *p = aux_pNode; + node_type *n = p->next.load(atomics::memory_order_consume); + + while (n != m_Tail && n->data == NULL) { //while not last and is aux node + cell_pNode->next.compare_exchange_strong( + p, + n, + memory_model::memory_order_release, + atomics::memory_order_relaxed + ); + p = n; + n = p->next.load(atomics::memory_order_consume); + } - void update_iterator(){ - if ( aux_pNode->next == m_pNode ){ - return; + aux_pNode = p; + m_pNode = n; } - node_type * p = aux_pNode; - node_type * n = p->next.load( atomics::memory_order_consume ); - while( n != m_Tail && n->data == NULL ){ //while not last and is aux node - cell_pNode->next.compare_exchange_strong( p, n, memory_model::memory_order_release, atomics::memory_order_relaxed ); - p = n; - n = p->next.load( atomics::memory_order_consume ); + value_ptr operator->() const { + return m_Guard.template get(); } - aux_pNode = p; - m_pNode = n; - } + value_ref operator*() const { + assert(m_Guard.get_native() != nullptr); + return *m_Guard.template get(); + } - value_ptr operator ->() const { - return m_Guard.template get(); - } + iterator &operator++() { + iterator temp = *this; + next(); + return temp; + } - value_ref operator *() const { - assert( m_Guard.get_native() != nullptr ); - return * m_Guard.template get(); - } + iterator &operator=(iterator &second) { + m_pNode = second.m_pNode; + aux_pNode = second.aux_pNode; + cell_pNode = second.cell_pNode; + m_Guard.copy(second.m_Guard); + return *this; + } - iterator& operator ++(){ - iterator temp = *this; - next(); - return temp; - } + bool operator==(const iterator &second) const { + return (m_pNode->data == second.m_pNode->data); + } + + bool operator!=(const iterator &second) const { + return (m_pNode->data != second.m_pNode->data); + } + }; - iterator& operator =( iterator & second ){ - m_pNode = second.m_pNode; - aux_pNode = second.aux_pNode; - cell_pNode = second.cell_pNode; - m_Guard.copy( second.m_Guard ); - return * this; + public: + ValoisList() { + init_list(); } - bool operator ==( const iterator & second ) const { - return (m_pNode->data == second.m_pNode->data ); + ~ValoisList() { + destroy(); } - bool operator !=( const iterator & second ) const { - return (m_pNode->data != second.m_pNode->data ); + iterator begin() { + return iterator().begin(); } - }; - public: - ValoisList(){ - init_list(); - } + bool insert(value_type val) { + //TODO fix bug with interrupting the method. + while (true) { + auto iter = begin(); + while (true) { + auto current_data = iter->m_pNode.data; + auto next_data = iter->m_pNode->next.data; + if (current_data == val) { + return true; + } + if (current_data < val && next_data > val) { + if (insert(iter, val)) { + return true; + } else { + break; + } + } + iter++; + } - ~ValoisList(){ - destroy(); - } + } + return false; + } - iterator begin(){ - return iterator().begin(); - } + /** + * try insert in the position + * @param i + * @param val + * @return + */ + + bool insert(iterator i, value_type &val) { + i.update_iterator(); + + node_type *real_node = new node_type(val); + node_type *aux_node = new node_type(); + + real_node->next = aux_node; + aux_node->next = i.m_pNode; + + bool insert_status = i.aux_pNode->next.compare_exchange_strong( + i.m_pNode, + real_node, + memory_model::memory_order_release, + memory_model::memory_order_relaxed + ); + if (insert_status) { + ++m_ItemCounter; + } + return insert_status; + } - //TODO: implement insert( value_type & val ), which will make sorted insert + /** + * + * It's true delete algorithm + * @param i + * @return + */ + + bool erase(iterator &i) { + if (i.cell_pNode != nullptr) { // if not Head + while (true) { + i.update_iterator(); + if (delete_node(i)) { + return true; + } + i.update_iterator(); + } + } + return false; + } - bool insert( iterator i, value_type & val ){ - i.update_iterator(); + /** + * delete value from linked list; + * @param value + * @return + */ + + bool erase(value_type &value) { + while (true) { + auto iter = begin(); + //skip if element not exists + if (!find(iter, value))return true; + if (erase(iter)) return true; + // commented for start from begin position + //iter.update_iterator(); + } + } - node_type * real_node = new node_type(val); - node_type * aux_node = new node_type(); - real_node->next = aux_node; - aux_node->next = i.m_pNode; + /** + * return value by integer index + * for testing only + * @param index + * @return + */ + value_type get(int index) { + auto iter = begin(); + int current_index = 0; + while (iter.next()) { + current_index++; + if (current_index == index) { + return iter->m_pNode.data; + } else if (current_index > index) { + break; + } + return NULL; + } + } - bool insert_status = i.aux_pNode->next.compare_exchange_strong(i.m_pNode, real_node, memory_model::memory_order_release, memory_model::memory_order_relaxed ); - if( insert_status ){ - ++m_ItemCounter; + bool contains(value_type &val) { + return find(iterator().begin(), val); } - return insert_status; - } - bool erase( iterator & i ){ - if( i.cell_pNode != nullptr ){ // if not Head - while( true ){ - i.update_iterator(); - if( delete_node( i ) ){ + bool find(iterator *i, value_type &val) { + while (i->m_pNode != nullptr) { + //FIX: safe read + if (i->m_pNode.data == val) { return true; + } else if (i->m_pNode.data > val) { + return false; + } else { + i->next(); } - i.update_iterator(); } + return false; } - return false; - } - bool contains( value_type & val ){ - return find( iterator().begin(), val ); - } + bool find(value_type val) { + return contains(val); + } - bool find( iterator * i, value_type & val ) { - while ( i->m_pNode != nullptr ){ - //FIX: safe read - if ( i->m_pNode.data == val ){ - return true; - } - else if ( i->m_pNode.data > val ){ - return false; - } - else{ - i->next(); + + //TODO: implement get_iterator( value_type & val ) + iterator interator(value_type &val) { + auto iter = begin(); + if (find(iter, val)) { + return iter; + } else { + return NULL; } } - return false; - } - //TODO: implement get_iterator( val ) - bool empty() const { - return size() == 0; - } + iterator interator() { + return begin(); + } - size_t size() const { - return m_ItemCounter.value(); - } + bool empty() const { + auto iter = this->begin(); + int size = 0; + if (iter->next()) { + // if next is not exist() container is empty() + return false; + } else { + return true; + } + } - private: + size_t size() const { + return m_ItemCounter.value(); + } + private: - void init_list(){ - m_Head->next.store( new node_type(), memory_model::memory_order_relaxed ); //link to aux node - m_Head->next->next.store( &m_Tail, memory_model::memory_order_relaxed ); //link aux node to tail - m_Tail->next.store( nullptr, memory_model::memory_order_release ); //link tail to nullptr - } + void init_list() { + m_Head->next.store(new node_type(), memory_model::memory_order_relaxed); //link to aux node + m_Head->next->next.store(&m_Tail, memory_model::memory_order_relaxed); //link aux node to tail + m_Tail->next.store(nullptr, memory_model::memory_order_release); //link tail to nullptr + } - void destroy(){ + void destroy() { - node_type * pNode = m_Head.next.load( memory_model::memory_order_relaxed ); + node_type *pNode = m_Head.next.load(memory_model::memory_order_relaxed); - while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) { - value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr(); - if ( pVal ) - erase( pNode ); - node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed ); - pNode = pNext; + while (pNode != pNode->next.load(memory_model::memory_order_relaxed)) { + value_type *pVal = pNode->data.load(memory_model::memory_order_relaxed).ptr(); + if (pVal) + erase(pNode); + node_type *pNext = pNode->next.load(memory_model::memory_order_relaxed); + pNode = pNext; + } } - } - bool delete_node( iterator i ){ + bool delete_node(iterator i) { - node_type * for_delete = i.m_pNode; - node_type * adjacent = i.m_pNode->next; + node_type *for_delete = i.m_pNode; + node_type *adjacent = i.m_pNode->next; - bool delete_status = i.aux_pNode->next.compare_exchange_strong( for_delete, adjacent, - memory_model::memory_order_relaxed, - memory_model::memory_order_release ); + bool delete_status = i.aux_pNode->next.compare_exchange_strong(for_delete, adjacent, + memory_model::memory_order_relaxed, + memory_model::memory_order_release); - if ( delete_status ){ - --m_ItemCounter; - } + if (delete_status) { + --m_ItemCounter; + } - return delete_status; - } - }; + return delete_status; + } + }; -}} + } +} #endif //CDS_VALOIS_LIST_H From 84f361f69e3a4c17455f06d933700f0b0cb427c5 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 8 Jan 2018 06:12:38 +0300 Subject: [PATCH 10/46] add some unit test --- .../intrusive-list/intrusive_valois_hp.cpp | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 00fa70cd4..18d44a4d5 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -63,22 +63,57 @@ namespace { } }; + /** + * + * @tparam List + * @param list + */ + template + void test_list(List& list) + { + /** + * 1) testing method is empty + * 2) test adding 10 element in the container + * 3) test comtainig 10 element on the container + * 4) test deleting element in the containing + */ + + // test empty method(); + ASSERT_TRUE( list.empty()); + + static const size_t nSize = 20; + typedef typename List::value_type value_type; + int size = 10; + + // insert and contains method + for ( size_t i = 0; i < nSize; i++ ) { + + ASSERT_FALSE(list.find(i)); + list.insert(i); + ASSERT_TRUE( list.find(i)); + ASSERT_FALSE( list.empty()); + } + + // delete and contains method + for(size_t i = nSize; i > 0; i--){ + ASSERT_TRUE( list.find(i)); + list.insert(i); + ASSERT_FALSE(list.find(i)); + } + // test empty method(); + ASSERT_TRUE( list.empty()); + + } + + TEST_F( IntrusiveValoisList_HP, base_hook ) { - /* - typedef ci::ValoisList< gc_type, base_item, - typename ci::valois_list::make_traits< - ci::opt::hook< ci::valois_list::base_hook< cds::opt::gc< gc_type >>> - ,ci::opt::disposer< mock_disposer > - ,cds::opt::less< less< base_item >> - >::type - > list_type; -/* + struct traits: public ci::valois_list::traits{}; + + typedef ci::ValoisList< gc_type, base_item, traits > list_type; list_type l; - test_common( l ); - test_ordered_iterator( l ); - test_hp( l ); -*/ + test_list(l); + } } // namespace From ff0e3875745ce56aa7d8ff879cee5951cccc028c Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Mon, 8 Jan 2018 12:08:59 +0300 Subject: [PATCH 11/46] Fixed compare --- cds/intrusive/impl/valois_list.h | 123 +++++++++++++------------------ 1 file changed, 53 insertions(+), 70 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 87ce544a7..299dd16a8 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -42,7 +42,7 @@ namespace cds { atomic_node_ptr m_pHead; ///< Head pointer atomic_node_ptr m_pTail; ///< Tail pointer - item_counter m_ItemCounter; ///< Item counter + item_counter m_ItemCounter; ///< Item counter node_type *m_Head; node_type *m_Tail; @@ -63,40 +63,43 @@ namespace cds { return false; } - cell_pNode->next.store(&m_pNode, memory_model::memory_order_consume); - aux_pNode->next.store(m_pNode->next, memory_model::memory_order_consume); + cell_pNode->next.store( m_pNode, memory_model::memory_order_consume); + aux_pNode->next.store( m_pNode->next, memory_model::memory_order_consume); update_iterator(); return true; } - iterator begin() { + public: + typedef typename cds::details::make_const_type::pointer value_ptr; + typedef typename cds::details::make_const_type::reference value_ref; + + iterator() + : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} + + iterator( node_type * node) { m_pNode->next.store(NULL, memory_model::memory_order_consume); + aux_pNode->next.store( - m_Head->next.load(memory_model::memory_order_seq_cst), + node->next.load(memory_model::memory_order_seq_cst), memory_model::memory_order_consume ); + cell_pNode->next.store( - m_pHead.load(memory_model::memory_order_seq_cst), - memory_model::memory_order_comsume + node, + memory_model::memory_order_consume ); - return this; - } - public: - typedef typename cds::details::make_const_type::pointer value_ptr; - typedef typename cds::details::make_const_type::reference value_ref; - - iterator() - : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} + update_iterator(); + } void update_iterator() { if (aux_pNode->next == m_pNode) { return; } node_type *p = aux_pNode; - node_type *n = p->next.load(atomics::memory_order_consume); + node_type *n = p->next.load(atomics::memory_order_release); - while (n != m_Tail && n->data == NULL) { //while not last and is aux node + while ( n->next != nullptr && n->data == NULL) { //while not last and is aux node cell_pNode->next.compare_exchange_strong( p, n, @@ -111,15 +114,6 @@ namespace cds { m_pNode = n; } - value_ptr operator->() const { - return m_Guard.template get(); - } - - value_ref operator*() const { - assert(m_Guard.get_native() != nullptr); - return *m_Guard.template get(); - } - iterator &operator++() { iterator temp = *this; next(); @@ -153,7 +147,7 @@ namespace cds { } iterator begin() { - return iterator().begin(); + return iterator(m_Head); } bool insert(value_type val) { @@ -266,18 +260,20 @@ namespace cds { } } - bool contains(value_type &val) { - return find(iterator().begin(), val); - } - - bool find(iterator *i, value_type &val) { + template + bool find( node_type * start_node, Q const& val, Compare cmp) const { + iterator * i = new iterator( start_node ); while (i->m_pNode != nullptr) { - //FIX: safe read - if (i->m_pNode.data == val) { + value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_relaxed).ptr(); + int const nCmp = cmp( *nVal, val ); + + if ( nCmp == 0 ){ return true; - } else if (i->m_pNode.data > val) { + } + else if ( nCmp > 0 ){ return false; - } else { + } + else{ i->next(); } } @@ -285,28 +281,13 @@ namespace cds { } bool find(value_type val) { - return contains(val); + return find( m_Head, val, key_comparator()); } - //TODO: implement get_iterator( value_type & val ) - iterator interator(value_type &val) { - auto iter = begin(); - if (find(iter, val)) { - return iter; - } else { - return NULL; - } - } - - - iterator interator() { - return begin(); - } - bool empty() const { - auto iter = this->begin(); - int size = 0; + bool empty() { + iterator * iter = new iterator(m_Head); if (iter->next()) { // if next is not exist() container is empty() return false; @@ -315,28 +296,30 @@ namespace cds { } } - size_t size() const { - return m_ItemCounter.value(); - } private: void init_list() { - m_Head->next.store(new node_type(), memory_model::memory_order_relaxed); //link to aux node - m_Head->next->next.store(&m_Tail, memory_model::memory_order_relaxed); //link aux node to tail - m_Tail->next.store(nullptr, memory_model::memory_order_release); //link tail to nullptr + node_type * aux_temp = new node_type(); + m_Head = new node_type(); + m_Tail = new node_type(); + m_Head->next.store( aux_temp, memory_model::memory_order_relaxed); //link to aux node + aux_temp->next.store( m_Tail, memory_model::memory_order_relaxed ); + m_Tail->next.store(nullptr, memory_model::memory_order_relaxed ); //link tail to nullptr } void destroy() { - - node_type *pNode = m_Head.next.load(memory_model::memory_order_relaxed); - - while (pNode != pNode->next.load(memory_model::memory_order_relaxed)) { - value_type *pVal = pNode->data.load(memory_model::memory_order_relaxed).ptr(); - if (pVal) - erase(pNode); - node_type *pNext = pNode->next.load(memory_model::memory_order_relaxed); - pNode = pNext; - } + //TODO: fix destroy() + //node_type *pNode = m_Head.next.load(memory_model::memory_order_relaxed); + // + //node_type *pNode = m_Head->next; + // + //while (pNode != pNode->next.load(memory_model::memory_order_relaxed)) { + // value_type *pVal = pNode->data.load(memory_model::memory_order_relaxed).ptr(); + // if (pVal) + // erase(pNode); + // node_type *pNext = pNode->next.load(memory_model::memory_order_relaxed); + // pNode = pNext; + //} } bool delete_node(iterator i) { From 6e6de8e39e8a37c627f9e4cb470576b2592e39b7 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Mon, 8 Jan 2018 15:02:44 +0300 Subject: [PATCH 12/46] Fix insert, find --- cds/intrusive/details/valois_list_base.h | 2 +- cds/intrusive/impl/valois_list.h | 114 ++++++++++++++--------- 2 files changed, 73 insertions(+), 43 deletions(-) diff --git a/cds/intrusive/details/valois_list_base.h b/cds/intrusive/details/valois_list_base.h index 00011b6fe..2d363dcf6 100644 --- a/cds/intrusive/details/valois_list_base.h +++ b/cds/intrusive/details/valois_list_base.h @@ -54,7 +54,7 @@ namespace cds { namespace intrusive { node() { next.store( nullptr, atomics::memory_order_relaxed ); - data.store( marked_data_ptr(), atomics::memory_order_release ); + data.store( marked_data_ptr( NULL ), atomics::memory_order_release ); } node( value_type * pVal ) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 299dd16a8..b4ce601d8 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -77,6 +77,11 @@ namespace cds { : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} iterator( node_type * node) { + + m_pNode = new node_type(); + aux_pNode = new node_type(); + cell_pNode = new node_type(); + m_pNode->next.store(NULL, memory_model::memory_order_consume); aux_pNode->next.store( @@ -96,6 +101,7 @@ namespace cds { if (aux_pNode->next == m_pNode) { return; } + node_type *p = aux_pNode; node_type *n = p->next.load(atomics::memory_order_release); @@ -150,30 +156,6 @@ namespace cds { return iterator(m_Head); } - bool insert(value_type val) { - //TODO fix bug with interrupting the method. - while (true) { - auto iter = begin(); - while (true) { - auto current_data = iter->m_pNode.data; - auto next_data = iter->m_pNode->next.data; - if (current_data == val) { - return true; - } - if (current_data < val && next_data > val) { - if (insert(iter, val)) { - return true; - } else { - break; - } - } - iter++; - } - - } - return false; - } - /** * try insert in the position * @param i @@ -181,27 +163,70 @@ namespace cds { * @return */ - bool insert(iterator i, value_type &val) { - i.update_iterator(); + template + bool search_insert(node_type * start_node, Q* val, Compare cmp) { + + std::cout << "val " << val << std::endl; + + iterator *i = new iterator(start_node); + while (i->m_pNode->next.load() != nullptr && i->m_pNode->data.load().ptr() != NULL ) { + value_type *nVal = i->m_pNode->data.load( memory_model::memory_order_relaxed ).ptr(); + //value_type *nVal = i->m_pNode->data.load().all(); + int const nCmp = cmp(*nVal, *val); + + if (nCmp == 0) { + delete i; + return true; + } else if (nCmp > 0) { + bool k = try_insert(i, val); + delete i; + return k; + } else { + i->next(); + } + } + + std::cout << "after while " << std::endl; + bool k = try_insert(i, val); + delete i; + return k; + } + + bool try_insert(iterator *i, value_type * val) { + std::cout << "val " << val << std::endl; + i->update_iterator(); node_type *real_node = new node_type(val); + std::cout << "insert " << real_node->data.load().ptr(); node_type *aux_node = new node_type(); real_node->next = aux_node; - aux_node->next = i.m_pNode; + aux_node->next = i->m_pNode; - bool insert_status = i.aux_pNode->next.compare_exchange_strong( - i.m_pNode, + bool insert_status = i->aux_pNode->next.compare_exchange_strong( + i->m_pNode, real_node, - memory_model::memory_order_release, + memory_model::memory_order_relaxed, memory_model::memory_order_relaxed ); - if (insert_status) { - ++m_ItemCounter; - } + + std::cout << "insert_status " << insert_status << std::endl; + return insert_status; } + bool insert( value_type &val){ + std::cout << "val " << val << std::endl; + return search_insert( m_Head, &val, key_comparator() ); + } + + void print_all(){ + iterator * i = new iterator(m_Head); + while(i->m_pNode->next != nullptr){ + std::cout << i->m_pNode->data.load().ptr() << std::endl; + i->next(); + } + } /** * * It's true delete algorithm @@ -261,37 +286,42 @@ namespace cds { } template - bool find( node_type * start_node, Q const& val, Compare cmp) const { - iterator * i = new iterator( start_node ); - while (i->m_pNode != nullptr) { - value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_relaxed).ptr(); + bool find( Q * val, Compare cmp) { + iterator * i = new iterator( m_Head ); + while (i->m_pNode->next.load() != nullptr && i->m_pNode->data.load().ptr() != NULL ) { + value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_release ).ptr(); + int const nCmp = cmp( *nVal, val ); if ( nCmp == 0 ){ + delete i; return true; } else if ( nCmp > 0 ){ + delete i; return false; } else{ i->next(); } } + delete i; return false; } - bool find(value_type val) { - return find( m_Head, val, key_comparator()); + bool find(value_type &val) { + return find( &val, key_comparator() ); } - //TODO: implement get_iterator( value_type & val ) bool empty() { - iterator * iter = new iterator(m_Head); - if (iter->next()) { + iterator * i = new iterator(m_Head); + if (i->next()) { // if next is not exist() container is empty() + delete i; return false; } else { + delete i; return true; } } From c09df90fe240159109e11e2192d204fa5ed3c662 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Mon, 8 Jan 2018 19:10:38 +0300 Subject: [PATCH 13/46] Almoust finished. Small test working --- cds/intrusive/impl/valois_list.h | 152 +++++++++++++------------------ 1 file changed, 64 insertions(+), 88 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index b4ce601d8..552bb2a35 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -15,8 +15,6 @@ namespace cds { template class ValoisList { - friend class iterator; - public: typedef GC gc; ///< Garbage collector typedef T value_type; ///< type of value stored in the list @@ -27,7 +25,6 @@ namespace cds { typedef typename traits::disposer disposer; ///< disposer for \p value_type typedef typename traits::back_off back_off; ///< back-off strategy - typedef typename traits::item_counter item_counter; ///< Item counting policy used typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics @@ -42,10 +39,12 @@ namespace cds { atomic_node_ptr m_pHead; ///< Head pointer atomic_node_ptr m_pTail; ///< Tail pointer - item_counter m_ItemCounter; ///< Item counter - node_type *m_Head; - node_type *m_Tail; + node_type m_Head; + node_type m_Tail; + + public: + friend class iterator; protected: //template @@ -63,12 +62,14 @@ namespace cds { return false; } - cell_pNode->next.store( m_pNode, memory_model::memory_order_consume); - aux_pNode->next.store( m_pNode->next, memory_model::memory_order_consume); + cell_pNode->next.store( m_pNode, memory_model::memory_order_seq_cst); + aux_pNode->next.store( m_pNode->next, memory_model::memory_order_seq_cst); update_iterator(); return true; } + + public: typedef typename cds::details::make_const_type::pointer value_ptr; typedef typename cds::details::make_const_type::reference value_ref; @@ -76,24 +77,31 @@ namespace cds { iterator() : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} + // node - only m_Head iterator( node_type * node) { m_pNode = new node_type(); aux_pNode = new node_type(); cell_pNode = new node_type(); - m_pNode->next.store(NULL, memory_model::memory_order_consume); - aux_pNode->next.store( node->next.load(memory_model::memory_order_seq_cst), - memory_model::memory_order_consume + memory_model::memory_order_seq_cst ); cell_pNode->next.store( node, - memory_model::memory_order_consume + memory_model::memory_order_seq_cst ); + node_type * tempNode = aux_pNode->next.load(); + if ( tempNode->next.load() == nullptr ){ + m_pNode->next.store(NULL, memory_model::memory_order_seq_cst); + } + else{ + m_pNode->next.store( tempNode->next.load(), memory_model::memory_order_relaxed); + } + update_iterator(); } @@ -103,17 +111,18 @@ namespace cds { } node_type *p = aux_pNode; - node_type *n = p->next.load(atomics::memory_order_release); + node_type *n = p->next.load(atomics::memory_order_seq_cst); + //std::cout << "DataLoad" << *n->data.load().ptr() << std::endl; while ( n->next != nullptr && n->data == NULL) { //while not last and is aux node cell_pNode->next.compare_exchange_strong( p, n, - memory_model::memory_order_release, - atomics::memory_order_relaxed + memory_model::memory_order_seq_cst, + atomics::memory_order_seq_cst ); p = n; - n = p->next.load(atomics::memory_order_consume); + n = p->next.load(atomics::memory_order_seq_cst); } aux_pNode = p; @@ -153,7 +162,7 @@ namespace cds { } iterator begin() { - return iterator(m_Head); + return iterator(&m_Head); } /** @@ -166,38 +175,33 @@ namespace cds { template bool search_insert(node_type * start_node, Q* val, Compare cmp) { - std::cout << "val " << val << std::endl; + iterator * mIter = new iterator(&m_Head); + while (mIter->m_pNode->next.load() != nullptr ) { + value_type *nVal = mIter->m_pNode->data.load( memory_model::memory_order_seq_cst ).ptr(); - iterator *i = new iterator(start_node); - while (i->m_pNode->next.load() != nullptr && i->m_pNode->data.load().ptr() != NULL ) { - value_type *nVal = i->m_pNode->data.load( memory_model::memory_order_relaxed ).ptr(); - //value_type *nVal = i->m_pNode->data.load().all(); int const nCmp = cmp(*nVal, *val); if (nCmp == 0) { - delete i; + delete mIter; return true; } else if (nCmp > 0) { - bool k = try_insert(i, val); - delete i; + bool k = try_insert(mIter, val); + delete mIter; return k; } else { - i->next(); + mIter->next(); } } - std::cout << "after while " << std::endl; - bool k = try_insert(i, val); - delete i; + bool k = try_insert(mIter, val); + delete mIter; return k; } bool try_insert(iterator *i, value_type * val) { - std::cout << "val " << val << std::endl; i->update_iterator(); node_type *real_node = new node_type(val); - std::cout << "insert " << real_node->data.load().ptr(); node_type *aux_node = new node_type(); real_node->next = aux_node; @@ -206,26 +210,26 @@ namespace cds { bool insert_status = i->aux_pNode->next.compare_exchange_strong( i->m_pNode, real_node, - memory_model::memory_order_relaxed, - memory_model::memory_order_relaxed + memory_model::memory_order_seq_cst, + memory_model::memory_order_seq_cst ); - std::cout << "insert_status " << insert_status << std::endl; - + i->update_iterator(); return insert_status; } - bool insert( value_type &val){ - std::cout << "val " << val << std::endl; - return search_insert( m_Head, &val, key_comparator() ); + + bool insert( value_type &val ){ + return search_insert( &m_Head, &val, key_comparator() ); } void print_all(){ - iterator * i = new iterator(m_Head); - while(i->m_pNode->next != nullptr){ - std::cout << i->m_pNode->data.load().ptr() << std::endl; + iterator * i = new iterator(&m_Head); + while(i->m_pNode->next.load() != nullptr){ + std::cout << "item: " << *i->m_pNode->data.load().ptr() << std::endl; i->next(); } + delete i; } /** * @@ -265,33 +269,13 @@ namespace cds { } - /** - * return value by integer index - * for testing only - * @param index - * @return - */ - value_type get(int index) { - auto iter = begin(); - int current_index = 0; - while (iter.next()) { - current_index++; - if (current_index == index) { - return iter->m_pNode.data; - } else if (current_index > index) { - break; - } - return NULL; - } - } - template - bool find( Q * val, Compare cmp) { - iterator * i = new iterator( m_Head ); - while (i->m_pNode->next.load() != nullptr && i->m_pNode->data.load().ptr() != NULL ) { - value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_release ).ptr(); + bool find( Q* val, Compare cmp) { + iterator * i = new iterator( &m_Head ); + while (i->m_pNode->next.load() != nullptr ) { + value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_seq_cst ).ptr(); - int const nCmp = cmp( *nVal, val ); + int const nCmp = cmp( *nVal, *val ); if ( nCmp == 0 ){ delete i; @@ -313,10 +297,9 @@ namespace cds { return find( &val, key_comparator() ); } - bool empty() { - iterator * i = new iterator(m_Head); - if (i->next()) { + iterator * i = new iterator(&m_Head); + if ( i->next() ) { // if next is not exist() container is empty() delete i; return false; @@ -330,25 +313,22 @@ namespace cds { void init_list() { node_type * aux_temp = new node_type(); - m_Head = new node_type(); - m_Tail = new node_type(); - m_Head->next.store( aux_temp, memory_model::memory_order_relaxed); //link to aux node - aux_temp->next.store( m_Tail, memory_model::memory_order_relaxed ); - m_Tail->next.store(nullptr, memory_model::memory_order_relaxed ); //link tail to nullptr + + m_Head.next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + aux_temp->next.store( &m_Tail, memory_model::memory_order_seq_cst ); + m_Tail.next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr } void destroy() { //TODO: fix destroy() - //node_type *pNode = m_Head.next.load(memory_model::memory_order_relaxed); - // - //node_type *pNode = m_Head->next; + //node_type *tNode = m_Head->next.load(memory_model::memory_order_relaxed); // - //while (pNode != pNode->next.load(memory_model::memory_order_relaxed)) { - // value_type *pVal = pNode->data.load(memory_model::memory_order_relaxed).ptr(); + //while (tNode != tNode->next.load(memory_model::memory_order_relaxed)) { + // value_type *pVal = tNode->data.load(memory_model::memory_order_relaxed).ptr(); // if (pVal) - // erase(pNode); - // node_type *pNext = pNode->next.load(memory_model::memory_order_relaxed); - // pNode = pNext; + // erase(tNode); + // node_type *pNext = tNode->next.load(memory_model::memory_order_relaxed); + // tNode = pNext; //} } @@ -358,12 +338,8 @@ namespace cds { node_type *adjacent = i.m_pNode->next; bool delete_status = i.aux_pNode->next.compare_exchange_strong(for_delete, adjacent, - memory_model::memory_order_relaxed, - memory_model::memory_order_release); - - if (delete_status) { - --m_ItemCounter; - } + memory_model::memory_order_seq_cst, + memory_model::memory_order_seq_cst); return delete_status; } From 5c1e8daf9b1d6ace7970ddc9f6c16f545019bfb9 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Mon, 8 Jan 2018 19:20:40 +0300 Subject: [PATCH 14/46] variables type fix --- .../intrusive-list/intrusive_valois_hp.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 18d44a4d5..9b1dd931e 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -86,7 +86,7 @@ namespace { int size = 10; // insert and contains method - for ( size_t i = 0; i < nSize; i++ ) { + for ( int i = 0; i < size; i++ ) { ASSERT_FALSE(list.find(i)); list.insert(i); @@ -94,14 +94,14 @@ namespace { ASSERT_FALSE( list.empty()); } - // delete and contains method - for(size_t i = nSize; i > 0; i--){ - ASSERT_TRUE( list.find(i)); - list.insert(i); - ASSERT_FALSE(list.find(i)); - } - // test empty method(); - ASSERT_TRUE( list.empty()); + //// delete and contains method + //for(size_t i = nSize; i > 0; i--){ + // ASSERT_TRUE( list.find(i)); + // list.insert(i); + // ASSERT_FALSE(list.find(i)); + //} + //// test empty method(); + //ASSERT_TRUE( list.empty()); } @@ -110,7 +110,7 @@ namespace { { struct traits: public ci::valois_list::traits{}; - typedef ci::ValoisList< gc_type, base_item, traits > list_type; + typedef ci::ValoisList< gc_type, int, traits > list_type; list_type l; test_list(l); From 745eb12ce1fc876caafed77973aeb462ae58c5f8 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 9 Jan 2018 03:44:08 +0300 Subject: [PATCH 15/46] add new debug functions --- cds/intrusive/impl/valois_list.h | 114 +++++++++++++++--- .../intrusive-list/intrusive_valois_hp.cpp | 29 +++-- 2 files changed, 119 insertions(+), 24 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 552bb2a35..7d1335320 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -40,9 +40,6 @@ namespace cds { atomic_node_ptr m_pHead; ///< Head pointer atomic_node_ptr m_pTail; ///< Tail pointer - node_type m_Head; - node_type m_Tail; - public: friend class iterator; @@ -157,12 +154,34 @@ namespace cds { init_list(); } + /** + * DEBUG ONLY + * @param number + */ + + ValoisList(int number) { + node_type * aux_temp = new node_type(); + std::cout << "hello from me" <next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + std::cout << "hello from me 2" <next.store( m_pTail, memory_model::memory_order_seq_cst ); + m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr + std::cout << "hello from me 3" < bool search_insert(node_type * start_node, Q* val, Compare cmp) { - iterator * mIter = new iterator(&m_Head); + iterator * mIter = new iterator(m_pHead); while (mIter->m_pNode->next.load() != nullptr ) { value_type *nVal = mIter->m_pNode->data.load( memory_model::memory_order_seq_cst ).ptr(); @@ -220,17 +239,50 @@ namespace cds { bool insert( value_type &val ){ - return search_insert( &m_Head, &val, key_comparator() ); + return search_insert( m_pHead, &val, key_comparator() ); } - void print_all(){ - iterator * i = new iterator(&m_Head); + + /** + * Print all node in console + * this function for debug only + */ + + void print_all_by_iterator(){ + iterator * i = new iterator(m_pHead); + + std::cout << "----------start print by iterator---------------" << std::endl; while(i->m_pNode->next.load() != nullptr){ - std::cout << "item: " << *i->m_pNode->data.load().ptr() << std::endl; + value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_seq_cst ).ptr(); + std::cout << *nVal << std::endl; i->next(); } + std::cout << "----------end---------------" << std::endl; + delete i; } + + void print_all_by_link(){ + std::cout << "----------start print by link---------------" << std::endl; + + node_type * next_node = m_pHead.load(); + node_type * next_aux_node; + int number = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + std::cout << "next_aux_node -> " < " <next.load() << std::endl; + std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; + + value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + + std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; + number++; + } while (next_node->next.load() != nullptr); + std::cout << "----------finish print by link---------------" << std::endl; + } + /** * * It's true delete algorithm @@ -271,10 +323,11 @@ namespace cds { template bool find( Q* val, Compare cmp) { - iterator * i = new iterator( &m_Head ); + iterator * i = new iterator( m_pHead ); while (i->m_pNode->next.load() != nullptr ) { value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_seq_cst ).ptr(); - + std::cout << *nVal << std::endl; + //std::cout << *nVal << std::end; int const nCmp = cmp( *nVal, *val ); if ( nCmp == 0 ){ @@ -298,7 +351,7 @@ namespace cds { } bool empty() { - iterator * i = new iterator(&m_Head); + iterator * i = new iterator(m_pHead); if ( i->next() ) { // if next is not exist() container is empty() delete i; @@ -314,9 +367,9 @@ namespace cds { void init_list() { node_type * aux_temp = new node_type(); - m_Head.next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node - aux_temp->next.store( &m_Tail, memory_model::memory_order_seq_cst ); - m_Tail.next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr + m_pHead.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + aux_temp->next.store( m_pTail, memory_model::memory_order_seq_cst ); + m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr } void destroy() { @@ -343,6 +396,37 @@ namespace cds { return delete_status; } + + + /** + * Debug only + * @param number + */ + + void append(int * number){ + node_type * next_node = m_pHead.load(); + node_type * next_aux_node; + std::cout << "iter " << *number << std::endl; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + std::cout << "next_aux_node -> " < " <next.load() << std::endl; + std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; + + } while (next_node->next.load() != nullptr); + + node_type * new_next_node = new node_type(number); + node_type * new_next_aux_node = new node_type(); + + new_next_aux_node->next.store(next_node); + std::cout << "append 5 " <next.store(new_next_aux_node); + std::cout << "append 6 " <next.store(new_next_node); + + std::cout << "finish" << std::endl << std::endl; + } }; } diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 9b1dd931e..feb19f2ef 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -63,11 +63,14 @@ namespace { } }; - /** - * - * @tparam List - * @param list - */ + template + void test_simple_list(List& list) + { + std::cout << "simple test started " << std::endl; + list.print_all_by_link(); + + } + template void test_list(List& list) { @@ -83,17 +86,23 @@ namespace { static const size_t nSize = 20; typedef typename List::value_type value_type; - int size = 10; + int size = 3; // insert and contains method for ( int i = 0; i < size; i++ ) { ASSERT_FALSE(list.find(i)); list.insert(i); + if(i>1){ + list.print_all_by_link(); + } ASSERT_TRUE( list.find(i)); ASSERT_FALSE( list.empty()); + } + list.print_all_by_link(); + //// delete and contains method //for(size_t i = nSize; i > 0; i--){ // ASSERT_TRUE( list.find(i)); @@ -111,9 +120,11 @@ namespace { struct traits: public ci::valois_list::traits{}; typedef ci::ValoisList< gc_type, int, traits > list_type; - list_type l; - test_list(l); - + list_type l(20); + test_simple_list(l); +/* + list_type l2; + test_list(l2);*/ } } // namespace From 4b503603792cbdde9706c0f5786b31808207cbaf Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 9 Jan 2018 05:28:12 +0300 Subject: [PATCH 16/46] fix with test --- cds/intrusive/impl/valois_list.h | 30 +++++++++++-------- .../intrusive-list/intrusive_valois_hp.cpp | 19 ++++++------ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 7d1335320..c67b7c7e7 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -161,15 +161,12 @@ namespace cds { ValoisList(int number) { node_type * aux_temp = new node_type(); - std::cout << "hello from me" <next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node - std::cout << "hello from me 2" <next.store( m_pTail, memory_model::memory_order_seq_cst ); m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr - std::cout << "hello from me 3" < " < " <next.load() << std::endl; std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; - - value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - - std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; + if (next_node->next){ + value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + value_type * nVala = next_aux_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + std::cout << number << " aux -> " << nVala << " -> "<< std::endl; + std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; + } number++; - } while (next_node->next.load() != nullptr); + } while (next_node->next != nullptr); std::cout << "----------finish print by link---------------" << std::endl; } @@ -366,10 +365,12 @@ namespace cds { void init_list() { node_type * aux_temp = new node_type(); - + m_pHead.store(new node_type); m_pHead.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + m_pTail.store(new node_type); aux_temp->next.store( m_pTail, memory_model::memory_order_seq_cst ); m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr + } void destroy() { @@ -393,7 +394,6 @@ namespace cds { bool delete_status = i.aux_pNode->next.compare_exchange_strong(for_delete, adjacent, memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst); - return delete_status; } @@ -416,7 +416,13 @@ namespace cds { } while (next_node->next.load() != nullptr); - node_type * new_next_node = new node_type(number); + std::cout << number << " -> " << *number << std::endl; + + + int d = *number; + int * index = new int32_t(d); + std::cout<< "wtf wtf " <next.store(next_node); diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index feb19f2ef..0001fdf45 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -74,6 +74,7 @@ namespace { template void test_list(List& list) { + std::cout << "simple middle started " << std::endl; /** * 1) testing method is empty * 2) test adding 10 element in the container @@ -90,13 +91,13 @@ namespace { // insert and contains method for ( int i = 0; i < size; i++ ) { + int * index = new int32_t(i); - ASSERT_FALSE(list.find(i)); - list.insert(i); - if(i>1){ - list.print_all_by_link(); - } - ASSERT_TRUE( list.find(i)); + std::cout << index << std::endl; + + ASSERT_FALSE(list.find(*index)); + list.insert(*index); + ASSERT_TRUE( list.find(*index)); ASSERT_FALSE( list.empty()); } @@ -120,11 +121,11 @@ namespace { struct traits: public ci::valois_list::traits{}; typedef ci::ValoisList< gc_type, int, traits > list_type; - list_type l(20); + list_type l(2); test_simple_list(l); -/* + list_type l2; - test_list(l2);*/ + test_list(l2); } } // namespace From f72fa65ae5de60a10ef830cd4824a62837ea5611 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 9 Jan 2018 05:37:19 +0300 Subject: [PATCH 17/46] update test --- .../intrusive-list/intrusive_valois_hp.cpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 0001fdf45..78edfa75f 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -90,7 +90,7 @@ namespace { int size = 3; // insert and contains method - for ( int i = 0; i < size; i++ ) { + for ( int i = 0; i <= size; i++ ) { int * index = new int32_t(i); std::cout << index << std::endl; @@ -102,16 +102,23 @@ namespace { } - list.print_all_by_link(); - //// delete and contains method - //for(size_t i = nSize; i > 0; i--){ - // ASSERT_TRUE( list.find(i)); - // list.insert(i); - // ASSERT_FALSE(list.find(i)); - //} - //// test empty method(); - //ASSERT_TRUE( list.empty()); + // test adding in + for(int i = nSize; i >= 0; i--){ + ASSERT_TRUE( list.find(i)); + } + + + //list.print_all_by_link(); + + // delete and contains method + for(int i = nSize; i >= 0; i--){ + ASSERT_TRUE( list.find(i)); + list.insert(i); + ASSERT_FALSE(list.find(i)); + } + // test empty method(); + ASSERT_TRUE( list.empty()); } From a4c5ca757a1b40d3c49d082a025b5ff92944e55d Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 9 Jan 2018 05:39:42 +0300 Subject: [PATCH 18/46] update test --- test/unit/intrusive-list/intrusive_valois_hp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 78edfa75f..ec5dc4180 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -87,10 +87,9 @@ namespace { static const size_t nSize = 20; typedef typename List::value_type value_type; - int size = 3; // insert and contains method - for ( int i = 0; i <= size; i++ ) { + for ( int i = 0; i <= nSize; i++ ) { int * index = new int32_t(i); std::cout << index << std::endl; From c212802648e68bdeeec6466a70c7513dd5569136 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 9 Jan 2018 15:40:01 +0300 Subject: [PATCH 19/46] add random test, fix bugs, comment update iterator --- cds/intrusive/impl/valois_list.h | 235 +++++++++++------- .../intrusive-list/intrusive_valois_hp.cpp | 55 +++- 2 files changed, 199 insertions(+), 91 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index c67b7c7e7..16ee8c1e3 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -49,19 +49,61 @@ namespace cds { friend class ValoisList; protected: - node_type *m_pNode; // Valois target - current real node - node_type *aux_pNode; // Valois pre_aux - aux node before the real node - node_type *cell_pNode; // Valois pre_cell - real node before the current real node + node_type * current_node; // Valois target - current real node + node_type * aux_pNode; // Valois pre_aux - aux node before the real node + node_type * prev_node; // Valois pre_cell - real node before the current real node typename gc::Guard m_Guard; bool next() { - if (m_pNode->next == nullptr) { // if tail + //std::cout <<"hello from next "<next == nullptr) { // if tail return false; } - cell_pNode->next.store( m_pNode, memory_model::memory_order_seq_cst); - aux_pNode->next.store( m_pNode->next, memory_model::memory_order_seq_cst); - update_iterator(); + int * value; + + +// if (prev_node->data.load() != nullptr){ +// value = prev_node->data.load().ptr(); +// std::cout <<"in next 1 "<< *value <data.load() != nullptr){ +// value = current_node->data.load().ptr(); +// std::cout << "current node " << *value <next <data.store(current_node->data.load()); + new_current_node->next.store(current_node->next.load()); + + prev_node = new_current_node; + + new_current_node = new node_type(); + new_current_node->data.store(current_node->next.load()->data.load()); + new_current_node->next.store(current_node->next.load()->next.load()); + + aux_pNode = new_current_node; + + current_node = aux_pNode->next.load(); + + + + //update_iterator(); + +// if (prev_node->data.load() != nullptr) { +// value = prev_node->data.load().ptr(); +// std::cout << "in next 2 " << *value << std::endl; +// } else{ +// std::cout <<"in next 2 NULL" <::reference value_ref; iterator() - : m_pNode(nullptr), aux_pNode(nullptr), cell_pNode(nullptr) {} + : current_node(nullptr), aux_pNode(nullptr), prev_node(nullptr) {} // node - only m_Head iterator( node_type * node) { - m_pNode = new node_type(); + current_node = new node_type(); aux_pNode = new node_type(); - cell_pNode = new node_type(); + prev_node = new node_type(); aux_pNode->next.store( node->next.load(memory_model::memory_order_seq_cst), memory_model::memory_order_seq_cst ); - cell_pNode->next.store( + prev_node->next.store( node, memory_model::memory_order_seq_cst ); node_type * tempNode = aux_pNode->next.load(); if ( tempNode->next.load() == nullptr ){ - m_pNode->next.store(NULL, memory_model::memory_order_seq_cst); + current_node->next.store(NULL, memory_model::memory_order_seq_cst); } else{ - m_pNode->next.store( tempNode->next.load(), memory_model::memory_order_relaxed); + current_node->next.store( tempNode->next.load(), memory_model::memory_order_relaxed); } update_iterator(); } void update_iterator() { - if (aux_pNode->next == m_pNode) { + //std::cout << "\t in update iterator " << std::endl; + if (aux_pNode->next == current_node) { return; } + int * data; + + node_type * p = aux_pNode; + node_type * n = p->next.load(atomics::memory_order_seq_cst); + + data = n->next.load()->data.load().ptr(); + //std::cout << "\t data 1 is "<< (n->data.load().ptr()) << " -> " << data << std::endl; + int tmp = 0; - node_type *p = aux_pNode; - node_type *n = p->next.load(atomics::memory_order_seq_cst); + while ( n->next != nullptr && n->data == nullptr) { //while not last and is aux node + tmp++; - //std::cout << "DataLoad" << *n->data.load().ptr() << std::endl; - while ( n->next != nullptr && n->data == NULL) { //while not last and is aux node - cell_pNode->next.compare_exchange_strong( + prev_node->next.compare_exchange_strong( p, n, - memory_model::memory_order_seq_cst, + atomics::memory_order_seq_cst, atomics::memory_order_seq_cst ); p = n; n = p->next.load(atomics::memory_order_seq_cst); } +// std::cout << "\t count in while " <data.load().ptr(); +// std::cout << "\t data 2 is " << data << std::endl; + aux_pNode = p; - m_pNode = n; + current_node = n; +// std::cout << "\t bye update iterator " << std::endl; } iterator &operator++() { @@ -133,19 +188,19 @@ namespace cds { } iterator &operator=(iterator &second) { - m_pNode = second.m_pNode; + current_node = second.current_node; aux_pNode = second.aux_pNode; - cell_pNode = second.cell_pNode; + prev_node = second.prev_node; m_Guard.copy(second.m_Guard); return *this; } bool operator==(const iterator &second) const { - return (m_pNode->data == second.m_pNode->data); + return (current_node->data == second.current_node->data); } bool operator!=(const iterator &second) const { - return (m_pNode->data != second.m_pNode->data); + return (current_node->data != second.current_node->data); } }; @@ -189,18 +244,22 @@ namespace cds { */ template - bool search_insert(node_type * start_node, Q* val, Compare cmp) { + bool search_insert(node_type * start_node /*it not used*/, Q* val, Compare cmp) { iterator * mIter = new iterator(m_pHead); - while (mIter->m_pNode->next.load() != nullptr ) { - value_type *nVal = mIter->m_pNode->data.load( memory_model::memory_order_seq_cst ).ptr(); - - int const nCmp = cmp(*nVal, *val); + while (mIter->current_node->next.load() != nullptr ) { + value_type *nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); + int const nCmp = cmp(*val, *nVal); + /*std::cout << "search_insert : finded value "<< *nVal << std::endl; + std::cout << "search_insert : inserted value "<< *val << std::endl; + std::cout << "search_insert : compare index "<< nCmp << std::endl;*/ if (nCmp == 0) { delete mIter; return true; } else if (nCmp > 0) { + + bool k = try_insert(mIter, val); delete mIter; return k; @@ -215,22 +274,23 @@ namespace cds { } bool try_insert(iterator *i, value_type * val) { - i->update_iterator(); + //i->update_iterator(); + //std::cout << "try insert "<< *val << std::endl; node_type *real_node = new node_type(val); node_type *aux_node = new node_type(); real_node->next = aux_node; - aux_node->next = i->m_pNode; + aux_node->next = i->current_node; bool insert_status = i->aux_pNode->next.compare_exchange_strong( - i->m_pNode, + i->current_node, real_node, memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst ); - i->update_iterator(); + //i->update_iterator(); return insert_status; } @@ -249,8 +309,8 @@ namespace cds { iterator * i = new iterator(m_pHead); std::cout << "----------start print by iterator---------------" << std::endl; - while(i->m_pNode->next.load() != nullptr){ - value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_seq_cst ).ptr(); + while(i->current_node->next.load() != nullptr){ + value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); std::cout << *nVal << std::endl; i->next(); } @@ -283,51 +343,49 @@ namespace cds { } /** - * - * It's true delete algorithm - * @param i + * delete value from linked list; + * @param value * @return */ + template + bool erase(Q* val, Compare cmp) { + iterator * i = new iterator( m_pHead ); + //search node + while (i->current_node->next.load() != nullptr ) { + value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + int const nCmp = cmp( *val , *nVal ); - bool erase(iterator &i) { - if (i.cell_pNode != nullptr) { // if not Head - while (true) { - i.update_iterator(); - if (delete_node(i)) { - return true; - } - i.update_iterator(); + if ( nCmp == 0 ){ + // hard delete operation + while (!try_erase(i)) {} + delete i; + return true; + } + else if ( nCmp > 0 ){ + delete i; + return true; + } + else{ + i->next(); } } - return false; - } - /** - * delete value from linked list; - * @param value - * @return - */ + delete i; + return true; + } - bool erase(value_type &value) { - while (true) { - auto iter = begin(); - //skip if element not exists - if (!find(iter, value))return true; - if (erase(iter)) return true; - // commented for start from begin position - //iter.update_iterator(); - } + bool erase(value_type val){ + return erase(&val, key_comparator()); } + template bool find( Q* val, Compare cmp) { iterator * i = new iterator( m_pHead ); - while (i->m_pNode->next.load() != nullptr ) { - value_type * nVal = i->m_pNode->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << *nVal << std::endl; - //std::cout << *nVal << std::end; - int const nCmp = cmp( *nVal, *val ); + while (i->current_node->next.load() != nullptr ) { + value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ delete i; @@ -349,8 +407,14 @@ namespace cds { return find( &val, key_comparator() ); } + bool contains(value_type &val) { + return find( &val, key_comparator() ); + } + bool empty() { + /*std::cout << "hello from empty" << std::endl;*/ iterator * i = new iterator(m_pHead); + if ( i->next() ) { // if next is not exist() container is empty() delete i; @@ -361,6 +425,7 @@ namespace cds { } } + private: void init_list() { @@ -386,14 +451,18 @@ namespace cds { //} } - bool delete_node(iterator i) { + bool try_erase(iterator *i) { - node_type *for_delete = i.m_pNode; - node_type *adjacent = i.m_pNode->next; + node_type *for_delete = i->current_node; + node_type *adjacent = i->current_node->next; + + bool delete_status = i->aux_pNode->next + .compare_exchange_strong( + for_delete, + adjacent, + memory_model::memory_order_seq_cst, + memory_model::memory_order_seq_cst); - bool delete_status = i.aux_pNode->next.compare_exchange_strong(for_delete, adjacent, - memory_model::memory_order_seq_cst, - memory_model::memory_order_seq_cst); return delete_status; } @@ -406,32 +475,32 @@ namespace cds { void append(int * number){ node_type * next_node = m_pHead.load(); node_type * next_aux_node; - std::cout << "iter " << *number << std::endl; + //std::cout << "iter " << *number << std::endl; do{ next_aux_node = next_node->next.load(); next_node = next_aux_node->next.load(); - std::cout << "next_aux_node -> " < " <next.load() << std::endl; - std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; + //std::cout << "next_aux_node -> " < " <next.load() << std::endl; + //std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; } while (next_node->next.load() != nullptr); - std::cout << number << " -> " << *number << std::endl; + //std::cout << number << " -> " << *number << std::endl; int d = *number; int * index = new int32_t(d); - std::cout<< "wtf wtf " <next.store(next_node); - std::cout << "append 5 " <next.store(new_next_aux_node); - std::cout << "append 6 " <next.store(new_next_node); - std::cout << "finish" << std::endl << std::endl; + //std::cout << "finish" << std::endl << std::endl; } }; diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index ec5dc4180..a1c2452ff 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -67,7 +67,21 @@ namespace { void test_simple_list(List& list) { std::cout << "simple test started " << std::endl; - list.print_all_by_link(); + list.empty(); + list.empty(); + list.empty(); + list.empty(); + list.empty(); + list.empty(); + list.print_all_by_iterator(); + list.print_all_by_iterator(); + + int value = 5; + std::cout << "find 5 "<= 0; i--){ + for ( int i = 0; i <= nSize; i++ ) { ASSERT_TRUE( list.find(i)); } @@ -113,7 +123,7 @@ namespace { // delete and contains method for(int i = nSize; i >= 0; i--){ ASSERT_TRUE( list.find(i)); - list.insert(i); + list.erase(i); ASSERT_FALSE(list.find(i)); } // test empty method(); @@ -121,17 +131,46 @@ namespace { } + template + void random_test_list(List& list){ + std::cout << "random test started " << std::endl; + int items[10] = {4,7,6,8,2,9,10,1,0,5}; + + //insert + for(auto i : items){ + int * index = new int32_t(i); + ASSERT_TRUE(list.insert(*index)); + } + + list.print_all_by_iterator(); + + //contains + for(auto i : items){ + ASSERT_TRUE(list.contains(i)); + } + + //delete + for(auto i : items){ + ASSERT_TRUE(list.erase(i)); + } + + } + TEST_F( IntrusiveValoisList_HP, base_hook ) { struct traits: public ci::valois_list::traits{}; typedef ci::ValoisList< gc_type, int, traits > list_type; - list_type l(2); + list_type l(20); test_simple_list(l); list_type l2; test_list(l2); + + list_type l3; + random_test_list(l3); + } } // namespace From 57e205a67fb8c30e59232e7b4f54799e8564c5a3 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 02:27:00 +0300 Subject: [PATCH 20/46] add revert unit test --- .../intrusive-list/intrusive_valois_hp.cpp | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index a1c2452ff..646e35f4d 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -131,6 +131,42 @@ namespace { } + template + void revert_test_list(List& list){ + std::cout << "revert test started " << std::endl; + ASSERT_TRUE( list.empty()); + + static const size_t nSize = 20; + typedef typename List::value_type value_type; + + // insert and contains method + for ( int i = nSize; i >= 0 ; i-- ) { + int * index = new int32_t(i); + ASSERT_FALSE(list.find(*index)); + list.insert(*index); + ASSERT_TRUE( list.find(*index)); + ASSERT_FALSE( list.empty()); + } + + // test adding in + for ( int i = nSize; i >= 0 ; i-- ) { + ASSERT_TRUE( list.find(i)); + } + + + //list.print_all_by_link(); + + // delete and contains method + for ( int i = nSize; i >= 0 ; i-- ) { + ASSERT_TRUE( list.find(i)); + list.erase(i); + ASSERT_FALSE(list.find(i)); + } + // test empty method(); + ASSERT_TRUE( list.empty()); + } + + template void random_test_list(List& list){ std::cout << "random test started " << std::endl; @@ -169,7 +205,10 @@ namespace { test_list(l2); list_type l3; - random_test_list(l3); + revert_test_list(l3); + + list_type l4; + random_test_list(l4); } From 829ef8fa2c19a49b4f9c3d5e410746c740f8029b Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 03:28:10 +0300 Subject: [PATCH 21/46] update insert --- cds/intrusive/impl/valois_list.h | 138 ++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 48 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 16ee8c1e3..202a20fd5 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -1,4 +1,32 @@ -//TODO: maybe add DOXYGEN docs +/* + 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 CDS_VALOIS_LIST_H #define CDS_VALOIS_LIST_H @@ -247,19 +275,31 @@ namespace cds { bool search_insert(node_type * start_node /*it not used*/, Q* val, Compare cmp) { iterator * mIter = new iterator(m_pHead); + // for first node + std::cout << "search_insert : finded value "<< mIter->current_node->data.load().ptr() << std::endl; + value_type * nVal = mIter->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + + if(nVal != nullptr){ + int const nCmp = cmp( *nVal , *val ); + if (nCmp > 0){ + bool k = try_insert(mIter, val); + delete mIter; + return k; + } + } + + while (mIter->current_node->next.load() != nullptr ) { - value_type *nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); + nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); int const nCmp = cmp(*val, *nVal); - /*std::cout << "search_insert : finded value "<< *nVal << std::endl; + std::cout << "search_insert : finded value "<< *nVal << std::endl; std::cout << "search_insert : inserted value "<< *val << std::endl; - std::cout << "search_insert : compare index "<< nCmp << std::endl;*/ + std::cout << "search_insert : compare index "<< nCmp << std::endl; if (nCmp == 0) { delete mIter; return true; } else if (nCmp > 0) { - - bool k = try_insert(mIter, val); delete mIter; return k; @@ -300,48 +340,6 @@ namespace cds { } - /** - * Print all node in console - * this function for debug only - */ - - void print_all_by_iterator(){ - iterator * i = new iterator(m_pHead); - - std::cout << "----------start print by iterator---------------" << std::endl; - while(i->current_node->next.load() != nullptr){ - value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << *nVal << std::endl; - i->next(); - } - std::cout << "----------end---------------" << std::endl; - - delete i; - } - - void print_all_by_link(){ - std::cout << "----------start print by link---------------" << std::endl; - - node_type * next_node = m_pHead.load(); - node_type * next_aux_node; - int number = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - std::cout << "next_aux_node -> " < " <next.load() << std::endl; - std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; - if (next_node->next){ - value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - value_type * nVala = next_aux_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << number << " aux -> " << nVala << " -> "<< std::endl; - std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; - } - number++; - } while (next_node->next != nullptr); - std::cout << "----------finish print by link---------------" << std::endl; - } - /** * delete value from linked list; * @param value @@ -426,6 +424,50 @@ namespace cds { } + + + /** + * Print all node in console + * this function for debug only + */ + + void print_all_by_iterator(){ + iterator * i = new iterator(m_pHead); + + std::cout << "----------start print by iterator---------------" << std::endl; + while(i->current_node->next.load() != nullptr){ + value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + std::cout << *nVal << std::endl; + i->next(); + } + std::cout << "----------end---------------" << std::endl; + + delete i; + } + + void print_all_by_link(){ + std::cout << "----------start print by link---------------" << std::endl; + + node_type * next_node = m_pHead.load(); + node_type * next_aux_node; + int number = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + std::cout << "next_aux_node -> " < " <next.load() << std::endl; + std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; + if (next_node->next){ + value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + value_type * nVala = next_aux_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + std::cout << number << " aux -> " << nVala << " -> "<< std::endl; + std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; + } + number++; + } while (next_node->next != nullptr); + std::cout << "----------finish print by link---------------" << std::endl; + } + private: void init_list() { From ae184936048cda53a5bb558d480a1b198f1bf5b5 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 12:29:06 +0300 Subject: [PATCH 22/46] fix verstion with append --- cds/intrusive/impl/valois_list.h | 92 ++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 202a20fd5..24848ef22 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -57,7 +57,7 @@ namespace cds { typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics - typedef typename gc::template guarded_ptr guarded_ptr; ///< Guarded pointer + /*typedef typename gc::template guarded_ptr guarded_ptr; */ ///< Guarded pointer static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm @@ -65,7 +65,7 @@ namespace cds { typedef typename atomics::atomic atomic_node_ptr; typedef typename node_type::marked_data_ptr marked_data_ptr; - atomic_node_ptr m_pHead; ///< Head pointer + atomic_node_ptr list_head_node; ///< Head pointer atomic_node_ptr m_pTail; ///< Tail pointer public: @@ -80,7 +80,7 @@ namespace cds { node_type * current_node; // Valois target - current real node node_type * aux_pNode; // Valois pre_aux - aux node before the real node node_type * prev_node; // Valois pre_cell - real node before the current real node - typename gc::Guard m_Guard; + /*typename gc::Guard m_Guard;*/ bool next() { //std::cout <<"hello from next "<next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + list_head_node.store(new node_type); + list_head_node.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node m_pTail.store(new node_type); aux_temp->next.store( m_pTail, memory_model::memory_order_seq_cst ); m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr @@ -261,7 +261,7 @@ namespace cds { } iterator begin() { - return iterator(m_pHead); + return iterator(list_head_node); } /** @@ -274,40 +274,55 @@ namespace cds { template bool search_insert(node_type * start_node /*it not used*/, Q* val, Compare cmp) { - iterator * mIter = new iterator(m_pHead); - // for first node - std::cout << "search_insert : finded value "<< mIter->current_node->data.load().ptr() << std::endl; - value_type * nVal = mIter->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + iterator * mIter = new iterator(list_head_node); - if(nVal != nullptr){ + /*if(nVal != nullptr){ int const nCmp = cmp( *nVal , *val ); if (nCmp > 0){ bool k = try_insert(mIter, val); delete mIter; return k; } - } + }*/ + + + while (true) { + value_type * nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); + + if(nVal == nullptr){ + append(val); + delete mIter; + return true; + } - while (mIter->current_node->next.load() != nullptr ) { - nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); int const nCmp = cmp(*val, *nVal); - std::cout << "search_insert : finded value "<< *nVal << std::endl; + /*std::cout << "search_insert : finded value "<< *nVal << std::endl; std::cout << "search_insert : inserted value "<< *val << std::endl; std::cout << "search_insert : compare index "<< nCmp << std::endl; +*/ if (nCmp == 0) { delete mIter; return true; - } else if (nCmp > 0) { + } else if (nCmp < 0) { + if (*val == 3 ){ + std::cout << "here "<<*val<< " " << *nVal << std::endl; + print_all_by_iterator(); + } bool k = try_insert(mIter, val); + if (*val == 3 ){ + print_all_by_iterator(); + std::cout << std::endl<< std::endl<< std::endl<< std::endl<< std::endl; + } + delete mIter; return k; } else { mIter->next(); } } - + std::cout << "here "<< std::endl; bool k = try_insert(mIter, val); delete mIter; return k; @@ -319,7 +334,18 @@ namespace cds { node_type *real_node = new node_type(val); node_type *aux_node = new node_type(); - + if(*val ==3){ + int * prev = i->prev_node->data.load().ptr(); + std::cout << "try insert inserted "<< *val << std::endl; + std::cout << "try insert current "<< *(i->current_node->data.load().ptr()) << std::endl; + //std::cout << "try insert prev "<< i->prev_node->data.load().ptr() << std::endl; + if (i->aux_pNode == nullptr){ + std::cout << "aux is null" << std::endl; + } + if (prev != nullptr){ + std::cout << "prev data " <<*prev << std::endl; + } + } real_node->next = aux_node; aux_node->next = i->current_node; @@ -331,12 +357,12 @@ namespace cds { ); //i->update_iterator(); - return insert_status; + return true; } bool insert( value_type &val ){ - return search_insert( m_pHead, &val, key_comparator() ); + return search_insert( list_head_node, &val, key_comparator() ); } @@ -347,7 +373,7 @@ namespace cds { */ template bool erase(Q* val, Compare cmp) { - iterator * i = new iterator( m_pHead ); + iterator * i = new iterator( list_head_node ); //search node while (i->current_node->next.load() != nullptr ) { value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); @@ -355,6 +381,7 @@ namespace cds { if ( nCmp == 0 ){ // hard delete operation + //std::cout << "trying delete " << *val << std::endl; while (!try_erase(i)) {} delete i; return true; @@ -380,7 +407,7 @@ namespace cds { template bool find( Q* val, Compare cmp) { - iterator * i = new iterator( m_pHead ); + iterator * i = new iterator( list_head_node ); while (i->current_node->next.load() != nullptr ) { value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); int const nCmp = cmp( *val , *nVal ); @@ -389,7 +416,7 @@ namespace cds { delete i; return true; } - else if ( nCmp > 0 ){ + else if ( nCmp < 0 ){ delete i; return false; } @@ -411,7 +438,7 @@ namespace cds { bool empty() { /*std::cout << "hello from empty" << std::endl;*/ - iterator * i = new iterator(m_pHead); + iterator * i = new iterator(list_head_node); if ( i->next() ) { // if next is not exist() container is empty() @@ -432,7 +459,7 @@ namespace cds { */ void print_all_by_iterator(){ - iterator * i = new iterator(m_pHead); + iterator * i = new iterator(list_head_node); std::cout << "----------start print by iterator---------------" << std::endl; while(i->current_node->next.load() != nullptr){ @@ -448,7 +475,7 @@ namespace cds { void print_all_by_link(){ std::cout << "----------start print by link---------------" << std::endl; - node_type * next_node = m_pHead.load(); + node_type * next_node = list_head_node.load(); node_type * next_aux_node; int number = 0; do{ @@ -472,8 +499,8 @@ namespace cds { void init_list() { node_type * aux_temp = new node_type(); - m_pHead.store(new node_type); - m_pHead.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + list_head_node.store(new node_type); + list_head_node.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node m_pTail.store(new node_type); aux_temp->next.store( m_pTail, memory_model::memory_order_seq_cst ); m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr @@ -515,15 +542,14 @@ namespace cds { */ void append(int * number){ - node_type * next_node = m_pHead.load(); + node_type * next_node = list_head_node.load(); node_type * next_aux_node; //std::cout << "iter " << *number << std::endl; do{ next_aux_node = next_node->next.load(); next_node = next_aux_node->next.load(); - //std::cout << "next_aux_node -> " < " <next.load() << std::endl; - //std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; + /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ } while (next_node->next.load() != nullptr); From d3de087c939013b4746129ca58bd2033e562c16b Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 13:58:42 +0300 Subject: [PATCH 23/46] add debug functions --- cds/intrusive/impl/valois_list.h | 156 +++++++++++++----- .../intrusive-list/intrusive_valois_hp.cpp | 48 +++--- 2 files changed, 144 insertions(+), 60 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 24848ef22..9b165e6f2 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -251,8 +251,8 @@ namespace cds { m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr - for(int i = 0 ; inext.load(); + next_node = next_aux_node->next.load(); + /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ + + } while (next_node->next.load() != nullptr); + + //std::cout << number << " -> " << *number << std::endl; + + int * index = new int32_t(number); + //std::cout<< "wtf wtf " <next.store(next_node); + //std::cout << "append 5 " <next.store(new_next_aux_node); + //std::cout << "append 6 " <next.store(new_next_node); + + //std::cout << "finish" << std::endl << std::endl; + } + + void append_in_first(const int& number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node = next_node->next.load(); + + int d = number; + int * index = new int32_t(d); + + node_type * new_next_node = new node_type(index); + node_type * new_next_aux_node = new node_type(); + + new_next_aux_node->next.store(next_aux_node->next.load()); + + new_next_node->next.store(new_next_aux_node); + + next_aux_node->next.store(new_next_node); + + } + + void append_in_position(const int& number, const int& position){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + + int ind = 0; + + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ + ind++; + } while (next_node->next.load() != nullptr && ind < position + 1); + std::cout << "value " <next.store(next_node); + //std::cout << "append 5 " <next.store(new_next_aux_node); + //std::cout << "append 6 " <next.store(new_next_node); + + //std::cout << "finish" << std::endl << std::endl; + + } + + int search(const int& number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + //std::cout << "iter " << *number << std::endl; + int ind = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ + if (number == *(next_node->data.load().ptr())){ + return ind; + } + ind++; + + } while (next_node->next.load() != nullptr); + + return -1; + } + + bool deleted (const int& number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + //std::cout << "iter " << *number << std::endl; + int ind = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ + if (number == *(next_node->data.load().ptr())){ + next_aux_node->next.store(next_node->next.load()->next.load()); + return true; + } + ind++; + + } while (next_node->next.load() != nullptr); + + + return false; + } + private: void init_list() { @@ -534,42 +650,6 @@ namespace cds { return delete_status; } - - - /** - * Debug only - * @param number - */ - - void append(int * number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - //std::cout << "iter " << *number << std::endl; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ - - } while (next_node->next.load() != nullptr); - - //std::cout << number << " -> " << *number << std::endl; - - - int d = *number; - int * index = new int32_t(d); - //std::cout<< "wtf wtf " <next.store(next_node); - //std::cout << "append 5 " <next.store(new_next_aux_node); - //std::cout << "append 6 " <next.store(new_next_node); - - //std::cout << "finish" << std::endl << std::endl; - } }; } diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 646e35f4d..298c5a236 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -67,21 +67,20 @@ namespace { void test_simple_list(List& list) { std::cout << "simple test started " << std::endl; - list.empty(); - list.empty(); - list.empty(); - list.empty(); - list.empty(); - list.empty(); - list.print_all_by_iterator(); + + + /*list.print_all_by_iterator();*/ + + list.append_in_first(3); + list.append_in_position(10000,10); + + std::cout << "search " << list.search(10000) << std::endl; + + list.deleted(10000); + list.print_all_by_iterator(); - int value = 5; - std::cout << "find 5 "<= 0; i--){ ASSERT_TRUE( list.find(i)); list.erase(i); - ASSERT_FALSE(list.find(i)); + //ASSERT_FALSE(list.find(i)); } // test empty method(); - ASSERT_TRUE( list.empty()); + //ASSERT_TRUE( list.empty()); } @@ -148,9 +149,11 @@ namespace { ASSERT_FALSE( list.empty()); } + // test adding in - for ( int i = nSize; i >= 0 ; i-- ) { - ASSERT_TRUE( list.find(i)); + for ( int i = 0; i <= nSize ; i++ ) { + //list.print_all_by_iterator(); + ASSERT_TRUE( list.contains(i)); } @@ -158,19 +161,19 @@ namespace { // delete and contains method for ( int i = nSize; i >= 0 ; i-- ) { - ASSERT_TRUE( list.find(i)); + ASSERT_TRUE( list.contains(i)); list.erase(i); - ASSERT_FALSE(list.find(i)); + //ASSERT_FALSE(list.contains(i)); } // test empty method(); - ASSERT_TRUE( list.empty()); + //ASSERT_TRUE( list.empty()); } template void random_test_list(List& list){ std::cout << "random test started " << std::endl; - int items[10] = {4,7,6,8,2,9,10,1,0,5}; + int items[10] = {4,7,6,8,2,9,3,1,0,5}; //insert for(auto i : items){ @@ -201,6 +204,7 @@ namespace { list_type l(20); test_simple_list(l); +/* list_type l2; test_list(l2); @@ -209,7 +213,7 @@ namespace { list_type l4; random_test_list(l4); - +*/ } } // namespace From fe3313bd93890dd345fda226a83074412c76be9c Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 15:25:07 +0300 Subject: [PATCH 24/46] test complite correctly but not free --- cds/intrusive/impl/valois_list.h | 155 ++++++++---------- .../intrusive-list/intrusive_valois_hp.cpp | 5 +- 2 files changed, 69 insertions(+), 91 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 9b165e6f2..d249b579f 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -72,7 +72,7 @@ namespace cds { friend class iterator; protected: - //template + class iterator { friend class ValoisList; @@ -83,55 +83,13 @@ namespace cds { /*typename gc::Guard m_Guard;*/ bool next() { - //std::cout <<"hello from next "<next == nullptr) { // if tail return false; } - - int * value; - - -// if (prev_node->data.load() != nullptr){ -// value = prev_node->data.load().ptr(); -// std::cout <<"in next 1 "<< *value <data.load() != nullptr){ -// value = current_node->data.load().ptr(); -// std::cout << "current node " << *value <next <data.store(current_node->data.load()); - new_current_node->next.store(current_node->next.load()); - - prev_node = new_current_node; - - new_current_node = new node_type(); - new_current_node->data.store(current_node->next.load()->data.load()); - new_current_node->next.store(current_node->next.load()->next.load()); - - aux_pNode = new_current_node; - + prev_node = current_node; + aux_pNode = current_node->next.load(); current_node = aux_pNode->next.load(); - - - //update_iterator(); - -// if (prev_node->data.load() != nullptr) { -// value = prev_node->data.load().ptr(); -// std::cout << "in next 2 " << *value << std::endl; -// } else{ -// std::cout <<"in next 2 NULL" <next.load()->next.load(); + aux_pNode = node->next.load(); + prev_node = node; +/* aux_pNode->next.store( node->next.load(memory_model::memory_order_seq_cst), memory_model::memory_order_seq_cst @@ -169,7 +127,8 @@ namespace cds { current_node->next.store( tempNode->next.load(), memory_model::memory_order_relaxed); } - update_iterator(); + current_node->next.store(aux_pNode->next.load()); + //update_iterator();*/ } void update_iterator() { @@ -209,6 +168,24 @@ namespace cds { // std::cout << "\t bye update iterator " << std::endl; } + + void print(){ + std::cout << "iterator" << std::endl; + if (current_node->data.load() != nullptr){ + std::cout << "current " << current_node << " value " << *(current_node->data.load().ptr()) << std::endl; + } else{ + std::cout << "current " << current_node << " value " << "NULL" << std::endl; + } + std::cout << "aux " << aux_pNode << std::endl; + if (prev_node->data.load() != nullptr){ + std::cout << "prev " << prev_node << " value " << *(prev_node->data.load().ptr()) << std::endl; + } else{ + std::cout << "prev " << prev_node << " value " << "NULL" << std::endl; + } + + std::cout << "--------------------" << std::endl; + } + iterator &operator++() { iterator temp = *this; next(); @@ -276,76 +253,47 @@ namespace cds { iterator * mIter = new iterator(list_head_node); - /*if(nVal != nullptr){ - int const nCmp = cmp( *nVal , *val ); - if (nCmp > 0){ - bool k = try_insert(mIter, val); - delete mIter; - return k; - } - }*/ - - while (true) { value_type * nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); if(nVal == nullptr){ - append(val); + try_insert(mIter, val); delete mIter; return true; } - - int const nCmp = cmp(*val, *nVal); - /*std::cout << "search_insert : finded value "<< *nVal << std::endl; - std::cout << "search_insert : inserted value "<< *val << std::endl; - std::cout << "search_insert : compare index "<< nCmp << std::endl; -*/ + if (nCmp == 0) { delete mIter; return true; } else if (nCmp < 0) { if (*val == 3 ){ std::cout << "here "<<*val<< " " << *nVal << std::endl; - print_all_by_iterator(); + print_all_pointers(); } bool k = try_insert(mIter, val); if (*val == 3 ){ print_all_by_iterator(); std::cout << std::endl<< std::endl<< std::endl<< std::endl<< std::endl; } - delete mIter; return k; } else { mIter->next(); } } - std::cout << "here "<< std::endl; - bool k = try_insert(mIter, val); - delete mIter; - return k; } bool try_insert(iterator *i, value_type * val) { //i->update_iterator(); - //std::cout << "try insert "<< *val << std::endl; node_type *real_node = new node_type(val); node_type *aux_node = new node_type(); if(*val ==3){ - int * prev = i->prev_node->data.load().ptr(); - std::cout << "try insert inserted "<< *val << std::endl; - std::cout << "try insert current "<< *(i->current_node->data.load().ptr()) << std::endl; - //std::cout << "try insert prev "<< i->prev_node->data.load().ptr() << std::endl; - if (i->aux_pNode == nullptr){ - std::cout << "aux is null" << std::endl; - } - if (prev != nullptr){ - std::cout << "prev data " <<*prev << std::endl; - } + i->print(); } + real_node->next = aux_node; aux_node->next = i->current_node; @@ -356,6 +304,12 @@ namespace cds { memory_model::memory_order_seq_cst ); + i->prev_node = real_node; + + if(*val ==3){ + i->print(); + } + //i->update_iterator(); return true; } @@ -495,6 +449,25 @@ namespace cds { std::cout << "----------finish print by link---------------" << std::endl; } + + void print_all_pointers(){ + node_type * selected_node = list_head_node.load(); + int number = 0; + std::string type; + do{ + + if (selected_node->data.load() == nullptr) + std::cout << number << "\t" << selected_node << "\t AUX" << std::endl; + else + std::cout << number << "\t" << selected_node << "\t " << *(selected_node->data.load().ptr()) << std::endl; + + number++; + + selected_node = selected_node->next.load(); + } while (selected_node != nullptr); + + } + void append(int& number){ node_type * next_node = list_head_node.load(); node_type * next_aux_node; @@ -505,7 +478,7 @@ namespace cds { /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ - } while (next_node->next.load() != nullptr); + } while (next_aux_node->next != nullptr && next_node->next.load() != nullptr); //std::cout << number << " -> " << *number << std::endl; @@ -638,7 +611,13 @@ namespace cds { bool try_erase(iterator *i) { - node_type *for_delete = i->current_node; + i->current_node = i->current_node->next.load()->next.load(); + i->aux_pNode = i->current_node; + + /* add delete */ + + + /*node_type *for_delete = i->current_node; node_type *adjacent = i->current_node->next; bool delete_status = i->aux_pNode->next @@ -647,8 +626,8 @@ namespace cds { adjacent, memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst); - - return delete_status; + */ + return true; } }; diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 298c5a236..3a3544f6a 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -68,7 +68,6 @@ namespace { { std::cout << "simple test started " << std::endl; - /*list.print_all_by_iterator();*/ list.append_in_first(3); @@ -201,10 +200,10 @@ namespace { struct traits: public ci::valois_list::traits{}; typedef ci::ValoisList< gc_type, int, traits > list_type; + list_type l(20); test_simple_list(l); -/* list_type l2; test_list(l2); @@ -213,7 +212,7 @@ namespace { list_type l4; random_test_list(l4); -*/ + } } // namespace From 253489f2141f367d17bb8ba6bfce67710b4958b7 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 16:29:03 +0300 Subject: [PATCH 25/46] update iterator work correctly --- cds/intrusive/impl/valois_list.h | 34 +++++-------------- .../intrusive-list/intrusive_valois_hp.cpp | 14 ++++---- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index d249b579f..aa1a4fb99 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -88,8 +88,8 @@ namespace cds { } prev_node = current_node; aux_pNode = current_node->next.load(); - current_node = aux_pNode->next.load(); - //update_iterator(); + //current_node = aux_pNode->next.load(); + update_iterator(); return true; } @@ -105,7 +105,7 @@ namespace cds { // node - only m_Head iterator( node_type * node) { - current_node = node->next.load()->next.load(); + //current_node = node->next.load()->next.load(); aux_pNode = node->next.load(); prev_node = node; /* @@ -127,8 +127,8 @@ namespace cds { current_node->next.store( tempNode->next.load(), memory_model::memory_order_relaxed); } - current_node->next.store(aux_pNode->next.load()); - //update_iterator();*/ + current_node->next.store(aux_pNode->next.load());*/ + update_iterator(); } void update_iterator() { @@ -136,17 +136,11 @@ namespace cds { if (aux_pNode->next == current_node) { return; } - int * data; node_type * p = aux_pNode; node_type * n = p->next.load(atomics::memory_order_seq_cst); - data = n->next.load()->data.load().ptr(); - //std::cout << "\t data 1 is "<< (n->data.load().ptr()) << " -> " << data << std::endl; - int tmp = 0; - while ( n->next != nullptr && n->data == nullptr) { //while not last and is aux node - tmp++; prev_node->next.compare_exchange_strong( p, @@ -158,14 +152,8 @@ namespace cds { n = p->next.load(atomics::memory_order_seq_cst); } -// std::cout << "\t count in while " <data.load().ptr(); -// std::cout << "\t data 2 is " << data << std::endl; - aux_pNode = p; current_node = n; -// std::cout << "\t bye update iterator " << std::endl; } @@ -286,7 +274,7 @@ namespace cds { } bool try_insert(iterator *i, value_type * val) { - //i->update_iterator(); + i->update_iterator(); node_type *real_node = new node_type(val); node_type *aux_node = new node_type(); @@ -310,7 +298,7 @@ namespace cds { i->print(); } - //i->update_iterator(); + i->update_iterator(); return true; } @@ -360,7 +348,7 @@ namespace cds { template - bool find( Q* val, Compare cmp) { + bool contains( Q* val, Compare cmp) { iterator * i = new iterator( list_head_node ); while (i->current_node->next.load() != nullptr ) { value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); @@ -382,12 +370,8 @@ namespace cds { return false; } - bool find(value_type &val) { - return find( &val, key_comparator() ); - } - bool contains(value_type &val) { - return find( &val, key_comparator() ); + return contains( &val, key_comparator() ); } bool empty() { diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 3a3544f6a..ba936f2ea 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -103,9 +103,9 @@ namespace { // insert and contains method for ( int i = 0; i <= nSize; i++ ) { int * index = new int32_t(i); - ASSERT_FALSE(list.find(*index)); + ASSERT_FALSE(list.contains(*index)); list.insert(*index); - ASSERT_TRUE( list.find(*index)); + ASSERT_TRUE( list.contains(*index)); ASSERT_FALSE( list.empty()); } @@ -114,7 +114,7 @@ namespace { // test adding in for ( int i = 0; i <= nSize; i++ ) { - ASSERT_TRUE( list.find(i)); + ASSERT_TRUE( list.contains(i)); } @@ -122,9 +122,9 @@ namespace { // delete and contains method for(int i = nSize; i >= 0; i--){ - ASSERT_TRUE( list.find(i)); + ASSERT_TRUE( list.contains(i)); list.erase(i); - //ASSERT_FALSE(list.find(i)); + //ASSERT_FALSE(list.contains(i)); } // test empty method(); //ASSERT_TRUE( list.empty()); @@ -142,9 +142,9 @@ namespace { // insert and contains method for ( int i = nSize; i >= 0 ; i-- ) { int * index = new int32_t(i); - ASSERT_FALSE(list.find(*index)); + ASSERT_FALSE(list.contains(*index)); list.insert(*index); - ASSERT_TRUE( list.find(*index)); + ASSERT_TRUE( list.contains(*index)); ASSERT_FALSE( list.empty()); } From c5e5f82081ff8c326192bc5a738a12777f2f1d6f Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 17:04:58 +0300 Subject: [PATCH 26/46] format code --- cds/intrusive/impl/valois_list.h | 68 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index aa1a4fb99..e75164943 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -102,12 +102,12 @@ namespace cds { iterator() : current_node(nullptr), aux_pNode(nullptr), prev_node(nullptr) {} - // node - only m_Head + // node - only Head iterator( node_type * node) { - //current_node = node->next.load()->next.load(); - aux_pNode = node->next.load(); prev_node = node; + aux_pNode = node->next.load(); + /* aux_pNode->next.store( node->next.load(memory_model::memory_order_seq_cst), @@ -132,7 +132,6 @@ namespace cds { } void update_iterator() { - //std::cout << "\t in update iterator " << std::endl; if (aux_pNode->next == current_node) { return; } @@ -237,36 +236,38 @@ namespace cds { */ template - bool search_insert(node_type * start_node /*it not used*/, Q* val, Compare cmp) { + bool search_insert(Q* val, Compare cmp) { iterator * mIter = new iterator(list_head_node); while (true) { - value_type * nVal = mIter->current_node->data.load( memory_model::memory_order_seq_cst ).ptr(); + value_type * nVal = mIter->current_node + ->data.load( + memory_model::memory_order_seq_cst + ).ptr(); if(nVal == nullptr){ + // for last node; try_insert(mIter, val); - delete mIter; return true; } + int const nCmp = cmp(*val, *nVal); if (nCmp == 0) { delete mIter; return true; } else if (nCmp < 0) { - if (*val == 3 ){ - std::cout << "here "<<*val<< " " << *nVal << std::endl; - print_all_pointers(); - } bool k = try_insert(mIter, val); - if (*val == 3 ){ - print_all_by_iterator(); - std::cout << std::endl<< std::endl<< std::endl<< std::endl<< std::endl; - } delete mIter; - return k; + if (k){ + return k; + } else{ + // find again; + mIter = new iterator(list_head_node); + } + } else { mIter->next(); } @@ -274,13 +275,9 @@ namespace cds { } bool try_insert(iterator *i, value_type * val) { - i->update_iterator(); node_type *real_node = new node_type(val); node_type *aux_node = new node_type(); - if(*val ==3){ - i->print(); - } real_node->next = aux_node; aux_node->next = i->current_node; @@ -292,19 +289,15 @@ namespace cds { memory_model::memory_order_seq_cst ); - i->prev_node = real_node; + /*i->prev_node = real_node;*/ - if(*val ==3){ - i->print(); - } - i->update_iterator(); - return true; + return insert_status; } bool insert( value_type &val ){ - return search_insert( list_head_node, &val, key_comparator() ); + return search_insert(&val, key_comparator() ); } @@ -322,23 +315,29 @@ namespace cds { int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ - // hard delete operation - //std::cout << "trying delete " << *val << std::endl; - while (!try_erase(i)) {} + + bool result = try_erase(i); delete i; - return true; + if (result){ + return true; + } + else{ + //run again + i = new iterator( list_head_node ); + } } else if ( nCmp > 0 ){ + // not found delete i; - return true; + return false; } else{ i->next(); } } - + // not found delete i; - return true; + return false; } bool erase(value_type val){ @@ -375,7 +374,6 @@ namespace cds { } bool empty() { - /*std::cout << "hello from empty" << std::endl;*/ iterator * i = new iterator(list_head_node); if ( i->next() ) { From e1f0109c4075d534174fca744d6c98adb2e93a7a Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 17:28:55 +0300 Subject: [PATCH 27/46] update erase --- cds/intrusive/impl/valois_list.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index e75164943..0ac6ceb0a 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -593,9 +593,21 @@ namespace cds { bool try_erase(iterator *i) { + node_type *d = i->current_node; + + node_type *n = i->current_node->next.load(); + bool r = i->aux_pNode->next.compare_exchange_strong(d, n); + + if (!r){ + return false; + } + + /* + node_type *d = i->current_node; + i->current_node = i->current_node->next.load()->next.load(); i->aux_pNode = i->current_node; - + */ /* add delete */ From a29ec7827e0a433da6dc655a4be1c00ffa116ed5 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 17:31:46 +0300 Subject: [PATCH 28/46] update test --- cds/intrusive/impl/valois_list.h | 4 +- .../intrusive-list/intrusive_valois_hp.cpp | 39 +++++++------------ 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 0ac6ceb0a..f08a87cc0 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -57,7 +57,7 @@ namespace cds { typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics - /*typedef typename gc::template guarded_ptr guarded_ptr; */ ///< Guarded pointer + typedef typename gc::template guarded_ptr guarded_ptr; ///< Guarded pointer static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm @@ -80,7 +80,7 @@ namespace cds { node_type * current_node; // Valois target - current real node node_type * aux_pNode; // Valois pre_aux - aux node before the real node node_type * prev_node; // Valois pre_cell - real node before the current real node - /*typename gc::Guard m_Guard;*/ + typename gc::Guard m_Guard; bool next() { if (current_node->next == nullptr) { // if tail diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index ba936f2ea..c38cc6e24 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -68,19 +68,14 @@ namespace { { std::cout << "simple test started " << std::endl; - /*list.print_all_by_iterator();*/ - list.append_in_first(3); list.append_in_position(10000,10); std::cout << "search " << list.search(10000) << std::endl; - list.deleted(10000); + list.deleted(50); list.print_all_by_iterator(); - - - } template @@ -110,24 +105,19 @@ namespace { } - //list.print_all_by_iterator(); - // test adding in for ( int i = 0; i <= nSize; i++ ) { ASSERT_TRUE( list.contains(i)); } - - //list.print_all_by_link(); - // delete and contains method - for(int i = nSize; i >= 0; i--){ + for ( int i = 0; i <= nSize; i++ ) { ASSERT_TRUE( list.contains(i)); list.erase(i); - //ASSERT_FALSE(list.contains(i)); + ASSERT_FALSE(list.contains(i)); } // test empty method(); - //ASSERT_TRUE( list.empty()); + ASSERT_TRUE( list.empty()); } @@ -148,24 +138,19 @@ namespace { ASSERT_FALSE( list.empty()); } - // test adding in for ( int i = 0; i <= nSize ; i++ ) { - //list.print_all_by_iterator(); ASSERT_TRUE( list.contains(i)); } - - //list.print_all_by_link(); - // delete and contains method - for ( int i = nSize; i >= 0 ; i-- ) { + for ( int i = 0; i <= nSize ; i++ ) { ASSERT_TRUE( list.contains(i)); list.erase(i); - //ASSERT_FALSE(list.contains(i)); + ASSERT_FALSE(list.contains(i)); } // test empty method(); - //ASSERT_TRUE( list.empty()); + ASSERT_TRUE( list.empty()); } @@ -177,7 +162,9 @@ namespace { //insert for(auto i : items){ int * index = new int32_t(i); + ASSERT_FALSE( list.contains(i)); ASSERT_TRUE(list.insert(*index)); + ASSERT_TRUE( list.contains(i)); } list.print_all_by_iterator(); @@ -188,10 +175,12 @@ namespace { } //delete - for(auto i : items){ - ASSERT_TRUE(list.erase(i)); + for ( int i = 0; i <= 9 ; i++ ) { + ASSERT_TRUE( list.contains(i)); + list.erase(i); + ASSERT_FALSE( list.contains(i)); } - + list.print_all_by_iterator(); } From 08a22ee1ad29b25fe0a4690500ba1c9e2ba2e084 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 19:35:35 +0300 Subject: [PATCH 29/46] update licency --- cds/intrusive/impl/valois_list.h | 4 +++- cds/intrusive/valois_list_dhp.h | 32 +++++++++++++++++++++++++++++--- cds/intrusive/valois_list_hp.h | 32 +++++++++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index f08a87cc0..74e83a46b 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -57,6 +57,8 @@ namespace cds { typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics + + /* not used */ typedef typename gc::template guarded_ptr guarded_ptr; ///< Guarded pointer static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm @@ -183,7 +185,7 @@ namespace cds { current_node = second.current_node; aux_pNode = second.aux_pNode; prev_node = second.prev_node; - /*m_Guard.copy(second.m_Guard);*/ + m_Guard.copy(second.m_Guard); return *this; } diff --git a/cds/intrusive/valois_list_dhp.h b/cds/intrusive/valois_list_dhp.h index 57dc366dc..3625fc31d 100644 --- a/cds/intrusive/valois_list_dhp.h +++ b/cds/intrusive/valois_list_dhp.h @@ -1,6 +1,32 @@ -// -// Created by denis on 06.01.18. -// +/* + 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_INTRUSIVE_VALOIS_LIST_DHP_H #define CDSLIB_INTRUSIVE_VALOIS_LIST_DHP_H diff --git a/cds/intrusive/valois_list_hp.h b/cds/intrusive/valois_list_hp.h index 2e0d3642e..300612cf0 100644 --- a/cds/intrusive/valois_list_hp.h +++ b/cds/intrusive/valois_list_hp.h @@ -1,6 +1,32 @@ -// -// Created by denis on 06.01.18. -// +/* + 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_INTRUSIVE_VALOIS_LIST_HP_H #define CDSLIB_INTRUSIVE_VALOIS_LIST_HP_H From 4aae4995aefb7d3a7448e132d2e33695f5af7c30 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 20:41:20 +0300 Subject: [PATCH 30/46] clear code and fix destroy --- cds/intrusive/impl/valois_list.h | 60 ++++++------------- .../intrusive-list/intrusive_valois_hp.cpp | 10 +--- 2 files changed, 21 insertions(+), 49 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 74e83a46b..bd8fba9a2 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -157,7 +157,7 @@ namespace cds { current_node = n; } - +/* void print(){ std::cout << "iterator" << std::endl; if (current_node->data.load() != nullptr){ @@ -173,7 +173,7 @@ namespace cds { } std::cout << "--------------------" << std::endl; - } + }*/ iterator &operator++() { iterator temp = *this; @@ -207,7 +207,7 @@ namespace cds { * DEBUG ONLY * @param number */ - +/* ValoisList(int number) { node_type * aux_temp = new node_type(); list_head_node.store(new node_type); @@ -220,7 +220,7 @@ namespace cds { for(int i = 0 ; inext.load(); next_node = next_aux_node->next.load(); - /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ - } while (next_aux_node->next != nullptr && next_node->next.load() != nullptr); - //std::cout << number << " -> " << *number << std::endl; int * index = new int32_t(number); - //std::cout<< "wtf wtf " <next.store(next_node); - //std::cout << "append 5 " <next.store(new_next_aux_node); - //std::cout << "append 6 " <next.store(new_next_node); - - //std::cout << "finish" << std::endl << std::endl; } void append_in_first(const int& number){ @@ -507,35 +494,27 @@ namespace cds { do{ next_aux_node = next_node->next.load(); next_node = next_aux_node->next.load(); - /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ ind++; } while (next_node->next.load() != nullptr && ind < position + 1); std::cout << "value " <next.store(next_node); - //std::cout << "append 5 " <next.store(new_next_aux_node); - //std::cout << "append 6 " <next.store(new_next_node); - //std::cout << "finish" << std::endl << std::endl; + } int search(const int& number){ node_type * next_node = list_head_node.load(); node_type * next_aux_node; - //std::cout << "iter " << *number << std::endl; int ind = 0; do{ next_aux_node = next_node->next.load(); next_node = next_aux_node->next.load(); - /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ if (number == *(next_node->data.load().ptr())){ return ind; } @@ -549,13 +528,10 @@ namespace cds { bool deleted (const int& number){ node_type * next_node = list_head_node.load(); node_type * next_aux_node; - //std::cout << "iter " << *number << std::endl; int ind = 0; do{ next_aux_node = next_node->next.load(); next_node = next_aux_node->next.load(); - /*std::cout << "next_aux_node -> " < " << next_node << std::endl;*/ if (number == *(next_node->data.load().ptr())){ next_aux_node->next.store(next_node->next.load()->next.load()); return true; @@ -566,7 +542,7 @@ namespace cds { return false; - } + }*/ private: @@ -581,16 +557,18 @@ namespace cds { } void destroy() { - //TODO: fix destroy() - //node_type *tNode = m_Head->next.load(memory_model::memory_order_relaxed); - // - //while (tNode != tNode->next.load(memory_model::memory_order_relaxed)) { - // value_type *pVal = tNode->data.load(memory_model::memory_order_relaxed).ptr(); - // if (pVal) - // erase(tNode); - // node_type *pNext = tNode->next.load(memory_model::memory_order_relaxed); - // tNode = pNext; - //} + node_type * tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); + + while (tNode->next.load(memory_model::memory_order_relaxed) != nullptr) { + value_type * pVal = tNode->data.load(memory_model::memory_order_relaxed).ptr(); + if (pVal) { + + erase(*pVal); + + tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); + } + tNode = tNode->next.load(memory_model::memory_order_relaxed); + } } bool try_erase(iterator *i) { diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index c38cc6e24..e71655b16 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -81,7 +81,6 @@ namespace { template void test_list(List& list) { - std::cout << "simple middle started " << std::endl; /** * 1) testing method is empty * 2) test adding 10 element in the container @@ -123,7 +122,6 @@ namespace { template void revert_test_list(List& list){ - std::cout << "revert test started " << std::endl; ASSERT_TRUE( list.empty()); static const size_t nSize = 20; @@ -156,7 +154,6 @@ namespace { template void random_test_list(List& list){ - std::cout << "random test started " << std::endl; int items[10] = {4,7,6,8,2,9,3,1,0,5}; //insert @@ -167,8 +164,6 @@ namespace { ASSERT_TRUE( list.contains(i)); } - list.print_all_by_iterator(); - //contains for(auto i : items){ ASSERT_TRUE(list.contains(i)); @@ -180,7 +175,6 @@ namespace { list.erase(i); ASSERT_FALSE( list.contains(i)); } - list.print_all_by_iterator(); } @@ -189,10 +183,10 @@ namespace { struct traits: public ci::valois_list::traits{}; typedef ci::ValoisList< gc_type, int, traits > list_type; - +/* list_type l(20); test_simple_list(l); - +*/ list_type l2; test_list(l2); From 67655b902db86734c526b81100f7f4a2ad8f232e Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Wed, 10 Jan 2018 21:56:45 +0300 Subject: [PATCH 31/46] Guarded added --- cds/intrusive/impl/valois_list.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index bd8fba9a2..e650c603b 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -57,9 +57,7 @@ namespace cds { typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics - - /* not used */ - typedef typename gc::template guarded_ptr guarded_ptr; ///< Guarded pointer + typename gc::Guard m_Guard; static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm @@ -155,6 +153,8 @@ namespace cds { aux_pNode = p; current_node = n; + + m_Guard.protect( current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); } /* @@ -243,6 +243,9 @@ namespace cds { iterator * mIter = new iterator(list_head_node); while (true) { + + m_Guard.protect( mIter->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); + value_type * nVal = mIter->current_node ->data.load( memory_model::memory_order_seq_cst @@ -318,6 +321,8 @@ namespace cds { if ( nCmp == 0 ){ + gc::template retire( nVal ); + bool result = try_erase(i); delete i; if (result){ @@ -352,6 +357,9 @@ namespace cds { bool contains( Q* val, Compare cmp) { iterator * i = new iterator( list_head_node ); while (i->current_node->next.load() != nullptr ) { + + m_Guard.protect( i->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); + value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); int const nCmp = cmp( *val , *nVal ); @@ -557,6 +565,8 @@ namespace cds { } void destroy() { + m_Guard.clear(); + node_type * tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); while (tNode->next.load(memory_model::memory_order_relaxed) != nullptr) { From d67d86d8116e651b86ea4d8338290754eaa12415 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 10 Jan 2018 22:15:40 +0300 Subject: [PATCH 32/46] format code --- cds/intrusive/impl/valois_list.h | 260 +++---------------------------- 1 file changed, 18 insertions(+), 242 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index e650c603b..86fa4a6e2 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -87,7 +87,7 @@ namespace cds { return false; } prev_node = current_node; - aux_pNode = current_node->next.load(); + aux_pNode = current_node->next.load(atomics::memory_order_relaxed); //current_node = aux_pNode->next.load(); update_iterator(); return true; @@ -108,26 +108,6 @@ namespace cds { prev_node = node; aux_pNode = node->next.load(); -/* - aux_pNode->next.store( - node->next.load(memory_model::memory_order_seq_cst), - memory_model::memory_order_seq_cst - ); - - prev_node->next.store( - node, - memory_model::memory_order_seq_cst - ); - - node_type * tempNode = aux_pNode->next.load(); - if ( tempNode->next.load() == nullptr ){ - current_node->next.store(NULL, memory_model::memory_order_seq_cst); - } - else{ - current_node->next.store( tempNode->next.load(), memory_model::memory_order_relaxed); - } - - current_node->next.store(aux_pNode->next.load());*/ update_iterator(); } @@ -137,7 +117,7 @@ namespace cds { } node_type * p = aux_pNode; - node_type * n = p->next.load(atomics::memory_order_seq_cst); + node_type * n = p->next.load(atomics::memory_order_acquire); while ( n->next != nullptr && n->data == nullptr) { //while not last and is aux node @@ -148,7 +128,7 @@ namespace cds { atomics::memory_order_seq_cst ); p = n; - n = p->next.load(atomics::memory_order_seq_cst); + n = p->next.load(atomics::memory_order_acquire); } aux_pNode = p; @@ -157,23 +137,6 @@ namespace cds { m_Guard.protect( current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); } -/* - void print(){ - std::cout << "iterator" << std::endl; - if (current_node->data.load() != nullptr){ - std::cout << "current " << current_node << " value " << *(current_node->data.load().ptr()) << std::endl; - } else{ - std::cout << "current " << current_node << " value " << "NULL" << std::endl; - } - std::cout << "aux " << aux_pNode << std::endl; - if (prev_node->data.load() != nullptr){ - std::cout << "prev " << prev_node << " value " << *(prev_node->data.load().ptr()) << std::endl; - } else{ - std::cout << "prev " << prev_node << " value " << "NULL" << std::endl; - } - - std::cout << "--------------------" << std::endl; - }*/ iterator &operator++() { iterator temp = *this; @@ -203,24 +166,6 @@ namespace cds { init_list(); } - /** - * DEBUG ONLY - * @param number - */ -/* - ValoisList(int number) { - node_type * aux_temp = new node_type(); - list_head_node.store(new node_type); - list_head_node.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node - m_pTail.store(new node_type); - aux_temp->next.store( m_pTail, memory_model::memory_order_seq_cst ); - m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr - - - for(int i = 0 ; icurrent_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); + m_Guard.protect( + mIter->current_node->data, + []( marked_data_ptr ptr ) { return ptr.ptr(); } + ).ptr(); value_type * nVal = mIter->current_node ->data.load( - memory_model::memory_order_seq_cst + atomics::memory_order_acquire ).ptr(); if(nVal == nullptr){ @@ -316,7 +264,7 @@ namespace cds { iterator * i = new iterator( list_head_node ); //search node while (i->current_node->next.load() != nullptr ) { - value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + value_type * nVal = i->current_node->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ @@ -360,7 +308,7 @@ namespace cds { m_Guard.protect( i->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); - value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + value_type * nVal = i->current_node->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ @@ -397,170 +345,15 @@ namespace cds { } -/* - - - - void print_all_by_iterator(){ - iterator * i = new iterator(list_head_node); - - std::cout << "----------start print by iterator---------------" << std::endl; - while(i->current_node->next.load() != nullptr){ - value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << *nVal << std::endl; - i->next(); - } - std::cout << "----------end---------------" << std::endl; - - delete i; - } - - void print_all_by_link(){ - std::cout << "----------start print by link---------------" << std::endl; - - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - int number = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - std::cout << "next_aux_node -> " < " <next.load() << std::endl; - std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; - if (next_node->next){ - value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - value_type * nVala = next_aux_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << number << " aux -> " << nVala << " -> "<< std::endl; - std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; - } - number++; - } while (next_node->next != nullptr); - std::cout << "----------finish print by link---------------" << std::endl; - } - - - void print_all_pointers(){ - node_type * selected_node = list_head_node.load(); - int number = 0; - std::string type; - do{ - - if (selected_node->data.load() == nullptr) - std::cout << number << "\t" << selected_node << "\t AUX" << std::endl; - else - std::cout << number << "\t" << selected_node << "\t " << *(selected_node->data.load().ptr()) << std::endl; - - number++; - - selected_node = selected_node->next.load(); - } while (selected_node != nullptr); - - } - - void append(int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - } while (next_aux_node->next != nullptr && next_node->next.load() != nullptr); - - - int * index = new int32_t(number); - node_type * new_next_node = new node_type(index); - node_type * new_next_aux_node = new node_type(); - - new_next_aux_node->next.store(next_node); - new_next_node->next.store(new_next_aux_node); - next_aux_node->next.store(new_next_node); - } - - void append_in_first(const int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node = next_node->next.load(); - - int d = number; - int * index = new int32_t(d); - - node_type * new_next_node = new node_type(index); - node_type * new_next_aux_node = new node_type(); - - new_next_aux_node->next.store(next_aux_node->next.load()); - - new_next_node->next.store(new_next_aux_node); - - next_aux_node->next.store(new_next_node); - - } - - void append_in_position(const int& number, const int& position){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - - int ind = 0; - - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - ind++; - } while (next_node->next.load() != nullptr && ind < position + 1); - std::cout << "value " <next.store(next_node); - new_next_node->next.store(new_next_aux_node); - next_aux_node->next.store(new_next_node); - - - - } - - int search(const int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - int ind = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - if (number == *(next_node->data.load().ptr())){ - return ind; - } - ind++; - - } while (next_node->next.load() != nullptr); - - return -1; - } - - bool deleted (const int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - int ind = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - if (number == *(next_node->data.load().ptr())){ - next_aux_node->next.store(next_node->next.load()->next.load()); - return true; - } - ind++; - - } while (next_node->next.load() != nullptr); - - - return false; - }*/ - private: void init_list() { node_type * aux_temp = new node_type(); list_head_node.store(new node_type); - list_head_node.load()->next.store( aux_temp, memory_model::memory_order_seq_cst); //link to aux node + list_head_node.load()->next.store( aux_temp, atomics::memory_order_release); //link to aux node m_pTail.store(new node_type); - aux_temp->next.store( m_pTail, memory_model::memory_order_seq_cst ); - m_pTail.load()->next.store(nullptr, memory_model::memory_order_seq_cst ); //link tail to nullptr + aux_temp->next.store( m_pTail, atomics::memory_order_release ); + m_pTail.load()->next.store(nullptr, atomics::memory_order_release ); //link tail to nullptr } @@ -575,7 +368,9 @@ namespace cds { erase(*pVal); - tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); + tNode = list_head_node.load( + atomics::memory_order_release) + ->next.load(memory_model::memory_order_relaxed); } tNode = tNode->next.load(memory_model::memory_order_relaxed); } @@ -585,32 +380,13 @@ namespace cds { node_type *d = i->current_node; - node_type *n = i->current_node->next.load(); - bool r = i->aux_pNode->next.compare_exchange_strong(d, n); + node_type *n = i->current_node->next.load(atomics::memory_order_release); + bool r = i->aux_pNode->next.compare_exchange_strong(d, n, atomics::memory_order_seq_cst); if (!r){ return false; } - /* - node_type *d = i->current_node; - - i->current_node = i->current_node->next.load()->next.load(); - i->aux_pNode = i->current_node; - */ - /* add delete */ - - - /*node_type *for_delete = i->current_node; - node_type *adjacent = i->current_node->next; - - bool delete_status = i->aux_pNode->next - .compare_exchange_strong( - for_delete, - adjacent, - memory_model::memory_order_seq_cst, - memory_model::memory_order_seq_cst); - */ return true; } }; From 0718da408fcd994a736e2ccc274135fd10157c07 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Fri, 12 Jan 2018 10:52:37 +0300 Subject: [PATCH 33/46] local Guard --- cds/intrusive/impl/valois_list.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index e650c603b..ddcea0792 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -34,9 +34,6 @@ #include #include -//CRITICAL: cheak all functions use safe read/write -//CRITICAL: cheak nullptr/NULL values for aux, Head, Tail nodes - namespace cds { namespace intrusive { @@ -57,8 +54,6 @@ namespace cds { typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics - typename gc::Guard m_Guard; - static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm protected: @@ -239,7 +234,7 @@ namespace cds { template bool search_insert(Q* val, Compare cmp) { - + typename gc::Guard m_Guard; iterator * mIter = new iterator(list_head_node); while (true) { @@ -355,6 +350,7 @@ namespace cds { template bool contains( Q* val, Compare cmp) { + typename gc::Guard m_Guard; iterator * i = new iterator( list_head_node ); while (i->current_node->next.load() != nullptr ) { @@ -565,6 +561,7 @@ namespace cds { } void destroy() { + typename gc::Guard m_Guard; m_Guard.clear(); node_type * tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); From ce2b3404704724419a039f8401b48b6c075335e0 Mon Sep 17 00:00:00 2001 From: MagisterDemens Date: Sat, 13 Jan 2018 21:28:49 +0300 Subject: [PATCH 34/46] local Guard --- cds/intrusive/impl/valois_list.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 86fa4a6e2..573585ab4 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -34,9 +34,6 @@ #include #include -//CRITICAL: cheak all functions use safe read/write -//CRITICAL: cheak nullptr/NULL values for aux, Head, Tail nodes - namespace cds { namespace intrusive { @@ -57,8 +54,6 @@ namespace cds { typedef typename traits::node_allocator node_allocator; ///< Node allocator typedef typename traits::stat stat; ///< Internal statistics - typename gc::Guard m_Guard; - static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 4; ///< Count of hazard pointer required for the algorithm protected: @@ -184,7 +179,7 @@ namespace cds { template bool search_insert(Q* val, Compare cmp) { - + typename gc::Guard m_Guard; iterator * mIter = new iterator(list_head_node); while (true) { @@ -303,6 +298,7 @@ namespace cds { template bool contains( Q* val, Compare cmp) { + typename gc::Guard m_Guard; iterator * i = new iterator( list_head_node ); while (i->current_node->next.load() != nullptr ) { @@ -354,10 +350,10 @@ namespace cds { m_pTail.store(new node_type); aux_temp->next.store( m_pTail, atomics::memory_order_release ); m_pTail.load()->next.store(nullptr, atomics::memory_order_release ); //link tail to nullptr - } void destroy() { + typename gc::Guard m_Guard; m_Guard.clear(); node_type * tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); From 8c1f6d43b7a96e4448e7e9d74dd5484dd37cc495 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 14 Jan 2018 08:58:52 +0300 Subject: [PATCH 35/46] add base for stress tests --- cds/intrusive/impl/valois_list.h | 4 +- .../intrusive-list/intrusive_valois_hp.cpp | 58 +++++++++++++++++-- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 573585ab4..f141d3dc7 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -377,11 +377,13 @@ namespace cds { node_type *d = i->current_node; node_type *n = i->current_node->next.load(atomics::memory_order_release); - bool r = i->aux_pNode->next.compare_exchange_strong(d, n, atomics::memory_order_seq_cst); + bool r = i->aux_pNode->next.compare_exchange_strong(d, n->next.load(), atomics::memory_order_seq_cst); if (!r){ return false; } + delete d; + delete n; return true; } diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index e71655b16..747a7bdde 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -30,6 +30,7 @@ #include "test_intrusive_list_hp.h" #include +#include namespace { namespace ci = cds::intrusive; @@ -177,16 +178,59 @@ namespace { } } + struct traits: public ci::valois_list::traits{}; + /*typedef ci::ValoisList< gc_type, int, traits > list_stress_type;*/ + typedef ci::ValoisList< gc_type, int, traits > list_type; + + struct val_and_id{ + std::thread::id thread_id; + int value; + + val_and_id(const std::thread::id & thread__id, const int & number){ + thread_id = thread__id; + value = number; + } + }; + + typedef ci::ValoisList< gc_type, val_and_id, traits > list_stress_type; + + + + template + void test_thread(List& list){ + list.empty(); + for (int key=0; key < 20000000; ++key ) { + int input = key;//new val_and_id(std::this_thread::get_id(),key); + + list.insert(input); + list.erase(input); + } + list.empty(); + } + + void stress_test_list(){ + std::cout << "test started" << std::endl; + list_type lst; + + std::thread::id this_id = std::this_thread::get_id(); + std::cout << this_id << std::endl; + //std::thread thr(test_thread,std::ref(lst)); + //std::thread thr([&]{ lst.empty(); }); + //thr.join(); + + /*auto aaa = std::thread( std::bind(test_thread,lst) ); + aaa.join();*/ + for (int i = 0;i<10;i++){ + test_thread(lst); + } + } TEST_F( IntrusiveValoisList_HP, base_hook ) { - struct traits: public ci::valois_list::traits{}; - typedef ci::ValoisList< gc_type, int, traits > list_type; -/* - list_type l(20); - test_simple_list(l); -*/ + struct traits: public ci::valois_list::traits{}; + + list_type l2; test_list(l2); @@ -196,6 +240,8 @@ namespace { list_type l4; random_test_list(l4); + stress_test_list(); + } } // namespace From 8bf69b8dd7164e954c9e80cfad06f2d0e1f78c58 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 15 Jan 2018 15:45:58 +0300 Subject: [PATCH 36/46] update test --- .../intrusive-list/intrusive_valois_hp.cpp | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 747a7bdde..a94ff9d82 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -199,9 +199,11 @@ namespace { template void test_thread(List& list){ list.empty(); - for (int key=0; key < 20000000; ++key ) { - int input = key;//new val_and_id(std::this_thread::get_id(),key); + std::thread::id this_id = std::this_thread::get_id(); + std::cout << this_id << std::endl; + for (int key=0; key < 2; ++key ) { + int input = key; list.insert(input); list.erase(input); } @@ -214,15 +216,29 @@ namespace { std::thread::id this_id = std::this_thread::get_id(); std::cout << this_id << std::endl; - //std::thread thr(test_thread,std::ref(lst)); - //std::thread thr([&]{ lst.empty(); }); - //thr.join(); - - /*auto aaa = std::thread( std::bind(test_thread,lst) ); - aaa.join();*/ - for (int i = 0;i<10;i++){ - test_thread(lst); - } + + std::thread thr(test_thread,std::ref(lst)); + std::thread thr1(test_thread,std::ref(lst)); + std::thread thr2(test_thread,std::ref(lst)); + std::thread thr3(test_thread,std::ref(lst)); + std::thread thr4(test_thread,std::ref(lst)); + std::thread thr5(test_thread,std::ref(lst)); + std::thread thr6(test_thread,std::ref(lst)); + std::thread thr7(test_thread,std::ref(lst)); + std::thread thr8(test_thread,std::ref(lst)); + std::thread thr9(test_thread,std::ref(lst)); + + thr.join(); + thr1.join(); + thr2.join(); + thr3.join(); + thr4.join(); + thr5.join(); + thr6.join(); + thr7.join(); + thr8.join(); + thr9.join(); + } TEST_F( IntrusiveValoisList_HP, base_hook ) @@ -230,7 +246,7 @@ namespace { struct traits: public ci::valois_list::traits{}; - +/* list_type l2; test_list(l2); @@ -238,7 +254,7 @@ namespace { revert_test_list(l3); list_type l4; - random_test_list(l4); + random_test_list(l4);*/ stress_test_list(); From 59f93d16f54c9fc2590602c022d98724ed708b2f Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 18 Jan 2018 02:31:26 +0300 Subject: [PATCH 37/46] stress test pass with memory leap --- cds/intrusive/impl/valois_list.h | 187 ++++++++++++++++-- .../intrusive-list/intrusive_valois_hp.cpp | 65 +++--- 2 files changed, 202 insertions(+), 50 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index f141d3dc7..fd394030b 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -75,14 +75,20 @@ namespace cds { node_type * current_node; // Valois target - current real node node_type * aux_pNode; // Valois pre_aux - aux node before the real node node_type * prev_node; // Valois pre_cell - real node before the current real node - typename gc::Guard m_Guard; + typename gc::Guard current_guard; + typename gc::Guard prev_guard; + typename gc::Guard aux_guard; bool next() { - if (current_node->next == nullptr) { // if tail + if (current_node->next.load() == nullptr) { // if tail + current_guard.clear(); + prev_guard.clear(); + aux_guard.clear(); return false; } - prev_node = current_node; - aux_pNode = current_node->next.load(atomics::memory_order_relaxed); + prev_node = current_guard.assign(current_node); + aux_pNode = aux_guard.assign(current_node->next.load(atomics::memory_order_relaxed)); + //current_node = aux_pNode->next.load(); update_iterator(); return true; @@ -124,12 +130,13 @@ namespace cds { ); p = n; n = p->next.load(atomics::memory_order_acquire); + } - aux_pNode = p; - current_node = n; + aux_pNode = aux_guard.assign(p); + current_node = current_guard.assign(n); - m_Guard.protect( current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); + //m_Guard.protect( current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); } @@ -143,10 +150,27 @@ namespace cds { current_node = second.current_node; aux_pNode = second.aux_pNode; prev_node = second.prev_node; - m_Guard.copy(second.m_Guard); + return *this; } + + void print(){ + std::cout << "iterator" << std::endl; + if (current_node->data.load() != nullptr){ + std::cout << "current " << current_node << " value " << *(current_node->data.load().ptr()) << std::endl; + } else{ + std::cout << "current " << current_node << " value " << "NULL" << std::endl; + } + std::cout << "aux " << aux_pNode << std::endl; + if (prev_node->data.load() != nullptr){ + std::cout << "prev " << prev_node << " value " << *(prev_node->data.load().ptr()) << std::endl; + } else{ + std::cout << "prev " << prev_node << " value " << "NULL" << std::endl; + } + std::cout << "--------------------" << std::endl; + } + bool operator==(const iterator &second) const { return (current_node->data == second.current_node->data); } @@ -184,12 +208,8 @@ namespace cds { while (true) { - m_Guard.protect( - mIter->current_node->data, - []( marked_data_ptr ptr ) { return ptr.ptr(); } - ).ptr(); - value_type * nVal = mIter->current_node + Q * nVal = mIter->current_node ->data.load( atomics::memory_order_acquire ).ptr(); @@ -208,6 +228,7 @@ namespace cds { return true; } else if (nCmp < 0) { bool k = try_insert(mIter, val); + delete mIter; if (k){ return k; @@ -264,8 +285,6 @@ namespace cds { if ( nCmp == 0 ){ - gc::template retire( nVal ); - bool result = try_erase(i); delete i; if (result){ @@ -294,6 +313,9 @@ namespace cds { return erase(&val, key_comparator()); } + bool erase(value_type * val){ + return erase(val, key_comparator()); + } template @@ -302,7 +324,7 @@ namespace cds { iterator * i = new iterator( list_head_node ); while (i->current_node->next.load() != nullptr ) { - m_Guard.protect( i->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); + //m_Guard.protect( i->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); value_type * nVal = i->current_node->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); @@ -340,6 +362,53 @@ namespace cds { } } + void print_all_by_iterator(){ + iterator * i = new iterator(list_head_node); + std::cout << "----------start print by iterator---------------" << std::endl; + while(i->current_node->next.load() != nullptr){ + value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + std::cout << *nVal << std::endl; + i->next(); + } + std::cout << "----------end---------------" << std::endl; + delete i; + } + void print_all_by_link(){ + std::cout << "----------start print by link---------------" << std::endl; + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + int number = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + std::cout << "next_aux_node -> " < " <next.load() << std::endl; + std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; + if (next_node->next){ + value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + value_type * nVala = next_aux_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + std::cout << number << " aux -> " << nVala << " -> "<< std::endl; + std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; + } + number++; + } while (next_node->next != nullptr); + std::cout << "----------finish print by link---------------" << std::endl; + } + void print_all_pointers(){ + node_type * selected_node = list_head_node.load(); + int number = 0; + std::string type; + do{ + if (selected_node->data.load() == nullptr) + std::cout << number << "\t" << selected_node << "\t AUX" << std::endl; + else + std::cout << number << "\t" << selected_node << "\t " << *(selected_node->data.load().ptr()) << std::endl; + number++; + selected_node = selected_node->next.load(); + } while (selected_node != nullptr); + } + + private: @@ -353,8 +422,6 @@ namespace cds { } void destroy() { - typename gc::Guard m_Guard; - m_Guard.clear(); node_type * tNode = list_head_node.load()->next.load(memory_model::memory_order_relaxed); @@ -362,7 +429,7 @@ namespace cds { value_type * pVal = tNode->data.load(memory_model::memory_order_relaxed).ptr(); if (pVal) { - erase(*pVal); + deleted(*pVal); tNode = list_head_node.load( atomics::memory_order_release) @@ -382,11 +449,89 @@ namespace cds { if (!r){ return false; } - delete d; - delete n; + gc::template retire( d ); + gc::template retire( n ); + + /*delete d; + delete n;*/ return true; } + + + + + void append(int& number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + } while (next_aux_node->next != nullptr && next_node->next.load() != nullptr); + int * index = new int32_t(number); + node_type * new_next_node = new node_type(index); + node_type * new_next_aux_node = new node_type(); + new_next_aux_node->next.store(next_node); + new_next_node->next.store(new_next_aux_node); + next_aux_node->next.store(new_next_node); + } + void append_in_first(const int& number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node = next_node->next.load(); + int d = number; + int * index = new int32_t(d); + node_type * new_next_node = new node_type(index); + node_type * new_next_aux_node = new node_type(); + new_next_aux_node->next.store(next_aux_node->next.load()); + new_next_node->next.store(new_next_aux_node); + next_aux_node->next.store(new_next_node); + } + void append_in_position(const int& number, const int& position){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + int ind = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + ind++; + } while (next_node->next.load() != nullptr && ind < position + 1); + std::cout << "value " <next.store(next_node); + new_next_node->next.store(new_next_aux_node); + next_aux_node->next.store(new_next_node); + } + int search(const int& number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + int ind = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + if (number == *(next_node->data.load().ptr())){ + return ind; + } + ind++; + } while (next_node->next.load() != nullptr); + return -1; + } + + bool deleted (const value_type & number){ + node_type * next_node = list_head_node.load(); + node_type * next_aux_node; + int ind = 0; + do{ + next_aux_node = next_node->next.load(); + next_node = next_aux_node->next.load(); + if (number == *(next_node->data.load().ptr())){ + next_aux_node->next.store(next_node->next.load()->next.load()); + return true; + } + ind++; + } while (next_node->next.load() != nullptr); + return false; + } }; } diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index a94ff9d82..e8915ef8f 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -182,6 +182,7 @@ namespace { /*typedef ci::ValoisList< gc_type, int, traits > list_stress_type;*/ typedef ci::ValoisList< gc_type, int, traits > list_type; + struct val_and_id{ std::thread::id thread_id; int value; @@ -190,43 +191,49 @@ namespace { thread_id = thread__id; value = number; } - }; + bool operator == (const val_and_id & rhs)const { + return rhs.value == this->value && rhs.thread_id == this->thread_id; + } + + bool operator < (const val_and_id & rhs)const { + return rhs.value < this->value; + } + }; typedef ci::ValoisList< gc_type, val_and_id, traits > list_stress_type; + template - void test_thread(List& list){ - list.empty(); + void complex_insdel_thread(List& list){ + cds::threading::Manager::attachThread(); std::thread::id this_id = std::this_thread::get_id(); std::cout << this_id << std::endl; - - for (int key=0; key < 2; ++key ) { - int input = key; - list.insert(input); - list.erase(input); + for (int key=0; key < 1000000; ++key ) { + val_and_id * input = new val_and_id(this_id,key); + list.insert(* input); + list.erase(* input); } - list.empty(); + cds::threading::Manager::detachThread(); } - - void stress_test_list(){ - std::cout << "test started" << std::endl; - list_type lst; + void complex_insdel_test(){ + std::cout << "complex test started" << std::endl; + list_stress_type lst; std::thread::id this_id = std::this_thread::get_id(); - std::cout << this_id << std::endl; - - std::thread thr(test_thread,std::ref(lst)); - std::thread thr1(test_thread,std::ref(lst)); - std::thread thr2(test_thread,std::ref(lst)); - std::thread thr3(test_thread,std::ref(lst)); - std::thread thr4(test_thread,std::ref(lst)); - std::thread thr5(test_thread,std::ref(lst)); - std::thread thr6(test_thread,std::ref(lst)); - std::thread thr7(test_thread,std::ref(lst)); - std::thread thr8(test_thread,std::ref(lst)); - std::thread thr9(test_thread,std::ref(lst)); + std::cout << "main threads " << this_id << std::endl; + + std::thread thr(complex_insdel_thread,std::ref(lst)); + std::thread thr1(complex_insdel_thread,std::ref(lst)); + std::thread thr2(complex_insdel_thread,std::ref(lst)); + std::thread thr3(complex_insdel_thread,std::ref(lst)); + std::thread thr4(complex_insdel_thread,std::ref(lst)); + std::thread thr5(complex_insdel_thread,std::ref(lst)); + std::thread thr6(complex_insdel_thread,std::ref(lst)); + std::thread thr7(complex_insdel_thread,std::ref(lst)); + std::thread thr8(complex_insdel_thread,std::ref(lst)); + std::thread thr9(complex_insdel_thread,std::ref(lst)); thr.join(); thr1.join(); @@ -238,7 +245,7 @@ namespace { thr7.join(); thr8.join(); thr9.join(); - + std::cout << "Complex test finished" << std::endl; } TEST_F( IntrusiveValoisList_HP, base_hook ) @@ -246,7 +253,7 @@ namespace { struct traits: public ci::valois_list::traits{}; -/* + list_type l2; test_list(l2); @@ -254,9 +261,9 @@ namespace { revert_test_list(l3); list_type l4; - random_test_list(l4);*/ + random_test_list(l4); - stress_test_list(); + complex_insdel_test(); } From cc152a643a087dd0444674dfde17d06b993db6e6 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 18 Jan 2018 20:22:52 +0300 Subject: [PATCH 38/46] change iterator to local iterator scheme --- cds/intrusive/impl/valois_list.h | 78 +++++++++++++++----------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index fd394030b..43e1f386b 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -105,7 +105,10 @@ namespace cds { // node - only Head iterator( node_type * node) { + set(node); + } + void set(node_type * node){ prev_node = node; aux_pNode = node->next.load(); @@ -204,12 +207,11 @@ namespace cds { template bool search_insert(Q* val, Compare cmp) { typename gc::Guard m_Guard; - iterator * mIter = new iterator(list_head_node); + iterator mIter; + mIter.set(list_head_node); while (true) { - - - Q * nVal = mIter->current_node + Q * nVal = mIter.current_node ->data.load( atomics::memory_order_acquire ).ptr(); @@ -217,42 +219,39 @@ namespace cds { if(nVal == nullptr){ // for last node; try_insert(mIter, val); - delete mIter; return true; } int const nCmp = cmp(*val, *nVal); if (nCmp == 0) { - delete mIter; return true; } else if (nCmp < 0) { bool k = try_insert(mIter, val); - delete mIter; if (k){ return k; } else{ // find again; - mIter = new iterator(list_head_node); + mIter.set(list_head_node); } } else { - mIter->next(); + mIter.next(); } } } - bool try_insert(iterator *i, value_type * val) { + bool try_insert(iterator& i, value_type * val) { node_type *real_node = new node_type(val); node_type *aux_node = new node_type(); real_node->next = aux_node; - aux_node->next = i->current_node; + aux_node->next = i.current_node; - bool insert_status = i->aux_pNode->next.compare_exchange_strong( - i->current_node, + bool insert_status = i.aux_pNode->next.compare_exchange_strong( + i.current_node, real_node, memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst @@ -277,35 +276,33 @@ namespace cds { */ template bool erase(Q* val, Compare cmp) { - iterator * i = new iterator( list_head_node ); + iterator mIter; + mIter.set( list_head_node ); //search node - while (i->current_node->next.load() != nullptr ) { - value_type * nVal = i->current_node->data.load(atomics::memory_order_acquire ).ptr(); + while (mIter.current_node->next.load() != nullptr ) { + value_type * nVal = mIter.current_node->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ - bool result = try_erase(i); - delete i; + bool result = try_erase(mIter); if (result){ return true; } else{ //run again - i = new iterator( list_head_node ); + mIter.set( list_head_node ); } } else if ( nCmp > 0 ){ // not found - delete i; return false; } else{ - i->next(); + mIter.next(); } } // not found - delete i; return false; } @@ -321,27 +318,25 @@ namespace cds { template bool contains( Q* val, Compare cmp) { typename gc::Guard m_Guard; - iterator * i = new iterator( list_head_node ); - while (i->current_node->next.load() != nullptr ) { + iterator mIter; + mIter.set(list_head_node); + while (mIter.current_node->next.load() != nullptr ) { //m_Guard.protect( i->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); - value_type * nVal = i->current_node->data.load(atomics::memory_order_acquire ).ptr(); + value_type * nVal = mIter.current_node->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ - delete i; return true; } else if ( nCmp < 0 ){ - delete i; return false; } else{ - i->next(); + mIter.next(); } } - delete i; return false; } @@ -350,28 +345,27 @@ namespace cds { } bool empty() { - iterator * i = new iterator(list_head_node); + iterator mIter; + mIter.set(list_head_node); - if ( i->next() ) { + if ( mIter.next() ) { // if next is not exist() container is empty() - delete i; return false; } else { - delete i; return true; } } void print_all_by_iterator(){ - iterator * i = new iterator(list_head_node); + iterator mIter; + mIter.set(list_head_node); std::cout << "----------start print by iterator---------------" << std::endl; - while(i->current_node->next.load() != nullptr){ - value_type * nVal = i->current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + while(mIter.current_node->next.load() != nullptr){ + value_type * nVal = mIter.current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); std::cout << *nVal << std::endl; - i->next(); + mIter.next(); } std::cout << "----------end---------------" << std::endl; - delete i; } void print_all_by_link(){ std::cout << "----------start print by link---------------" << std::endl; @@ -439,12 +433,12 @@ namespace cds { } } - bool try_erase(iterator *i) { + bool try_erase(iterator& i) { - node_type *d = i->current_node; + node_type *d = i.current_node; - node_type *n = i->current_node->next.load(atomics::memory_order_release); - bool r = i->aux_pNode->next.compare_exchange_strong(d, n->next.load(), atomics::memory_order_seq_cst); + node_type *n = i.current_node->next.load(atomics::memory_order_release); + bool r = i.aux_pNode->next.compare_exchange_strong(d, n->next.load(), atomics::memory_order_seq_cst); if (!r){ return false; From 538e93c0ba05d6bb8a1e952c442acb775c0a14c3 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 18 Jan 2018 21:44:54 +0300 Subject: [PATCH 39/46] moving to atomik ptr need help with CAS --- cds/intrusive/impl/valois_list.h | 64 ++++++++++---------------------- 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 43e1f386b..1af852c6b 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -72,24 +72,23 @@ namespace cds { friend class ValoisList; protected: - node_type * current_node; // Valois target - current real node - node_type * aux_pNode; // Valois pre_aux - aux node before the real node - node_type * prev_node; // Valois pre_cell - real node before the current real node + atomic_node_ptr current_node; // Valois target - current real node + atomic_node_ptr aux_pNode; // Valois pre_aux - aux node before the real node + atomic_node_ptr prev_node; // Valois pre_cell - real node before the current real node typename gc::Guard current_guard; typename gc::Guard prev_guard; typename gc::Guard aux_guard; bool next() { - if (current_node->next.load() == nullptr) { // if tail + if (current_node.load()->next.load() == nullptr) { // if tail current_guard.clear(); prev_guard.clear(); aux_guard.clear(); return false; } - prev_node = current_guard.assign(current_node); - aux_pNode = aux_guard.assign(current_node->next.load(atomics::memory_order_relaxed)); + prev_node = current_guard.protect(current_node); + aux_pNode = aux_guard.protect(current_node.load()->next); - //current_node = aux_pNode->next.load(); update_iterator(); return true; } @@ -116,7 +115,7 @@ namespace cds { } void update_iterator() { - if (aux_pNode->next == current_node) { + if (aux_pNode.load()->next == current_node) { return; } @@ -125,7 +124,7 @@ namespace cds { while ( n->next != nullptr && n->data == nullptr) { //while not last and is aux node - prev_node->next.compare_exchange_strong( + prev_node.load()->next.compare_exchange_strong( p, n, atomics::memory_order_seq_cst, @@ -143,20 +142,6 @@ namespace cds { } - iterator &operator++() { - iterator temp = *this; - next(); - return temp; - } - - iterator &operator=(iterator &second) { - current_node = second.current_node; - aux_pNode = second.aux_pNode; - prev_node = second.prev_node; - - return *this; - } - void print(){ std::cout << "iterator" << std::endl; @@ -173,14 +158,6 @@ namespace cds { } std::cout << "--------------------" << std::endl; } - - bool operator==(const iterator &second) const { - return (current_node->data == second.current_node->data); - } - - bool operator!=(const iterator &second) const { - return (current_node->data != second.current_node->data); - } }; public: @@ -211,7 +188,7 @@ namespace cds { mIter.set(list_head_node); while (true) { - Q * nVal = mIter.current_node + Q * nVal = mIter.current_node.load() ->data.load( atomics::memory_order_acquire ).ptr(); @@ -248,16 +225,15 @@ namespace cds { node_type *aux_node = new node_type(); real_node->next = aux_node; - aux_node->next = i.current_node; + aux_node->next.store(i.current_node.load()); - bool insert_status = i.aux_pNode->next.compare_exchange_strong( - i.current_node, + bool insert_status = i.aux_pNode.load()->next.compare_exchange_strong( + i.current_node.load(), real_node, memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst ); - /*i->prev_node = real_node;*/ return insert_status; @@ -279,8 +255,8 @@ namespace cds { iterator mIter; mIter.set( list_head_node ); //search node - while (mIter.current_node->next.load() != nullptr ) { - value_type * nVal = mIter.current_node->data.load(atomics::memory_order_acquire ).ptr(); + while (mIter.current_node.load()->next.load() != nullptr ) { + value_type * nVal = mIter.current_node.load()->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ @@ -322,8 +298,6 @@ namespace cds { mIter.set(list_head_node); while (mIter.current_node->next.load() != nullptr ) { - //m_Guard.protect( i->current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); - value_type * nVal = mIter.current_node->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); @@ -360,8 +334,8 @@ namespace cds { iterator mIter; mIter.set(list_head_node); std::cout << "----------start print by iterator---------------" << std::endl; - while(mIter.current_node->next.load() != nullptr){ - value_type * nVal = mIter.current_node->data.load(memory_model::memory_order_seq_cst ).ptr(); + while(mIter.current_node.load()->next.load() != nullptr){ + value_type * nVal = mIter.current_node.load()->data.load(memory_model::memory_order_seq_cst ).ptr(); std::cout << *nVal << std::endl; mIter.next(); } @@ -435,10 +409,10 @@ namespace cds { bool try_erase(iterator& i) { - node_type *d = i.current_node; + node_type *d = i.current_node.load(); - node_type *n = i.current_node->next.load(atomics::memory_order_release); - bool r = i.aux_pNode->next.compare_exchange_strong(d, n->next.load(), atomics::memory_order_seq_cst); + node_type *n = i.current_node.load()->next.load(atomics::memory_order_release); + bool r = i.aux_pNode.load()->next.compare_exchange_strong(d, n->next.load(), atomics::memory_order_seq_cst); if (!r){ return false; From c0338a39399a60096a6de5f6609e7e491271e55d Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 18 Jan 2018 21:51:03 +0300 Subject: [PATCH 40/46] moving to atomik ptr need help with CAS --- cds/intrusive/impl/valois_list.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index fbff5157e..3fa021220 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -135,8 +135,8 @@ namespace cds { } - aux_pNode = aux_guard.assign(p); - current_node = current_guard.assign(n); + aux_pNode.store(p); + current_node.store(n); //m_Guard.protect( current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); } From 0254032149230c6382e471e057313eed83fd49d1 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 18 Jan 2018 22:56:24 +0300 Subject: [PATCH 41/46] fix with marked pointers --- cds/intrusive/impl/valois_list.h | 54 +++++++++---------- .../intrusive-list/intrusive_valois_hp.cpp | 5 +- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 3fa021220..da6b07089 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -86,7 +86,8 @@ namespace cds { aux_guard.clear(); return false; } - prev_node = current_guard.protect(current_node); + prev_guard.copy(current_guard); + prev_node = prev_guard.protect(current_node); aux_pNode = aux_guard.protect(current_node.load()->next); update_iterator(); @@ -118,32 +119,29 @@ namespace cds { if (aux_pNode.load()->next == current_node) { return; } + node_type * new_aux = aux_pNode.load(); + node_type * new_cur = new_aux->next.load(atomics::memory_order_acquire); - node_type * p = aux_pNode; - node_type * n = p->next.load(atomics::memory_order_acquire); - - while ( n->next != nullptr && n->data == nullptr) { //while not last and is aux node + while ( new_cur->next != nullptr && new_cur->data == nullptr) { //while not last and is aux node prev_node.load()->next.compare_exchange_strong( - p, - n, + new_aux, + new_cur, atomics::memory_order_seq_cst, atomics::memory_order_seq_cst ); - p = n; - n = p->next.load(atomics::memory_order_acquire); - } + new_aux = new_cur; - aux_pNode.store(p); - current_node.store(n); - - //m_Guard.protect( current_node->data, []( marked_data_ptr ptr ) { return ptr.ptr(); }).ptr(); - } + new_cur = new_aux->next.load(atomics::memory_order_acquire); + } + current_node.store(new_cur); + aux_pNode.store(new_aux); + } - void print(){ + /*void print(){ std::cout << "iterator" << std::endl; if (current_node->data.load() != nullptr){ std::cout << "current " << current_node << " value " << *(current_node->data.load().ptr()) << std::endl; @@ -157,7 +155,7 @@ namespace cds { std::cout << "prev " << prev_node << " value " << "NULL" << std::endl; } std::cout << "--------------------" << std::endl; - } + }*/ }; public: @@ -220,21 +218,21 @@ namespace cds { bool try_insert(iterator& i, value_type * val) { - node_type *real_node = new node_type(val); - node_type *aux_node = new node_type(); + node_type * real_node = new node_type(val); + node_type * aux_node = new node_type(); real_node->next = aux_node; aux_node->next.store(i.current_node.load()); + node_type * cur_node = i.current_node.load(); + bool insert_status = i.aux_pNode.load()->next.compare_exchange_strong( - i.current_node.load(), + cur_node, real_node, memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst ); - - return insert_status; } @@ -295,8 +293,8 @@ namespace cds { typename gc::Guard m_Guard; iterator mIter; mIter.set(list_head_node); - while (mIter.current_node->next.load() != nullptr ) { - value_type * nVal = mIter.current_node->data.load(atomics::memory_order_acquire ).ptr(); + while (mIter.current_node.load()->next.load() != nullptr ) { + value_type * nVal = mIter.current_node.load()->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ @@ -327,7 +325,7 @@ namespace cds { return true; } } - + /* void print_all_by_iterator(){ iterator mIter; mIter.set(list_head_node); @@ -372,7 +370,7 @@ namespace cds { number++; selected_node = selected_node->next.load(); } while (selected_node != nullptr); - } + }*/ @@ -426,7 +424,7 @@ namespace cds { - +/* void append(int& number){ node_type * next_node = list_head_node.load(); node_type * next_aux_node; @@ -482,7 +480,7 @@ namespace cds { } while (next_node->next.load() != nullptr); return -1; } - +*/ bool deleted (const value_type & number){ node_type * next_node = list_head_node.load(); node_type * next_aux_node; diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index e8915ef8f..77d09d9b6 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -202,15 +202,12 @@ namespace { }; typedef ci::ValoisList< gc_type, val_and_id, traits > list_stress_type; - - - template void complex_insdel_thread(List& list){ cds::threading::Manager::attachThread(); std::thread::id this_id = std::this_thread::get_id(); std::cout << this_id << std::endl; - for (int key=0; key < 1000000; ++key ) { + for (int key=0; key < 10000; ++key ) { val_and_id * input = new val_and_id(this_id,key); list.insert(* input); list.erase(* input); From 4793090f4fc8b53c8e6bfb5336e0e6ad7b779ffd Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 19 Jan 2018 00:52:33 +0300 Subject: [PATCH 42/46] fix with memory leaks --- cds/intrusive/impl/valois_list.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index da6b07089..bd3fde480 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -232,6 +232,10 @@ namespace cds { memory_model::memory_order_seq_cst, memory_model::memory_order_seq_cst ); + if(!insert_status){ + delete real_node; + delete aux_node; + } return insert_status; } From effc8349f6fc353e9091964d7ac7f1be1837cd4a Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 19 Jan 2018 01:14:31 +0300 Subject: [PATCH 43/46] optimize methods --- cds/intrusive/impl/valois_list.h | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index bd3fde480..17be6cdb4 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -138,7 +138,10 @@ namespace cds { } current_node.store(new_cur); + current_guard.protect(current_node); aux_pNode.store(new_aux); + aux_pNode = aux_guard.protect(aux_pNode); + } /*void print(){ @@ -185,10 +188,10 @@ namespace cds { iterator mIter; mIter.set(list_head_node); while (true) { - Q * nVal = mIter.current_node.load() - ->data.load( - atomics::memory_order_acquire - ).ptr(); + + Q * nVal = (mIter.current_guard.template get())->data.load( + atomics::memory_order_acquire + ).ptr() ; if(nVal == nullptr){ // for last node; @@ -256,8 +259,9 @@ namespace cds { iterator mIter; mIter.set( list_head_node ); //search node - while (mIter.current_node.load()->next.load() != nullptr ) { - value_type * nVal = mIter.current_node.load()->data.load(atomics::memory_order_acquire ).ptr(); + while ((mIter.current_guard.template get())->next.load() != nullptr ) { + value_type * nVal = (mIter.current_guard.template get()) + ->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ @@ -297,8 +301,8 @@ namespace cds { typename gc::Guard m_Guard; iterator mIter; mIter.set(list_head_node); - while (mIter.current_node.load()->next.load() != nullptr ) { - value_type * nVal = mIter.current_node.load()->data.load(atomics::memory_order_acquire ).ptr(); + while ((mIter.current_guard.template get())->next.load() != nullptr ) { + value_type * nVal = (mIter.current_guard.template get())->data.load(atomics::memory_order_acquire ).ptr(); int const nCmp = cmp( *val , *nVal ); if ( nCmp == 0 ){ @@ -334,8 +338,8 @@ namespace cds { iterator mIter; mIter.set(list_head_node); std::cout << "----------start print by iterator---------------" << std::endl; - while(mIter.current_node.load()->next.load() != nullptr){ - value_type * nVal = mIter.current_node.load()->data.load(memory_model::memory_order_seq_cst ).ptr(); + while((mIter.current_guard.template get())->next.load() != nullptr){ + value_type * nVal = (mIter.current_guard.template get())->data.load(memory_model::memory_order_seq_cst ).ptr(); std::cout << *nVal << std::endl; mIter.next(); } From fe4f90b5c3eab756d8302539b4ccfbb1ab1d1255 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 19 Jan 2018 01:20:13 +0300 Subject: [PATCH 44/46] fix with CAS result in search insert --- cds/intrusive/impl/valois_list.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 17be6cdb4..1472782de 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -187,6 +187,7 @@ namespace cds { typename gc::Guard m_Guard; iterator mIter; mIter.set(list_head_node); + bool k = false; while (true) { Q * nVal = (mIter.current_guard.template get())->data.load( @@ -195,8 +196,13 @@ namespace cds { if(nVal == nullptr){ // for last node; - try_insert(mIter, val); - return true; + k = try_insert(mIter, val); + if (k){ + return k; + } else{ + // find again; + mIter.set(list_head_node); + } } int const nCmp = cmp(*val, *nVal); @@ -204,7 +210,7 @@ namespace cds { if (nCmp == 0) { return true; } else if (nCmp < 0) { - bool k = try_insert(mIter, val); + k = try_insert(mIter, val); if (k){ return k; From 3d624470d477d7c11e643f1dd18b3ff0cd216791 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 19 Jan 2018 01:26:27 +0300 Subject: [PATCH 45/46] fix a bug --- cds/intrusive/impl/valois_list.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index 1472782de..b4441051a 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -202,6 +202,7 @@ namespace cds { } else{ // find again; mIter.set(list_head_node); + continue; } } @@ -231,9 +232,9 @@ namespace cds { node_type * aux_node = new node_type(); real_node->next = aux_node; - aux_node->next.store(i.current_node.load()); + aux_node->next.store((i.current_guard.template get())); - node_type * cur_node = i.current_node.load(); + node_type * cur_node = (i.current_guard.template get()); bool insert_status = i.aux_pNode.load()->next.compare_exchange_strong( cur_node, @@ -419,9 +420,9 @@ namespace cds { bool try_erase(iterator& i) { - node_type *d = i.current_node.load(); + node_type *d = (i.current_guard.template get()); - node_type *n = i.current_node.load()->next.load(atomics::memory_order_release); + node_type *n = (i.current_guard.template get())->next.load(atomics::memory_order_release); bool r = i.aux_pNode.load()->next.compare_exchange_strong(d, n->next.load(), atomics::memory_order_seq_cst); if (!r){ From 2214b930e13b278aeeba3e26cff18ea4215fd2f2 Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 27 Jan 2018 20:37:04 +0300 Subject: [PATCH 46/46] fix for request --- cds/intrusive/impl/valois_list.h | 124 ------------------ .../intrusive-list/intrusive_valois_hp.cpp | 41 ++---- 2 files changed, 13 insertions(+), 152 deletions(-) diff --git a/cds/intrusive/impl/valois_list.h b/cds/intrusive/impl/valois_list.h index b4441051a..c809def76 100644 --- a/cds/intrusive/impl/valois_list.h +++ b/cds/intrusive/impl/valois_list.h @@ -144,21 +144,6 @@ namespace cds { } - /*void print(){ - std::cout << "iterator" << std::endl; - if (current_node->data.load() != nullptr){ - std::cout << "current " << current_node << " value " << *(current_node->data.load().ptr()) << std::endl; - } else{ - std::cout << "current " << current_node << " value " << "NULL" << std::endl; - } - std::cout << "aux " << aux_pNode << std::endl; - if (prev_node->data.load() != nullptr){ - std::cout << "prev " << prev_node << " value " << *(prev_node->data.load().ptr()) << std::endl; - } else{ - std::cout << "prev " << prev_node << " value " << "NULL" << std::endl; - } - std::cout << "--------------------" << std::endl; - }*/ }; public: @@ -334,58 +319,11 @@ namespace cds { mIter.set(list_head_node); if ( mIter.next() ) { - // if next is not exist() container is empty() return false; } else { return true; } } - /* - void print_all_by_iterator(){ - iterator mIter; - mIter.set(list_head_node); - std::cout << "----------start print by iterator---------------" << std::endl; - while((mIter.current_guard.template get())->next.load() != nullptr){ - value_type * nVal = (mIter.current_guard.template get())->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << *nVal << std::endl; - mIter.next(); - } - std::cout << "----------end---------------" << std::endl; - } - void print_all_by_link(){ - std::cout << "----------start print by link---------------" << std::endl; - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - int number = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - std::cout << "next_aux_node -> " < " <next.load() << std::endl; - std::cout << "next_node.next -> " <next.load() << std::endl << std::endl; - if (next_node->next){ - value_type * nVal = next_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - value_type * nVala = next_aux_node->data.load(memory_model::memory_order_seq_cst ).ptr(); - std::cout << number << " aux -> " << nVala << " -> "<< std::endl; - std::cout << number << " -> " << nVal << " -> "<< *nVal << std::endl; - } - number++; - } while (next_node->next != nullptr); - std::cout << "----------finish print by link---------------" << std::endl; - } - void print_all_pointers(){ - node_type * selected_node = list_head_node.load(); - int number = 0; - std::string type; - do{ - if (selected_node->data.load() == nullptr) - std::cout << number << "\t" << selected_node << "\t AUX" << std::endl; - else - std::cout << number << "\t" << selected_node << "\t " << *(selected_node->data.load().ptr()) << std::endl; - number++; - selected_node = selected_node->next.load(); - } while (selected_node != nullptr); - }*/ @@ -431,71 +369,9 @@ namespace cds { gc::template retire( d ); gc::template retire( n ); - /*delete d; - delete n;*/ - return true; } - - -/* - void append(int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - } while (next_aux_node->next != nullptr && next_node->next.load() != nullptr); - int * index = new int32_t(number); - node_type * new_next_node = new node_type(index); - node_type * new_next_aux_node = new node_type(); - new_next_aux_node->next.store(next_node); - new_next_node->next.store(new_next_aux_node); - next_aux_node->next.store(new_next_node); - } - void append_in_first(const int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node = next_node->next.load(); - int d = number; - int * index = new int32_t(d); - node_type * new_next_node = new node_type(index); - node_type * new_next_aux_node = new node_type(); - new_next_aux_node->next.store(next_aux_node->next.load()); - new_next_node->next.store(new_next_aux_node); - next_aux_node->next.store(new_next_node); - } - void append_in_position(const int& number, const int& position){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - int ind = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - ind++; - } while (next_node->next.load() != nullptr && ind < position + 1); - std::cout << "value " <next.store(next_node); - new_next_node->next.store(new_next_aux_node); - next_aux_node->next.store(new_next_node); - } - int search(const int& number){ - node_type * next_node = list_head_node.load(); - node_type * next_aux_node; - int ind = 0; - do{ - next_aux_node = next_node->next.load(); - next_node = next_aux_node->next.load(); - if (number == *(next_node->data.load().ptr())){ - return ind; - } - ind++; - } while (next_node->next.load() != nullptr); - return -1; - } -*/ bool deleted (const value_type & number){ node_type * next_node = list_head_node.load(); node_type * next_aux_node; diff --git a/test/unit/intrusive-list/intrusive_valois_hp.cpp b/test/unit/intrusive-list/intrusive_valois_hp.cpp index 77d09d9b6..19f5d309e 100644 --- a/test/unit/intrusive-list/intrusive_valois_hp.cpp +++ b/test/unit/intrusive-list/intrusive_valois_hp.cpp @@ -67,12 +67,11 @@ namespace { template void test_simple_list(List& list) { - std::cout << "simple test started " << std::endl; list.append_in_first(3); list.append_in_position(10000,10); - std::cout << "search " << list.search(10000) << std::endl; + list.search(10000); list.deleted(50); @@ -206,7 +205,6 @@ namespace { void complex_insdel_thread(List& list){ cds::threading::Manager::attachThread(); std::thread::id this_id = std::this_thread::get_id(); - std::cout << this_id << std::endl; for (int key=0; key < 10000; ++key ) { val_and_id * input = new val_and_id(this_id,key); list.insert(* input); @@ -215,34 +213,21 @@ namespace { cds::threading::Manager::detachThread(); } void complex_insdel_test(){ - std::cout << "complex test started" << std::endl; list_stress_type lst; std::thread::id this_id = std::this_thread::get_id(); - std::cout << "main threads " << this_id << std::endl; - - std::thread thr(complex_insdel_thread,std::ref(lst)); - std::thread thr1(complex_insdel_thread,std::ref(lst)); - std::thread thr2(complex_insdel_thread,std::ref(lst)); - std::thread thr3(complex_insdel_thread,std::ref(lst)); - std::thread thr4(complex_insdel_thread,std::ref(lst)); - std::thread thr5(complex_insdel_thread,std::ref(lst)); - std::thread thr6(complex_insdel_thread,std::ref(lst)); - std::thread thr7(complex_insdel_thread,std::ref(lst)); - std::thread thr8(complex_insdel_thread,std::ref(lst)); - std::thread thr9(complex_insdel_thread,std::ref(lst)); - - thr.join(); - thr1.join(); - thr2.join(); - thr3.join(); - thr4.join(); - thr5.join(); - thr6.join(); - thr7.join(); - thr8.join(); - thr9.join(); - std::cout << "Complex test finished" << std::endl; + + + int numThreads = 10; + std::vector threads; + + + for(int i = 0; i < numThreads; i++) + threads.push_back(std::thread(complex_insdel_thread, std::ref(lst))); + + for(int i = 0; i < numThreads; i++) + threads[i].join(); + } TEST_F( IntrusiveValoisList_HP, base_hook )