condition_variable.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. #ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
  2. #define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_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-10 Anthony Williams
  7. // (C) Copyright 2011-2012 Vicente J. Botet Escriba
  8. #include <boost/thread/pthread/timespec.hpp>
  9. #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
  10. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  11. #include <boost/thread/pthread/thread_data.hpp>
  12. #endif
  13. #include <boost/thread/pthread/condition_variable_fwd.hpp>
  14. #ifdef BOOST_THREAD_USES_CHRONO
  15. #include <boost/chrono/system_clocks.hpp>
  16. #include <boost/chrono/ceil.hpp>
  17. #endif
  18. #include <boost/thread/detail/delete.hpp>
  19. #include <boost/config/abi_prefix.hpp>
  20. namespace boost
  21. {
  22. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  23. namespace this_thread
  24. {
  25. void BOOST_THREAD_DECL interruption_point();
  26. }
  27. #endif
  28. namespace thread_cv_detail
  29. {
  30. template<typename MutexType>
  31. struct lock_on_exit
  32. {
  33. MutexType* m;
  34. lock_on_exit():
  35. m(0)
  36. {}
  37. void activate(MutexType& m_)
  38. {
  39. m_.unlock();
  40. m=&m_;
  41. }
  42. ~lock_on_exit()
  43. {
  44. if(m)
  45. {
  46. m->lock();
  47. }
  48. }
  49. };
  50. }
  51. inline void condition_variable::wait(unique_lock<mutex>& m)
  52. {
  53. #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
  54. if(! m.owns_lock())
  55. {
  56. boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned"));
  57. }
  58. #endif
  59. int res=0;
  60. {
  61. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  62. thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
  63. detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
  64. guard.activate(m);
  65. do {
  66. res = pthread_cond_wait(&cond,&internal_mutex);
  67. } while (res == EINTR);
  68. #else
  69. //boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
  70. pthread_mutex_t* the_mutex = m.mutex()->native_handle();
  71. do {
  72. res = pthread_cond_wait(&cond,the_mutex);
  73. } while (res == EINTR);
  74. #endif
  75. }
  76. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  77. this_thread::interruption_point();
  78. #endif
  79. if(res)
  80. {
  81. boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait"));
  82. }
  83. }
  84. inline bool condition_variable::do_wait_until(
  85. unique_lock<mutex>& m,
  86. struct timespec const &timeout)
  87. {
  88. #if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
  89. if (!m.owns_lock())
  90. {
  91. boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned"));
  92. }
  93. #endif
  94. thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
  95. int cond_res;
  96. {
  97. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  98. detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
  99. guard.activate(m);
  100. cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
  101. #else
  102. //boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
  103. pthread_mutex_t* the_mutex = m.mutex()->native_handle();
  104. cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
  105. #endif
  106. }
  107. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  108. this_thread::interruption_point();
  109. #endif
  110. if(cond_res==ETIMEDOUT)
  111. {
  112. return false;
  113. }
  114. if(cond_res)
  115. {
  116. boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait"));
  117. }
  118. return true;
  119. }
  120. inline void condition_variable::notify_one() BOOST_NOEXCEPT
  121. {
  122. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  123. boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
  124. #endif
  125. BOOST_VERIFY(!pthread_cond_signal(&cond));
  126. }
  127. inline void condition_variable::notify_all() BOOST_NOEXCEPT
  128. {
  129. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  130. boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
  131. #endif
  132. BOOST_VERIFY(!pthread_cond_broadcast(&cond));
  133. }
  134. class condition_variable_any
  135. {
  136. pthread_mutex_t internal_mutex;
  137. pthread_cond_t cond;
  138. public:
  139. BOOST_THREAD_NO_COPYABLE(condition_variable_any)
  140. condition_variable_any()
  141. {
  142. int const res=pthread_mutex_init(&internal_mutex,NULL);
  143. if(res)
  144. {
  145. boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init"));
  146. }
  147. int const res2=pthread_cond_init(&cond,NULL);
  148. if(res2)
  149. {
  150. BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
  151. boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
  152. }
  153. }
  154. ~condition_variable_any()
  155. {
  156. BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
  157. BOOST_VERIFY(!pthread_cond_destroy(&cond));
  158. }
  159. template<typename lock_type>
  160. void wait(lock_type& m)
  161. {
  162. int res=0;
  163. {
  164. thread_cv_detail::lock_on_exit<lock_type> guard;
  165. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  166. detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
  167. #else
  168. boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
  169. #endif
  170. guard.activate(m);
  171. res=pthread_cond_wait(&cond,&internal_mutex);
  172. }
  173. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  174. this_thread::interruption_point();
  175. #endif
  176. if(res)
  177. {
  178. boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait"));
  179. }
  180. }
  181. template<typename lock_type,typename predicate_type>
  182. void wait(lock_type& m,predicate_type pred)
  183. {
  184. while(!pred()) wait(m);
  185. }
  186. #if defined BOOST_THREAD_USES_DATETIME
  187. template<typename lock_type>
  188. bool timed_wait(lock_type& m,boost::system_time const& abs_time)
  189. {
  190. struct timespec const timeout=detail::to_timespec(abs_time);
  191. return do_wait_until(m, timeout);
  192. }
  193. template<typename lock_type>
  194. bool timed_wait(lock_type& m,xtime const& abs_time)
  195. {
  196. return timed_wait(m,system_time(abs_time));
  197. }
  198. template<typename lock_type,typename duration_type>
  199. bool timed_wait(lock_type& m,duration_type const& wait_duration)
  200. {
  201. return timed_wait(m,get_system_time()+wait_duration);
  202. }
  203. template<typename lock_type,typename predicate_type>
  204. bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
  205. {
  206. while (!pred())
  207. {
  208. if(!timed_wait(m, abs_time))
  209. return pred();
  210. }
  211. return true;
  212. }
  213. template<typename lock_type,typename predicate_type>
  214. bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred)
  215. {
  216. return timed_wait(m,system_time(abs_time),pred);
  217. }
  218. template<typename lock_type,typename duration_type,typename predicate_type>
  219. bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
  220. {
  221. return timed_wait(m,get_system_time()+wait_duration,pred);
  222. }
  223. #endif
  224. #ifdef BOOST_THREAD_USES_CHRONO
  225. template <class lock_type,class Duration>
  226. cv_status
  227. wait_until(
  228. lock_type& lock,
  229. const chrono::time_point<chrono::system_clock, Duration>& t)
  230. {
  231. using namespace chrono;
  232. typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
  233. wait_until(lock,
  234. nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
  235. return system_clock::now() < t ? cv_status::no_timeout :
  236. cv_status::timeout;
  237. }
  238. template <class lock_type, class Clock, class Duration>
  239. cv_status
  240. wait_until(
  241. lock_type& lock,
  242. const chrono::time_point<Clock, Duration>& t)
  243. {
  244. using namespace chrono;
  245. system_clock::time_point s_now = system_clock::now();
  246. typename Clock::time_point c_now = Clock::now();
  247. wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
  248. return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
  249. }
  250. template <class lock_type, class Clock, class Duration, class Predicate>
  251. bool
  252. wait_until(
  253. lock_type& lock,
  254. const chrono::time_point<Clock, Duration>& t,
  255. Predicate pred)
  256. {
  257. while (!pred())
  258. {
  259. if (wait_until(lock, t) == cv_status::timeout)
  260. return pred();
  261. }
  262. return true;
  263. }
  264. template <class lock_type, class Rep, class Period>
  265. cv_status
  266. wait_for(
  267. lock_type& lock,
  268. const chrono::duration<Rep, Period>& d)
  269. {
  270. using namespace chrono;
  271. system_clock::time_point s_now = system_clock::now();
  272. steady_clock::time_point c_now = steady_clock::now();
  273. wait_until(lock, s_now + ceil<nanoseconds>(d));
  274. return steady_clock::now() - c_now < d ? cv_status::no_timeout :
  275. cv_status::timeout;
  276. }
  277. template <class lock_type, class Rep, class Period, class Predicate>
  278. bool
  279. wait_for(
  280. lock_type& lock,
  281. const chrono::duration<Rep, Period>& d,
  282. Predicate pred)
  283. {
  284. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  285. // while (!pred())
  286. // {
  287. // if (wait_for(lock, d) == cv_status::timeout)
  288. // return pred();
  289. // }
  290. // return true;
  291. }
  292. template <class lock_type>
  293. cv_status wait_until(
  294. lock_type& lk,
  295. chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
  296. {
  297. using namespace chrono;
  298. nanoseconds d = tp.time_since_epoch();
  299. timespec ts = boost::detail::to_timespec(d);
  300. if (do_wait_until(lk, ts)) return cv_status::no_timeout;
  301. else return cv_status::timeout;
  302. }
  303. #endif
  304. void notify_one() BOOST_NOEXCEPT
  305. {
  306. boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
  307. BOOST_VERIFY(!pthread_cond_signal(&cond));
  308. }
  309. void notify_all() BOOST_NOEXCEPT
  310. {
  311. boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
  312. BOOST_VERIFY(!pthread_cond_broadcast(&cond));
  313. }
  314. private: // used by boost::thread::try_join_until
  315. template <class lock_type>
  316. inline bool do_wait_until(
  317. lock_type& m,
  318. struct timespec const &timeout)
  319. {
  320. int res=0;
  321. {
  322. thread_cv_detail::lock_on_exit<lock_type> guard;
  323. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  324. detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
  325. #else
  326. boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
  327. #endif
  328. guard.activate(m);
  329. res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
  330. }
  331. #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
  332. this_thread::interruption_point();
  333. #endif
  334. if(res==ETIMEDOUT)
  335. {
  336. return false;
  337. }
  338. if(res)
  339. {
  340. boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait"));
  341. }
  342. return true;
  343. }
  344. };
  345. }
  346. #include <boost/config/abi_suffix.hpp>
  347. #endif