condition_variable.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. #ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
  2. #define BOOST_THREAD_CONDITION_VARIABLE_WIN32_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/thread/win32/thread_primitives.hpp>
  9. #include <boost/thread/win32/thread_data.hpp>
  10. #include <boost/thread/win32/thread_data.hpp>
  11. #include <boost/thread/win32/interlocked_read.hpp>
  12. #include <boost/thread/cv_status.hpp>
  13. #if defined BOOST_THREAD_USES_DATETIME
  14. #include <boost/thread/xtime.hpp>
  15. #endif
  16. #include <boost/thread/mutex.hpp>
  17. #include <boost/thread/thread_time.hpp>
  18. #include <boost/thread/lock_guard.hpp>
  19. #include <boost/thread/lock_types.hpp>
  20. #include <boost/thread/detail/platform_time.hpp>
  21. #include <boost/assert.hpp>
  22. #include <boost/intrusive_ptr.hpp>
  23. #ifdef BOOST_THREAD_USES_CHRONO
  24. #include <boost/chrono/system_clocks.hpp>
  25. #include <boost/chrono/ceil.hpp>
  26. #endif
  27. #include <limits.h>
  28. #include <algorithm>
  29. #include <vector>
  30. #include <boost/config/abi_prefix.hpp>
  31. namespace boost
  32. {
  33. namespace detail
  34. {
  35. class basic_cv_list_entry;
  36. void intrusive_ptr_add_ref(basic_cv_list_entry * p);
  37. void intrusive_ptr_release(basic_cv_list_entry * p);
  38. class basic_cv_list_entry
  39. {
  40. private:
  41. detail::win32::handle_manager semaphore;
  42. detail::win32::handle_manager wake_sem;
  43. long waiters;
  44. bool notified;
  45. long references;
  46. public:
  47. BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
  48. explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
  49. semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
  50. wake_sem(wake_sem_.duplicate()),
  51. waiters(1),notified(false),references(0)
  52. {}
  53. static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
  54. {
  55. return !detail::interlocked_read_acquire(&entry->waiters);
  56. }
  57. void add_waiter()
  58. {
  59. BOOST_INTERLOCKED_INCREMENT(&waiters);
  60. }
  61. void remove_waiter()
  62. {
  63. BOOST_INTERLOCKED_DECREMENT(&waiters);
  64. }
  65. void release(unsigned count_to_release)
  66. {
  67. notified=true;
  68. winapi::ReleaseSemaphore(semaphore,count_to_release,0);
  69. }
  70. void release_waiters()
  71. {
  72. release(detail::interlocked_read_acquire(&waiters));
  73. }
  74. bool is_notified() const
  75. {
  76. return notified;
  77. }
  78. bool interruptible_wait(detail::internal_platform_timepoint const &timeout)
  79. {
  80. return this_thread::interruptible_wait(semaphore, timeout);
  81. }
  82. bool woken()
  83. {
  84. unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0);
  85. BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
  86. return woken_result==0;
  87. }
  88. friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
  89. friend void intrusive_ptr_release(basic_cv_list_entry * p);
  90. };
  91. inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
  92. {
  93. BOOST_INTERLOCKED_INCREMENT(&p->references);
  94. }
  95. inline void intrusive_ptr_release(basic_cv_list_entry * p)
  96. {
  97. if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
  98. {
  99. delete p;
  100. }
  101. }
  102. class basic_condition_variable
  103. {
  104. boost::mutex internal_mutex;
  105. long total_count;
  106. unsigned active_generation_count;
  107. typedef basic_cv_list_entry list_entry;
  108. typedef boost::intrusive_ptr<list_entry> entry_ptr;
  109. typedef std::vector<entry_ptr> generation_list;
  110. generation_list generations;
  111. detail::win32::handle_manager wake_sem;
  112. void wake_waiters(long count_to_wake)
  113. {
  114. detail::interlocked_write_release(&total_count,total_count-count_to_wake);
  115. winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
  116. }
  117. template<typename lock_type>
  118. struct relocker
  119. {
  120. BOOST_THREAD_NO_COPYABLE(relocker)
  121. lock_type& _lock;
  122. bool _unlocked;
  123. relocker(lock_type& lock_):
  124. _lock(lock_), _unlocked(false)
  125. {}
  126. void unlock()
  127. {
  128. if ( ! _unlocked )
  129. {
  130. _lock.unlock();
  131. _unlocked=true;
  132. }
  133. }
  134. void lock()
  135. {
  136. if ( _unlocked )
  137. {
  138. _lock.lock();
  139. _unlocked=false;
  140. }
  141. }
  142. ~relocker() BOOST_NOEXCEPT_IF(false)
  143. {
  144. lock();
  145. }
  146. };
  147. entry_ptr get_wait_entry()
  148. {
  149. boost::lock_guard<boost::mutex> lk(internal_mutex);
  150. if(!wake_sem)
  151. {
  152. wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
  153. BOOST_ASSERT(wake_sem);
  154. }
  155. detail::interlocked_write_release(&total_count,total_count+1);
  156. if(generations.empty() || generations.back()->is_notified())
  157. {
  158. entry_ptr new_entry(new list_entry(wake_sem));
  159. generations.push_back(new_entry);
  160. return new_entry;
  161. }
  162. else
  163. {
  164. generations.back()->add_waiter();
  165. return generations.back();
  166. }
  167. }
  168. struct entry_manager
  169. {
  170. entry_ptr entry;
  171. boost::mutex& internal_mutex;
  172. BOOST_THREAD_NO_COPYABLE(entry_manager)
  173. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  174. entry_manager(entry_ptr&& entry_, boost::mutex& mutex_):
  175. entry(static_cast< entry_ptr&& >(entry_)), internal_mutex(mutex_)
  176. {}
  177. #else
  178. entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
  179. entry(entry_), internal_mutex(mutex_)
  180. {}
  181. #endif
  182. void remove_waiter_and_reset()
  183. {
  184. if (entry) {
  185. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  186. entry->remove_waiter();
  187. entry.reset();
  188. }
  189. }
  190. ~entry_manager() BOOST_NOEXCEPT_IF(false)
  191. {
  192. remove_waiter_and_reset();
  193. }
  194. list_entry* operator->()
  195. {
  196. return entry.get();
  197. }
  198. };
  199. protected:
  200. basic_condition_variable(const basic_condition_variable& other);
  201. basic_condition_variable& operator=(const basic_condition_variable& other);
  202. public:
  203. basic_condition_variable():
  204. total_count(0),active_generation_count(0),wake_sem(0)
  205. {}
  206. ~basic_condition_variable()
  207. {}
  208. // When this function returns true:
  209. // * A notification (or sometimes a spurious OS signal) has been received
  210. // * Do not assume that the timeout has not been reached
  211. // * Do not assume that the predicate has been changed
  212. //
  213. // When this function returns false:
  214. // * The timeout has been reached
  215. // * Do not assume that a notification has not been received
  216. // * Do not assume that the predicate has not been changed
  217. template<typename lock_type>
  218. bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout)
  219. {
  220. relocker<lock_type> locker(lock);
  221. entry_manager entry(get_wait_entry(), internal_mutex);
  222. locker.unlock();
  223. bool woken=false;
  224. while(!woken)
  225. {
  226. if(!entry->interruptible_wait(timeout))
  227. {
  228. return false;
  229. }
  230. woken=entry->woken();
  231. }
  232. // do it here to avoid throwing on the destructor
  233. entry.remove_waiter_and_reset();
  234. locker.lock();
  235. return true;
  236. }
  237. void notify_one() BOOST_NOEXCEPT
  238. {
  239. if(detail::interlocked_read_acquire(&total_count))
  240. {
  241. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  242. if(!total_count)
  243. {
  244. return;
  245. }
  246. wake_waiters(1);
  247. for(generation_list::iterator it=generations.begin(),
  248. end=generations.end();
  249. it!=end;++it)
  250. {
  251. (*it)->release(1);
  252. }
  253. generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
  254. }
  255. }
  256. void notify_all() BOOST_NOEXCEPT
  257. {
  258. if(detail::interlocked_read_acquire(&total_count))
  259. {
  260. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  261. if(!total_count)
  262. {
  263. return;
  264. }
  265. wake_waiters(total_count);
  266. for(generation_list::iterator it=generations.begin(),
  267. end=generations.end();
  268. it!=end;++it)
  269. {
  270. (*it)->release_waiters();
  271. }
  272. generations.clear();
  273. wake_sem=detail::win32::handle(0);
  274. }
  275. }
  276. };
  277. }
  278. class condition_variable:
  279. private detail::basic_condition_variable
  280. {
  281. public:
  282. BOOST_THREAD_NO_COPYABLE(condition_variable)
  283. condition_variable()
  284. {}
  285. using detail::basic_condition_variable::do_wait_until;
  286. using detail::basic_condition_variable::notify_one;
  287. using detail::basic_condition_variable::notify_all;
  288. void wait(unique_lock<mutex>& m)
  289. {
  290. do_wait_until(m, detail::internal_platform_timepoint::getMax());
  291. }
  292. template<typename predicate_type>
  293. void wait(unique_lock<mutex>& m,predicate_type pred)
  294. {
  295. while (!pred())
  296. {
  297. wait(m);
  298. }
  299. }
  300. #if defined BOOST_THREAD_USES_DATETIME
  301. bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
  302. {
  303. // The system time may jump while this function is waiting. To compensate for this and time
  304. // out near the correct time, we could call do_wait_until() in a loop with a short timeout
  305. // and recheck the time remaining each time through the loop. However, because we can't
  306. // check the predicate each time do_wait_until() completes, this introduces the possibility
  307. // of not exiting the function when a notification occurs, since do_wait_until() may report
  308. // that it timed out even though a notification was received. The best this function can do
  309. // is report correctly whether or not it reached the timeout time.
  310. const detail::real_platform_timepoint ts(abs_time);
  311. const detail::platform_duration d(ts - detail::real_platform_clock::now());
  312. do_wait_until(m, detail::internal_platform_clock::now() + d);
  313. return ts > detail::real_platform_clock::now();
  314. }
  315. bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
  316. {
  317. return timed_wait(m, system_time(abs_time));
  318. }
  319. template<typename duration_type>
  320. bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
  321. {
  322. if (wait_duration.is_pos_infinity())
  323. {
  324. wait(m);
  325. return true;
  326. }
  327. if (wait_duration.is_special())
  328. {
  329. return true;
  330. }
  331. const detail::platform_duration d(wait_duration);
  332. return do_wait_until(m, detail::internal_platform_clock::now() + d);
  333. }
  334. template<typename predicate_type>
  335. bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
  336. {
  337. // The system time may jump while this function is waiting. To compensate for this
  338. // and time out near the correct time, we call do_wait_until() in a loop with a
  339. // short timeout and recheck the time remaining each time through the loop.
  340. const detail::real_platform_timepoint ts(abs_time);
  341. while (!pred())
  342. {
  343. detail::platform_duration d(ts - detail::real_platform_clock::now());
  344. if (d <= detail::platform_duration::zero()) break; // timeout occurred
  345. d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  346. do_wait_until(m, detail::internal_platform_clock::now() + d);
  347. }
  348. return pred();
  349. }
  350. template<typename predicate_type>
  351. bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
  352. {
  353. return timed_wait(m, system_time(abs_time), pred);
  354. }
  355. template<typename duration_type,typename predicate_type>
  356. bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
  357. {
  358. if (wait_duration.is_pos_infinity())
  359. {
  360. while (!pred())
  361. {
  362. wait(m);
  363. }
  364. return true;
  365. }
  366. if (wait_duration.is_special())
  367. {
  368. return pred();
  369. }
  370. const detail::platform_duration d(wait_duration);
  371. const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
  372. while (!pred())
  373. {
  374. if (!do_wait_until(m, ts)) break; // timeout occurred
  375. }
  376. return pred();
  377. }
  378. #endif
  379. #ifdef BOOST_THREAD_USES_CHRONO
  380. template <class Duration>
  381. cv_status
  382. wait_until(
  383. unique_lock<mutex>& lock,
  384. const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
  385. {
  386. const detail::internal_platform_timepoint ts(t);
  387. if (do_wait_until(lock, ts)) return cv_status::no_timeout;
  388. else return cv_status::timeout;
  389. }
  390. template <class Clock, class Duration>
  391. cv_status
  392. wait_until(
  393. unique_lock<mutex>& lock,
  394. const chrono::time_point<Clock, Duration>& t)
  395. {
  396. // The system time may jump while this function is waiting. To compensate for this and time
  397. // out near the correct time, we could call do_wait_until() in a loop with a short timeout
  398. // and recheck the time remaining each time through the loop. However, because we can't
  399. // check the predicate each time do_wait_until() completes, this introduces the possibility
  400. // of not exiting the function when a notification occurs, since do_wait_until() may report
  401. // that it timed out even though a notification was received. The best this function can do
  402. // is report correctly whether or not it reached the timeout time.
  403. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  404. common_duration d(t - Clock::now());
  405. do_wait_until(lock, detail::internal_chrono_clock::now() + d);
  406. if (t > Clock::now()) return cv_status::no_timeout;
  407. else return cv_status::timeout;
  408. }
  409. template <class Rep, class Period>
  410. cv_status
  411. wait_for(
  412. unique_lock<mutex>& lock,
  413. const chrono::duration<Rep, Period>& d)
  414. {
  415. return wait_until(lock, chrono::steady_clock::now() + d);
  416. }
  417. template <class Duration, class Predicate>
  418. bool
  419. wait_until(
  420. unique_lock<mutex>& lock,
  421. const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
  422. Predicate pred)
  423. {
  424. const detail::internal_platform_timepoint ts(t);
  425. while (!pred())
  426. {
  427. if (!do_wait_until(lock, ts)) break; // timeout occurred
  428. }
  429. return pred();
  430. }
  431. template <class Clock, class Duration, class Predicate>
  432. bool
  433. wait_until(
  434. unique_lock<mutex>& lock,
  435. const chrono::time_point<Clock, Duration>& t,
  436. Predicate pred)
  437. {
  438. // The system time may jump while this function is waiting. To compensate for this
  439. // and time out near the correct time, we call do_wait_until() in a loop with a
  440. // short timeout and recheck the time remaining each time through the loop.
  441. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  442. while (!pred())
  443. {
  444. common_duration d(t - Clock::now());
  445. if (d <= common_duration::zero()) break; // timeout occurred
  446. d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
  447. do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
  448. }
  449. return pred();
  450. }
  451. template <class Rep, class Period, class Predicate>
  452. bool
  453. wait_for(
  454. unique_lock<mutex>& lock,
  455. const chrono::duration<Rep, Period>& d,
  456. Predicate pred)
  457. {
  458. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  459. }
  460. #endif
  461. };
  462. class condition_variable_any:
  463. private detail::basic_condition_variable
  464. {
  465. public:
  466. BOOST_THREAD_NO_COPYABLE(condition_variable_any)
  467. condition_variable_any()
  468. {}
  469. using detail::basic_condition_variable::do_wait_until;
  470. using detail::basic_condition_variable::notify_one;
  471. using detail::basic_condition_variable::notify_all;
  472. template<typename lock_type>
  473. void wait(lock_type& m)
  474. {
  475. do_wait_until(m, detail::internal_platform_timepoint::getMax());
  476. }
  477. template<typename lock_type,typename predicate_type>
  478. void wait(lock_type& m,predicate_type pred)
  479. {
  480. while (!pred())
  481. {
  482. wait(m);
  483. }
  484. }
  485. #if defined BOOST_THREAD_USES_DATETIME
  486. template<typename lock_type>
  487. bool timed_wait(lock_type& m,boost::system_time const& abs_time)
  488. {
  489. // The system time may jump while this function is waiting. To compensate for this and time
  490. // out near the correct time, we could call do_wait_until() in a loop with a short timeout
  491. // and recheck the time remaining each time through the loop. However, because we can't
  492. // check the predicate each time do_wait_until() completes, this introduces the possibility
  493. // of not exiting the function when a notification occurs, since do_wait_until() may report
  494. // that it timed out even though a notification was received. The best this function can do
  495. // is report correctly whether or not it reached the timeout time.
  496. const detail::real_platform_timepoint ts(abs_time);
  497. const detail::platform_duration d(ts - detail::real_platform_clock::now());
  498. do_wait_until(m, detail::internal_platform_clock::now() + d);
  499. return ts > detail::real_platform_clock::now();
  500. }
  501. template<typename lock_type>
  502. bool timed_wait(lock_type& m,boost::xtime const& abs_time)
  503. {
  504. return timed_wait(m, system_time(abs_time));
  505. }
  506. template<typename lock_type,typename duration_type>
  507. bool timed_wait(lock_type& m,duration_type const& wait_duration)
  508. {
  509. if (wait_duration.is_pos_infinity())
  510. {
  511. wait(m);
  512. return true;
  513. }
  514. if (wait_duration.is_special())
  515. {
  516. return true;
  517. }
  518. const detail::platform_duration d(wait_duration);
  519. return do_wait_until(m, detail::internal_platform_clock::now() + d);
  520. }
  521. template<typename lock_type,typename predicate_type>
  522. bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
  523. {
  524. // The system time may jump while this function is waiting. To compensate for this
  525. // and time out near the correct time, we call do_wait_until() in a loop with a
  526. // short timeout and recheck the time remaining each time through the loop.
  527. const detail::real_platform_timepoint ts(abs_time);
  528. while (!pred())
  529. {
  530. detail::platform_duration d(ts - detail::real_platform_clock::now());
  531. if (d <= detail::platform_duration::zero()) break; // timeout occurred
  532. d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  533. do_wait_until(m, detail::internal_platform_clock::now() + d);
  534. }
  535. return pred();
  536. }
  537. template<typename lock_type,typename predicate_type>
  538. bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
  539. {
  540. return timed_wait(m, system_time(abs_time), pred);
  541. }
  542. template<typename lock_type,typename duration_type,typename predicate_type>
  543. bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
  544. {
  545. if (wait_duration.is_pos_infinity())
  546. {
  547. while (!pred())
  548. {
  549. wait(m);
  550. }
  551. return true;
  552. }
  553. if (wait_duration.is_special())
  554. {
  555. return pred();
  556. }
  557. const detail::platform_duration d(wait_duration);
  558. const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
  559. while (!pred())
  560. {
  561. if (!do_wait_until(m, ts)) break; // timeout occurred
  562. }
  563. return pred();
  564. }
  565. #endif
  566. #ifdef BOOST_THREAD_USES_CHRONO
  567. template <class lock_type,class Duration>
  568. cv_status
  569. wait_until(
  570. lock_type& lock,
  571. const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
  572. {
  573. const detail::internal_platform_timepoint ts(t);
  574. if (do_wait_until(lock, ts)) return cv_status::no_timeout;
  575. else return cv_status::timeout;
  576. }
  577. template <class lock_type, class Clock, class Duration>
  578. cv_status
  579. wait_until(
  580. lock_type& lock,
  581. const chrono::time_point<Clock, Duration>& t)
  582. {
  583. // The system time may jump while this function is waiting. To compensate for this and time
  584. // out near the correct time, we could call do_wait_until() in a loop with a short timeout
  585. // and recheck the time remaining each time through the loop. However, because we can't
  586. // check the predicate each time do_wait_until() completes, this introduces the possibility
  587. // of not exiting the function when a notification occurs, since do_wait_until() may report
  588. // that it timed out even though a notification was received. The best this function can do
  589. // is report correctly whether or not it reached the timeout time.
  590. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  591. common_duration d(t - Clock::now());
  592. do_wait_until(lock, detail::internal_chrono_clock::now() + d);
  593. if (t > Clock::now()) return cv_status::no_timeout;
  594. else return cv_status::timeout;
  595. }
  596. template <class lock_type, class Rep, class Period>
  597. cv_status
  598. wait_for(
  599. lock_type& lock,
  600. const chrono::duration<Rep, Period>& d)
  601. {
  602. return wait_until(lock, chrono::steady_clock::now() + d);
  603. }
  604. template <class lock_type, class Clock, class Duration, class Predicate>
  605. bool
  606. wait_until(
  607. lock_type& lock,
  608. const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
  609. Predicate pred)
  610. {
  611. const detail::internal_platform_timepoint ts(t);
  612. while (!pred())
  613. {
  614. if (!do_wait_until(lock, ts)) break; // timeout occurred
  615. }
  616. return pred();
  617. }
  618. template <class lock_type, class Clock, class Duration, class Predicate>
  619. bool
  620. wait_until(
  621. lock_type& lock,
  622. const chrono::time_point<Clock, Duration>& t,
  623. Predicate pred)
  624. {
  625. // The system time may jump while this function is waiting. To compensate for this
  626. // and time out near the correct time, we call do_wait_until() in a loop with a
  627. // short timeout and recheck the time remaining each time through the loop.
  628. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  629. while (!pred())
  630. {
  631. common_duration d(t - Clock::now());
  632. if (d <= common_duration::zero()) break; // timeout occurred
  633. d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
  634. do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
  635. }
  636. return pred();
  637. }
  638. template <class lock_type, class Rep, class Period, class Predicate>
  639. bool
  640. wait_for(
  641. lock_type& lock,
  642. const chrono::duration<Rep, Period>& d,
  643. Predicate pred)
  644. {
  645. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  646. }
  647. #endif
  648. };
  649. BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
  650. }
  651. #include <boost/config/abi_suffix.hpp>
  652. #endif