condition_any_algorithm.hpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2012-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP
  11. #define BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #
  16. #if defined(BOOST_HAS_PRAGMA_ONCE)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/config_begin.hpp>
  20. #include <boost/interprocess/detail/workaround.hpp>
  21. #include <boost/interprocess/sync/scoped_lock.hpp>
  22. #include <boost/interprocess/sync/detail/locks.hpp>
  23. #include <limits>
  24. namespace boost {
  25. namespace interprocess {
  26. namespace ipcdetail {
  27. ////////////////////////////////////////////////////////////////////////
  28. ////////////////////////////////////////////////////////////////////////
  29. ////////////////////////////////////////////////////////////////////////
  30. //
  31. // Condition variable 'any' (able to use any type of external mutex)
  32. //
  33. // The code is based on Howard E. Hinnant's ISO C++ N2406 paper.
  34. // Many thanks to Howard for his support and comments.
  35. ////////////////////////////////////////////////////////////////////////
  36. ////////////////////////////////////////////////////////////////////////
  37. ////////////////////////////////////////////////////////////////////////
  38. // Required interface for ConditionAnyMembers
  39. // class ConditionAnyMembers
  40. // {
  41. // typedef implementation_defined mutex_type;
  42. // typedef implementation_defined condvar_type;
  43. //
  44. // condvar &get_condvar()
  45. // mutex_type &get_mutex()
  46. // };
  47. //
  48. // Must be initialized as following
  49. //
  50. // get_condvar() [no threads blocked]
  51. // get_mutex() [unlocked]
  52. template<class ConditionAnyMembers>
  53. class condition_any_algorithm
  54. {
  55. private:
  56. condition_any_algorithm();
  57. ~condition_any_algorithm();
  58. condition_any_algorithm(const condition_any_algorithm &);
  59. condition_any_algorithm &operator=(const condition_any_algorithm &);
  60. typedef typename ConditionAnyMembers::mutex_type mutex_type;
  61. typedef typename ConditionAnyMembers::condvar_type condvar_type;
  62. template <class Lock>
  63. static void do_wait(ConditionAnyMembers &data, Lock& lock);
  64. template <class Lock>
  65. static bool do_timed_wait(ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time);
  66. public:
  67. template<class Lock>
  68. static bool wait ( ConditionAnyMembers &data, Lock &mut
  69. , bool timeout_enabled, const boost::posix_time::ptime &abs_time);
  70. static void signal( ConditionAnyMembers &data, bool broadcast);
  71. };
  72. template<class ConditionAnyMembers>
  73. void condition_any_algorithm<ConditionAnyMembers>::signal(ConditionAnyMembers &data, bool broadcast)
  74. {
  75. scoped_lock<mutex_type> internal_lock(data.get_mutex());
  76. if(broadcast){
  77. data.get_condvar().notify_all();
  78. }
  79. else{
  80. data.get_condvar().notify_one();
  81. }
  82. }
  83. template<class ConditionAnyMembers>
  84. template<class Lock>
  85. bool condition_any_algorithm<ConditionAnyMembers>::wait
  86. ( ConditionAnyMembers &data
  87. , Lock &lock
  88. , bool tout_enabled
  89. , const boost::posix_time::ptime &abs_time)
  90. {
  91. if(tout_enabled){
  92. return condition_any_algorithm::do_timed_wait(data, lock, abs_time);
  93. }
  94. else{
  95. condition_any_algorithm::do_wait(data, lock);
  96. return true;
  97. }
  98. }
  99. template<class ConditionAnyMembers>
  100. template <class Lock>
  101. void condition_any_algorithm<ConditionAnyMembers>::do_wait
  102. (ConditionAnyMembers &data, Lock& lock)
  103. {
  104. //lock internal before unlocking external to avoid race with a notifier
  105. scoped_lock<mutex_type> internal_lock(data.get_mutex());
  106. {
  107. lock_inverter<Lock> inverted_lock(lock);
  108. scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
  109. { //unlock internal first to avoid deadlock with near simultaneous waits
  110. scoped_lock<mutex_type> internal_unlock;
  111. internal_lock.swap(internal_unlock);
  112. data.get_condvar().wait(internal_unlock);
  113. }
  114. }
  115. }
  116. template<class ConditionAnyMembers>
  117. template <class Lock>
  118. bool condition_any_algorithm<ConditionAnyMembers>::do_timed_wait
  119. (ConditionAnyMembers &data, Lock& lock, const boost::posix_time::ptime &abs_time)
  120. {
  121. //lock internal before unlocking external to avoid race with a notifier
  122. scoped_lock<mutex_type> internal_lock(data.get_mutex());
  123. {
  124. //Unlock external lock and program for relock
  125. lock_inverter<Lock> inverted_lock(lock);
  126. scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
  127. { //unlock internal first to avoid deadlock with near simultaneous waits
  128. scoped_lock<mutex_type> internal_unlock;
  129. internal_lock.swap(internal_unlock);
  130. return data.get_condvar().timed_wait(internal_unlock, abs_time);
  131. }
  132. }
  133. }
  134. template<class ConditionAnyMembers>
  135. class condition_any_wrapper
  136. {
  137. //Non-copyable
  138. condition_any_wrapper(const condition_any_wrapper &);
  139. condition_any_wrapper &operator=(const condition_any_wrapper &);
  140. ConditionAnyMembers m_data;
  141. typedef ipcdetail::condition_any_algorithm<ConditionAnyMembers> algo_type;
  142. public:
  143. condition_any_wrapper(){}
  144. ~condition_any_wrapper(){}
  145. ConditionAnyMembers & get_members()
  146. { return m_data; }
  147. const ConditionAnyMembers & get_members() const
  148. { return m_data; }
  149. void notify_one()
  150. { algo_type::signal(m_data, false); }
  151. void notify_all()
  152. { algo_type::signal(m_data, true); }
  153. template <typename L>
  154. void wait(L& lock)
  155. {
  156. if (!lock)
  157. throw lock_exception();
  158. algo_type::wait(m_data, lock, false, boost::posix_time::ptime());
  159. }
  160. template <typename L, typename Pr>
  161. void wait(L& lock, Pr pred)
  162. {
  163. if (!lock)
  164. throw lock_exception();
  165. while (!pred())
  166. algo_type::wait(m_data, lock, false, boost::posix_time::ptime());
  167. }
  168. template <typename L>
  169. bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
  170. {
  171. if (!lock)
  172. throw lock_exception();
  173. return algo_type::wait(m_data, lock, true, abs_time);
  174. }
  175. template <typename L, typename Pr>
  176. bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
  177. {
  178. if (!lock)
  179. throw lock_exception();
  180. while (!pred()){
  181. if (!algo_type::wait(m_data, lock, true, abs_time))
  182. return pred();
  183. }
  184. return true;
  185. }
  186. };
  187. } //namespace ipcdetail
  188. } //namespace interprocess
  189. } //namespace boost
  190. #include <boost/interprocess/detail/config_end.hpp>
  191. #endif //BOOST_INTERPROCESS_DETAIL_CONDITION_ANY_ALGORITHM_HPP