X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=cds%2Fsync%2Fmonitor.h;h=2ac85a330b2140cd9e371dddafe18c397fc8f7a9;hb=99d4d70957c586988f4a15e5f0f7df511086c2d8;hp=82577420f5fc4bd3c45c241ad36ab934693d098c;hpb=f8d36edb2cba8693dfe047cb866568b1696be8ac;p=libcds.git diff --git a/cds/sync/monitor.h b/cds/sync/monitor.h index 82577420..2ac85a33 100644 --- a/cds/sync/monitor.h +++ b/cds/sync/monitor.h @@ -6,21 +6,17 @@ #include namespace cds { namespace sync { - /** @page cds_sync_monitor Synchronization monitor - A monitor is synchronization construct that allows threads to have both mutual exclusion and the ability to wait (block) for a certain condition to become true. - Some blocking data structure algoritms like the trees require per-node locking. For huge trees containing millions of nodes it can be very inefficient to inject the lock object into each node. Moreover, some operating systems may not support the millions of system objects like mutexes per user process. - The monitor strategy is intended to solve that problem. 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. + lock object for the node if needed, and to lock the node. The monitor strategy can significantly reduce the number of system objects required for data structure. @@ -30,15 +26,19 @@ namespace cds { namespace sync { - \p sync::injecting_monitor injects the lock object into each node. That mock monitor is designed for user-space locking primitive like \ref sync::spin_lock "spin-lock". + - \p sync::pool_monitor is the monitor that allocates a lock object + for a node from the pool when needed. When the node is unlocked + the lock assigned to it is given back to the pool if no thread + references to that node. How to use If you use a container from \p libcds that requires a monitor, you should just - specify required monitor type in container's traits. Usually, the monitor + specify required monitor type in container's traits. Usually, the monitor is specified by \p traits::sync_monitor typedef, or by \p cds::opt::sync_monitor option for container's \p make_traits metafunction. - If you're developing a new container algorithm, you should know internal monitor + If you're developing a new container algorithm, you should know internal monitor interface: \code class Monitor { @@ -48,43 +48,71 @@ namespace cds { namespace sync { struct node_injection: public Node { // Monitor data to inject into container's node - // ... + // ... }; - - // Locks the node + // Locks the node template void lock( Node& node ); - // Unlocks the node template void unlock( Node& node ); - // Scoped lock applyes RAII to Monitor template - class scoped_lock - { - public: - // Locks node by monitor mon - scoped_lock( Monitor& mon, Node& node ); - - // Unlocks the node locked by ctor - ~scoped_lock(); - }; + using scoped_lock = monitor_scoped_lock< pool_monitor, Node >; + }; + \endcode + Monitor's data must be inject into container's node as \p m_SyncMonitorInjection data member: + \code + template + struct my_node + { + // ... + typename SyncMonitor::node_injection m_SyncMonitorInjection; }; \endcode - The monitor should be a member of your container: + The monitor must be a member of your container: \code template class my_container { // ... typedef typename Traits::sync_monitor sync_monitor; + typedef my_node node_type; sync_monitor m_Monitor; //... }; \endcode */ - + /// Monitor scoped lock (RAII) + /** + Template arguments: + - \p Monitor - monitor type + - \p Node - node type + */ + template + struct monitor_scoped_lock + { + public: + typedef Monitor monitor_type; ///< Monitor type + typedef Node node_type; ///< Node type + private: + //@cond + monitor_type& m_Monitor; ///< Monitor + node_type const& m_Node; ///< Our locked node + //@endcond + public: + /// Makes exclusive access to the node \p p by \p monitor + monitor_scoped_lock( monitor_type& monitor, node_type const& p ) + : m_Monitor( monitor ) + , m_Node( p ) + { + monitor.lock( p ); + } + /// Unlocks the node + ~monitor_scoped_lock() + { + m_Monitor.unlock( m_Node ); + } + }; }} // namespace cds::sync - #endif // #ifndef CDSLIB_SYNC_MONITOR_H