monitor.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright (c) 2006-2018 Maxim Khizhinsky
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef CDSLIB_SYNC_MONITOR_H
  6. #define CDSLIB_SYNC_MONITOR_H
  7. #include <cds/details/defs.h>
  8. namespace cds { namespace sync {
  9. /**
  10. @page cds_sync_monitor Synchronization monitor
  11. A <a href="http://en.wikipedia.org/wiki/Monitor_%28synchronization%29">monitor</a> is synchronization construction
  12. that allows threads to have both mutual exclusion and the ability to wait (block) for a certain condition to become true.
  13. Some blocking data structure algoritms like the trees require per-node locking.
  14. For huge trees containing millions of nodes it can be very inefficient to inject
  15. the lock object into each node. Moreover, some operating systems may not support
  16. the millions of system objects like mutexes per user process.
  17. The monitor strategy is intended to solve that problem.
  18. When the node should be locked, the monitor is called to allocate appropriate
  19. lock object for the node if needed, and to lock the node.
  20. The monitor strategy can significantly reduce the number of system objects
  21. required for data structure.
  22. <b>Implemetations</b>
  23. \p libcds contains several monitor implementations:
  24. - \p sync::injecting_monitor injects the lock object into each node.
  25. That mock monitor is designed for user-space locking primitive like
  26. \ref sync::spin_lock "spin-lock".
  27. - \p sync::pool_monitor is the monitor that allocates a lock object
  28. for a node from the pool when needed. When the node is unlocked
  29. the lock assigned to it is given back to the pool if no thread
  30. references to that node.
  31. <b>How to use</b>
  32. If you use a container from \p libcds that requires a monitor, you should just
  33. specify required monitor type in container's traits. Usually, the monitor
  34. is specified by \p traits::sync_monitor typedef, or by \p cds::opt::sync_monitor
  35. option for container's \p make_traits metafunction.
  36. If you're developing a new container algorithm, you should know internal monitor
  37. interface:
  38. \code
  39. class Monitor {
  40. public:
  41. // Monitor's injection into the Node class
  42. template <typename Node>
  43. struct node_injection: public Node
  44. {
  45. // Monitor data injecting into container's node
  46. // ...
  47. };
  48. // Locks the node
  49. template <typename Node>
  50. void lock( Node& node );
  51. // Unlocks the node
  52. template <typename Node>
  53. void unlock( Node& node );
  54. // Scoped lock applyes RAII to Monitor
  55. template <typename Node>
  56. using scoped_lock = monitor_scoped_lock< pool_monitor, Node >;
  57. };
  58. \endcode
  59. Monitor's data must be injected into container's node as \p m_SyncMonitorInjection data member:
  60. \code
  61. template <typename SyncMonitor>
  62. struct my_node
  63. {
  64. // ...
  65. typename SyncMonitor::node_injection m_SyncMonitorInjection;
  66. };
  67. \endcode
  68. The monitor must be a member of your container:
  69. \code
  70. template <typename GC, typename T, typename Traits>
  71. class my_container {
  72. // ...
  73. typedef typename Traits::sync_monitor sync_monitor;
  74. typedef my_node<sync_monitor> node_type;
  75. sync_monitor m_Monitor;
  76. //...
  77. };
  78. \endcode
  79. */
  80. /// Monitor scoped lock (RAII)
  81. /**
  82. Template arguments:
  83. - \p Monitor - monitor type
  84. - \p Node - node type
  85. */
  86. template <typename Monitor, typename Node>
  87. struct monitor_scoped_lock
  88. {
  89. public:
  90. typedef Monitor monitor_type; ///< Monitor type
  91. typedef Node node_type; ///< Node type
  92. private:
  93. //@cond
  94. monitor_type& m_Monitor; ///< Monitor
  95. node_type const& m_Node; ///< Our locked node
  96. //@endcond
  97. public:
  98. /// Makes exclusive access to the node \p p by \p monitor
  99. monitor_scoped_lock( monitor_type& monitor, node_type const& p )
  100. : m_Monitor( monitor )
  101. , m_Node( p )
  102. {
  103. monitor.lock( p );
  104. }
  105. /// Unlocks the node
  106. ~monitor_scoped_lock()
  107. {
  108. m_Monitor.unlock( m_Node );
  109. }
  110. };
  111. }} // namespace cds::sync
  112. #endif // #ifndef CDSLIB_SYNC_MONITOR_H