From: khizmax Date: Mon, 2 Feb 2015 20:13:11 +0000 (+0300) Subject: Added sync_monitor option X-Git-Tag: v2.1.0~305^2~79 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=f8d36edb2cba8693dfe047cb866568b1696be8ac;p=libcds.git Added sync_monitor option --- diff --git a/cds/compiler/clang/defs.h b/cds/compiler/clang/defs.h index 1c24b09c..8b649d10 100644 --- a/cds/compiler/clang/defs.h +++ b/cds/compiler/clang/defs.h @@ -44,6 +44,9 @@ // Full SFINAE support #define CDS_CXX11_SFINAE +// Inheriting constructors +#define CDS_CXX11_INHERITING_CTOR + // ************************************************* // Alignment macro diff --git a/cds/compiler/gcc/defs.h b/cds/compiler/gcc/defs.h index 6cf29563..2dadc6e1 100644 --- a/cds/compiler/gcc/defs.h +++ b/cds/compiler/gcc/defs.h @@ -20,7 +20,6 @@ #include - #define alignof __alignof__ // *************************************** @@ -42,6 +41,9 @@ // Full SFINAE support #define CDS_CXX11_SFINAE +// Inheriting constructors +#define CDS_CXX11_INHERITING_CTOR + // ************************************************* // Alignment macro diff --git a/cds/compiler/icl/defs.h b/cds/compiler/icl/defs.h index 7552be38..79ffefed 100644 --- a/cds/compiler/icl/defs.h +++ b/cds/compiler/icl/defs.h @@ -86,6 +86,9 @@ // C++11 inline namespace #define CDS_CXX11_INLINE_NAMESPACE_SUPPORT +// Inheriting constructors +#define CDS_CXX11_INHERITING_CTOR + // ************************************************* // Alignment macro diff --git a/cds/compiler/vc/defs.h b/cds/compiler/vc/defs.h index 30e2ec59..908aa008 100644 --- a/cds/compiler/vc/defs.h +++ b/cds/compiler/vc/defs.h @@ -14,7 +14,7 @@ #define CDS_COMPILER_MSVC14 1900 // 2015 vc14 #if CDS_COMPILER_VERSION < CDS_COMPILER_MSVC12 -# error "Only MS Visual C++ 12 (2013) and above is supported" +# error "Only MS Visual C++ 12 (2013) Update 4 and above is supported" #endif #if _MSC_VER == 1800 @@ -109,6 +109,11 @@ # define CDS_CXX11_SFINAE #endif +// Inheriting constructors +#if CDS_COMPILER_VERSION > CDS_COMPILER_MSVC12 +# define CDS_CXX11_INHERITING_CTOR +#endif + // ************************************************* // Alignment macro diff --git a/cds/container/details/bronson_avltree_base.h b/cds/container/details/bronson_avltree_base.h index 77f77ef7..8da14d65 100644 --- a/cds/container/details/bronson_avltree_base.h +++ b/cds/container/details/bronson_avltree_base.h @@ -17,12 +17,11 @@ namespace cds { namespace container { struct node; //@cond - template + template struct link { typedef node node_type; typedef uint32_t version_type; - typedef Lock lock_type; enum { @@ -37,7 +36,6 @@ namespace cds { namespace container { atomics::atomic m_pParent; ///< Parent node atomics::atomic m_pLeft; ///< Left child atomics::atomic m_pRight; ///< Right child - lock_type m_Lock; ///< Node-level lock node_type * m_pNextRemoved; ///< thread-local list o removed node @@ -112,12 +110,12 @@ namespace cds { namespace container { } }; - template - struct node : public link< Key, T, Lock > + template + struct node : public link< Key, T > { typedef Key key_type; typedef T mapped_type; - typedef link< key_type, mapped_type, Lock > base_class; + typedef link< key_type, mapped_type > base_class; key_type const m_key; atomics::atomic m_pValue; @@ -264,8 +262,8 @@ namespace cds { namespace container { */ typedef opt::v::delete_disposer<> disposer; - /// Node lock - typedef std::mutex lock_type; + /// @ref cds_sync_monitor "Synchronization monitor" type for node-level locking + typedef cds::sync::injecting_monitor sync_monitor; /// Enable relaxed insertion. /** @@ -323,7 +321,8 @@ namespace cds { namespace container { the disposer will be called to signal that the memory for the value can be safely freed. Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator. Due the nature of GC schema the disposer may be called asynchronously. - - \p opt::lock_type - node lock type, default is \p std::mutex + - \p opt::sync_monitor - @ref cds_sync_monitor "synchronization monitor" type for node-level locking, + default is cds::sync::injecting_monitor - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default) @ref bronson_avltree::relaxed_insert "relaxed insertion" - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter) diff --git a/cds/container/impl/bronson_avltree_map_rcu.h b/cds/container/impl/bronson_avltree_map_rcu.h index 533ac3db..4ea56e89 100644 --- a/cds/container/impl/bronson_avltree_map_rcu.h +++ b/cds/container/impl/bronson_avltree_map_rcu.h @@ -60,14 +60,14 @@ namespace cds { namespace container { typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy typedef typename traits::back_off back_off; ///< Back-off strategy typedef typename traits::disposer disposer; ///< Value disposer - typedef typename traits::lock_type lock_type; ///< Node lock type + typedef typename traits::sync_monitor sync_monitor; ///< @ref cds_sync_monitor "Synchronization monitor" type for node-level locking /// Enabled or disabled @ref bronson_avltree::relaxed_insert "relaxed insertion" static bool const c_bRelaxedInsert = traits::relaxed_insert; protected: //@cond - typedef bronson_avltree::node< key_type, mapped_type, lock_type > node_type; + typedef typename sync_monitor::template node_injection< bronson_avltree::node< key_type, mapped_type >> node_type; typedef typename node_type::version_type version_type; typedef cds::details::Allocator< node_type, node_allocator_type > cxx_allocator; @@ -98,22 +98,7 @@ namespace cds { namespace container { unlink_required = -1 }; - class node_scoped_lock - { - node_type * m_pNode; - public: - node_scoped_lock( node_type * pNode ) - : m_pNode( pNode ) - { - pNode->m_Lock.lock(); - } - - ~node_scoped_lock() - { - m_pNode->m_Lock.unlock(); - } - }; - + typedef typename sync_monitor::template scoped_lock node_scoped_lock; //@endcond protected: @@ -186,6 +171,7 @@ namespace cds { namespace container { typename node_type::base_class m_Root; node_type * m_pRoot; item_counter m_ItemCounter; + mutable sync_monitor m_Monitor; mutable stat m_stat; //@endcond @@ -405,8 +391,9 @@ namespace cds { namespace container { template bool find( K const& key, Func f ) { - return do_find( key, key_comparator(), [&f]( node_type * pNode ) -> bool { - node_scoped_lock l( pNode ); + return do_find( key, key_comparator(), [&f]( sync_monitor& monitor, node_type * pNode ) -> bool { + assert( pNode != nullptr ); + node_scoped_lock l( monitor, *pNode ); mapped_type * pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed ); if ( pVal ) { f( *pVal ); @@ -427,15 +414,18 @@ namespace cds { namespace container { bool find_with( K const& key, Less pred, Func f ) { CDS_UNUSED( pred ); - return do_find( key, opt::details::make_comparator_from_less(), [&f]( node_type * pNode ) -> bool { - node_scoped_lock l( pNode ); - mapped_type * pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed ); - if ( pVal ) { - f( *pVal ); - return true; - } - return false; - } ); + return do_find( key, opt::details::make_comparator_from_less(), + [&f]( sync_monitor& monitor, node_type * pNode ) -> bool { + assert( pNode != nullptr ); + node_scoped_lock l( monitor, *pNode ); + mapped_type * pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed ); + if ( pVal ) { + f( *pVal ); + return true; + } + return false; + } + ); } /// Find the key \p key @@ -614,7 +604,7 @@ namespace cds { namespace container { if ( nCmp == 0 ) { if ( pChild->is_valued( memory_model::memory_order_relaxed ) ) { // key found - if ( f( pChild ) ) { + if ( f( m_Monitor, pChild ) ) { m_stat.onFindSuccess(); return find_result::found; } @@ -672,7 +662,7 @@ namespace cds { namespace container { if ( nFlags & update_flags::allow_insert ) { // insert into tree as right child of the root { - node_scoped_lock l( m_pRoot ); + node_scoped_lock l( m_Monitor, *m_pRoot ); node_type * pNew = alloc_node( key, 1, 0, m_pRoot, nullptr, nullptr ); mapped_type * pVal = funcUpdate( pNew ); @@ -775,7 +765,8 @@ namespace cds { namespace container { node_type * pDamaged; { - node_scoped_lock l( pNode ); + assert( pNode != nullptr ); + node_scoped_lock l( m_Monitor, *pNode ); if ( pNode->version( memory_model::memory_order_relaxed ) != nVersion || pNode->child( nDir ).load( memory_model::memory_order_relaxed ) != nullptr ) @@ -807,7 +798,8 @@ namespace cds { namespace container { { mapped_type * pOld; { - node_scoped_lock l( pNode ); + assert( pNode != nullptr ); + node_scoped_lock l( m_Monitor, *pNode ); if ( pNode->version( memory_model::memory_order_relaxed ) == node_type::unlinked ) { if ( c_RelaxedInsert ) @@ -895,7 +887,8 @@ namespace cds { namespace container { node_type * fix_height( node_type * pNode ) { - node_scoped_lock l( pNode ); + assert( pNode != nullptr ); + node_scoped_lock l( m_Monitor, *pNode ); return fix_height_locked( pNode ); } @@ -928,11 +921,11 @@ namespace cds { namespace container { node_type * pParent = pNode->m_pParent.load( memory_model::memry_order_relaxed ); assert( pParent != nullptr ); { - node_scoped_lock lp( pParent ); + node_scoped_lock lp( m_Monitor, *pParent ); if ( !pParent->is_unlinked( memory_model::memory_order_relaxed ) && pNode->m_pParent.load( memory_model::memory_order_relaxed ) == pParent ) { - node_scoped_lock ln( pNode ); + node_scoped_lock ln( m_Monitor, *pNode ); pNode = rebalance_locked( pParent, pNode, disp ); } } @@ -991,7 +984,8 @@ namespace cds { namespace container { // If pLeft->pRight is taller than pLeft->pLeft, then we will first rotate-left pLeft. { - node_scoped_lock l( pLeft ); + assert( pLeft != nullptr ); + node_scoped_lock l( m_Monitor, *pLeft ); if ( pNode->m_pLeft.load( memory_model::memory_order_relaxed ) != pLeft ) return pNode; // retry for pNode @@ -1011,7 +1005,7 @@ namespace cds { namespace container { else { assert( pLRight != nullptr ); { - node_scoped_lock lr( pLRight ); + node_scoped_lock lr( m_Monitor, *pLRight ); if ( pLeft->m_pRight.load( memory_model::memory_order_relaxed ) != pLRight ) return pNode; // retry @@ -1042,7 +1036,8 @@ namespace cds { namespace container { // pParent and pNode is locked yet { - node_scoped_lock l( pRight ); + assert( pRight != nullptr ); + node_scoped_lock l( m_Monitor, *pRight ); if ( pNode->m_pRight.load( memory_model::memory_order_relaxed ) != pRight ) return pNode; // retry for pNode @@ -1059,7 +1054,7 @@ namespace cds { namespace container { { assert( pRLeft != nullptr ); - node_scoped_lock lrl( pRLeft ); + node_scoped_lock lrl( m_Monitor, *pRLeft ); if ( pRight->m_pLeft.load( memory_model::memory_order_relaxed ) != pRLeft ) return pNode; // retry diff --git a/cds/opt/options.h b/cds/opt/options.h index 34c289eb..9c8d208d 100644 --- a/cds/opt/options.h +++ b/cds/opt/options.h @@ -177,6 +177,21 @@ namespace opt { //@endcond }; + /// [type-option] @ref cds_sync_monitor "Monitor" type setter + /** + This option setter specifyes @ref cds_sync_monitor "synchronization monitor" + for blocking container. + */ + template + struct sync_monitor { + //@cond + template struct pack : public Base + { + typedef Type sync_monitor; + }; + //@endcond + }; + /// [type-option] Back-off strategy option setter /** Back-off strategy used in some algorithm. diff --git a/cds/sync/injecting_monitor.h b/cds/sync/injecting_monitor.h index 7991fe2a..d7bf7c2f 100644 --- a/cds/sync/injecting_monitor.h +++ b/cds/sync/injecting_monitor.h @@ -4,6 +4,9 @@ #define CDSLIB_SYNC_INJECTING_MONITOR_H #include +#ifndef CDS_CXX11_INHERITING_CTOR +# include // std::forward +#endif namespace cds { namespace sync { @@ -22,19 +25,26 @@ namespace cds { namespace sync { typedef Lock lock_type; ///< Lock type /// Monitor injection into \p Node - template - struct node_wrapper : public Node + struct node_injection { +# ifdef CDS_CXX11_INHERITING_CTOR using Node::Node; +# else + // Inheriting ctor emulation + template + node_injection( Args&&... args ) + : Node( std::forward( args )... ) + {} +# endif mutable lock_type m_Lock; ///< Node-level lock - /// Makes exclusive access to the object + /// Makes exclusive access to the node void lock() const { m_Lock.lock; } - /// Unlocks the object + /// Unlocks the node void unlock() const { m_Lock.unlock(); diff --git a/cds/sync/monitor.h b/cds/sync/monitor.h index 00835677..82577420 100644 --- a/cds/sync/monitor.h +++ b/cds/sync/monitor.h @@ -22,9 +22,9 @@ namespace cds { namespace sync { When the node should be locked, the monitor is called to allocate appropriate lock object for the node if it's needed, and to lock the node. The monitor strategy can significantly reduce the number of system objects - required for the data structure. + required for data structure. - Implemetatios + Implemetations \p libcds contains several monitor implementations: - \p sync::injecting_monitor injects the lock object into each node. @@ -45,7 +45,11 @@ namespace cds { namespace sync { public: // Monitor's injection into the Node class template - struct node_wrapper; + struct node_injection: public Node + { + // Monitor data to inject into container's node + // ... + }; // Locks the node template diff --git a/doxygen/cds.doxy b/doxygen/cds.doxy index 6e2578af..bebbae6e 100644 --- a/doxygen/cds.doxy +++ b/doxygen/cds.doxy @@ -1398,7 +1398,8 @@ PREDEFINED = CDS_BUILD_BITS=64 \ CDS_CXX11_INLINE_NAMESPACE_SUPPORT \ CDS_CXX11_INLINE_NAMESPACE=inline \ CDS_NOEXCEPT=noexcept() \ - CDS_CONSTEXPR=constexpr + CDS_CONSTEXPR=constexpr \ + CDS_CXX11_INHERITING_CTOR # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded.