condition_variable_fwd.hpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
  2. #define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // (C) Copyright 2007-8 Anthony Williams
  7. // (C) Copyright 2011-2012 Vicente J. Botet Escriba
  8. #include <boost/assert.hpp>
  9. #include <boost/throw_exception.hpp>
  10. #include <pthread.h>
  11. #include <boost/thread/cv_status.hpp>
  12. #include <boost/thread/mutex.hpp>
  13. #include <boost/thread/lock_types.hpp>
  14. #include <boost/thread/thread_time.hpp>
  15. #include <boost/thread/pthread/timespec.hpp>
  16. #if defined BOOST_THREAD_USES_DATETIME
  17. #include <boost/thread/xtime.hpp>
  18. #endif
  19. #ifdef BOOST_THREAD_USES_CHRONO
  20. #include <boost/chrono/system_clocks.hpp>
  21. #include <boost/chrono/ceil.hpp>
  22. #endif
  23. #include <boost/thread/detail/delete.hpp>
  24. #include <boost/date_time/posix_time/posix_time_duration.hpp>
  25. #include <boost/config/abi_prefix.hpp>
  26. namespace boost
  27. {
  28. class condition_variable
  29. {
  30. private:
  31. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  32. pthread_mutex_t internal_mutex;
  33. #endif
  34. pthread_cond_t cond;
  35. public:
  36. //private: // used by boost::thread::try_join_until
  37. inline bool do_wait_until(
  38. unique_lock<mutex>& lock,
  39. struct timespec const &timeout);
  40. bool do_wait_for(
  41. unique_lock<mutex>& lock,
  42. struct timespec const &timeout)
  43. {
  44. return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now()));
  45. }
  46. public:
  47. BOOST_THREAD_NO_COPYABLE(condition_variable)
  48. condition_variable()
  49. {
  50. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  51. int const res=pthread_mutex_init(&internal_mutex,NULL);
  52. if(res)
  53. {
  54. boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init"));
  55. }
  56. #endif
  57. int const res2=pthread_cond_init(&cond,NULL);
  58. if(res2)
  59. {
  60. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  61. BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
  62. #endif
  63. boost::throw_exception(thread_resource_error(res2, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init"));
  64. }
  65. }
  66. ~condition_variable()
  67. {
  68. int ret;
  69. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  70. do {
  71. ret = pthread_mutex_destroy(&internal_mutex);
  72. } while (ret == EINTR);
  73. BOOST_ASSERT(!ret);
  74. #endif
  75. do {
  76. ret = pthread_cond_destroy(&cond);
  77. } while (ret == EINTR);
  78. BOOST_ASSERT(!ret);
  79. }
  80. void wait(unique_lock<mutex>& m);
  81. template<typename predicate_type>
  82. void wait(unique_lock<mutex>& m,predicate_type pred)
  83. {
  84. while(!pred()) wait(m);
  85. }
  86. #if defined BOOST_THREAD_USES_DATETIME
  87. inline bool timed_wait(
  88. unique_lock<mutex>& m,
  89. boost::system_time const& abs_time)
  90. {
  91. #if defined BOOST_THREAD_WAIT_BUG
  92. struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG);
  93. return do_wait_until(m, timeout);
  94. #else
  95. struct timespec const timeout=detail::to_timespec(abs_time);
  96. return do_wait_until(m, timeout);
  97. #endif
  98. }
  99. bool timed_wait(
  100. unique_lock<mutex>& m,
  101. xtime const& abs_time)
  102. {
  103. return timed_wait(m,system_time(abs_time));
  104. }
  105. template<typename duration_type>
  106. bool timed_wait(
  107. unique_lock<mutex>& m,
  108. duration_type const& wait_duration)
  109. {
  110. return timed_wait(m,get_system_time()+wait_duration);
  111. }
  112. template<typename predicate_type>
  113. bool timed_wait(
  114. unique_lock<mutex>& m,
  115. boost::system_time const& abs_time,predicate_type pred)
  116. {
  117. while (!pred())
  118. {
  119. if(!timed_wait(m, abs_time))
  120. return pred();
  121. }
  122. return true;
  123. }
  124. template<typename predicate_type>
  125. bool timed_wait(
  126. unique_lock<mutex>& m,
  127. xtime const& abs_time,predicate_type pred)
  128. {
  129. return timed_wait(m,system_time(abs_time),pred);
  130. }
  131. template<typename duration_type,typename predicate_type>
  132. bool timed_wait(
  133. unique_lock<mutex>& m,
  134. duration_type const& wait_duration,predicate_type pred)
  135. {
  136. return timed_wait(m,get_system_time()+wait_duration,pred);
  137. }
  138. #endif
  139. #ifdef BOOST_THREAD_USES_CHRONO
  140. template <class Duration>
  141. cv_status
  142. wait_until(
  143. unique_lock<mutex>& lock,
  144. const chrono::time_point<chrono::system_clock, Duration>& t)
  145. {
  146. using namespace chrono;
  147. typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
  148. wait_until(lock,
  149. nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
  150. return system_clock::now() < t ? cv_status::no_timeout :
  151. cv_status::timeout;
  152. }
  153. template <class Clock, class Duration>
  154. cv_status
  155. wait_until(
  156. unique_lock<mutex>& lock,
  157. const chrono::time_point<Clock, Duration>& t)
  158. {
  159. using namespace chrono;
  160. system_clock::time_point s_now = system_clock::now();
  161. typename Clock::time_point c_now = Clock::now();
  162. wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
  163. return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
  164. }
  165. template <class Clock, class Duration, class Predicate>
  166. bool
  167. wait_until(
  168. unique_lock<mutex>& lock,
  169. const chrono::time_point<Clock, Duration>& t,
  170. Predicate pred)
  171. {
  172. while (!pred())
  173. {
  174. if (wait_until(lock, t) == cv_status::timeout)
  175. return pred();
  176. }
  177. return true;
  178. }
  179. template <class Rep, class Period>
  180. cv_status
  181. wait_for(
  182. unique_lock<mutex>& lock,
  183. const chrono::duration<Rep, Period>& d)
  184. {
  185. using namespace chrono;
  186. system_clock::time_point s_now = system_clock::now();
  187. steady_clock::time_point c_now = steady_clock::now();
  188. wait_until(lock, s_now + ceil<nanoseconds>(d));
  189. return steady_clock::now() - c_now < d ? cv_status::no_timeout :
  190. cv_status::timeout;
  191. }
  192. template <class Rep, class Period, class Predicate>
  193. bool
  194. wait_for(
  195. unique_lock<mutex>& lock,
  196. const chrono::duration<Rep, Period>& d,
  197. Predicate pred)
  198. {
  199. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  200. // while (!pred())
  201. // {
  202. // if (wait_for(lock, d) == cv_status::timeout)
  203. // return pred();
  204. // }
  205. // return true;
  206. }
  207. #endif
  208. #define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE
  209. typedef pthread_cond_t* native_handle_type;
  210. native_handle_type native_handle()
  211. {
  212. return &cond;
  213. }
  214. void notify_one() BOOST_NOEXCEPT;
  215. void notify_all() BOOST_NOEXCEPT;
  216. #ifdef BOOST_THREAD_USES_CHRONO
  217. inline cv_status wait_until(
  218. unique_lock<mutex>& lk,
  219. chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
  220. {
  221. using namespace chrono;
  222. nanoseconds d = tp.time_since_epoch();
  223. timespec ts = boost::detail::to_timespec(d);
  224. if (do_wait_until(lk, ts)) return cv_status::no_timeout;
  225. else return cv_status::timeout;
  226. }
  227. #endif
  228. };
  229. BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
  230. }
  231. #include <boost/config/abi_suffix.hpp>
  232. #endif