condition_variable.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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/assert.hpp>
  21. #include <boost/intrusive_ptr.hpp>
  22. #ifdef BOOST_THREAD_USES_CHRONO
  23. #include <boost/chrono/system_clocks.hpp>
  24. #include <boost/chrono/ceil.hpp>
  25. #endif
  26. #include <limits.h>
  27. #include <algorithm>
  28. #include <vector>
  29. #include <boost/config/abi_prefix.hpp>
  30. namespace boost
  31. {
  32. namespace detail
  33. {
  34. class basic_cv_list_entry;
  35. void intrusive_ptr_add_ref(basic_cv_list_entry * p);
  36. void intrusive_ptr_release(basic_cv_list_entry * p);
  37. class basic_cv_list_entry
  38. {
  39. private:
  40. detail::win32::handle_manager semaphore;
  41. detail::win32::handle_manager wake_sem;
  42. long waiters;
  43. bool notified;
  44. long references;
  45. public:
  46. BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
  47. explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
  48. semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
  49. wake_sem(wake_sem_.duplicate()),
  50. waiters(1),notified(false),references(0)
  51. {}
  52. static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
  53. {
  54. return !detail::interlocked_read_acquire(&entry->waiters);
  55. }
  56. void add_waiter()
  57. {
  58. BOOST_INTERLOCKED_INCREMENT(&waiters);
  59. }
  60. void remove_waiter()
  61. {
  62. BOOST_INTERLOCKED_DECREMENT(&waiters);
  63. }
  64. void release(unsigned count_to_release)
  65. {
  66. notified=true;
  67. detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
  68. }
  69. void release_waiters()
  70. {
  71. release(detail::interlocked_read_acquire(&waiters));
  72. }
  73. bool is_notified() const
  74. {
  75. return notified;
  76. }
  77. bool wait(timeout abs_time)
  78. {
  79. return this_thread::interruptible_wait(semaphore,abs_time);
  80. }
  81. bool woken()
  82. {
  83. unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0);
  84. BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
  85. return woken_result==0;
  86. }
  87. friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
  88. friend void intrusive_ptr_release(basic_cv_list_entry * p);
  89. };
  90. inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
  91. {
  92. BOOST_INTERLOCKED_INCREMENT(&p->references);
  93. }
  94. inline void intrusive_ptr_release(basic_cv_list_entry * p)
  95. {
  96. if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
  97. {
  98. delete p;
  99. }
  100. }
  101. class basic_condition_variable
  102. {
  103. boost::mutex internal_mutex;
  104. long total_count;
  105. unsigned active_generation_count;
  106. typedef basic_cv_list_entry list_entry;
  107. typedef boost::intrusive_ptr<list_entry> entry_ptr;
  108. typedef std::vector<entry_ptr> generation_list;
  109. generation_list generations;
  110. detail::win32::handle_manager wake_sem;
  111. void wake_waiters(long count_to_wake)
  112. {
  113. detail::interlocked_write_release(&total_count,total_count-count_to_wake);
  114. detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
  115. }
  116. template<typename lock_type>
  117. struct relocker
  118. {
  119. BOOST_THREAD_NO_COPYABLE(relocker)
  120. lock_type& lock;
  121. bool unlocked;
  122. relocker(lock_type& lock_):
  123. lock(lock_),unlocked(false)
  124. {}
  125. void unlock()
  126. {
  127. lock.unlock();
  128. unlocked=true;
  129. }
  130. ~relocker()
  131. {
  132. if(unlocked)
  133. {
  134. lock.lock();
  135. }
  136. }
  137. };
  138. entry_ptr get_wait_entry()
  139. {
  140. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  141. if(!wake_sem)
  142. {
  143. wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
  144. BOOST_ASSERT(wake_sem);
  145. }
  146. detail::interlocked_write_release(&total_count,total_count+1);
  147. if(generations.empty() || generations.back()->is_notified())
  148. {
  149. entry_ptr new_entry(new list_entry(wake_sem));
  150. generations.push_back(new_entry);
  151. return new_entry;
  152. }
  153. else
  154. {
  155. generations.back()->add_waiter();
  156. return generations.back();
  157. }
  158. }
  159. struct entry_manager
  160. {
  161. entry_ptr const entry;
  162. boost::mutex& internal_mutex;
  163. BOOST_THREAD_NO_COPYABLE(entry_manager)
  164. entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
  165. entry(entry_), internal_mutex(mutex_)
  166. {}
  167. ~entry_manager()
  168. {
  169. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  170. entry->remove_waiter();
  171. }
  172. list_entry* operator->()
  173. {
  174. return entry.get();
  175. }
  176. };
  177. protected:
  178. template<typename lock_type>
  179. bool do_wait(lock_type& lock,timeout abs_time)
  180. {
  181. relocker<lock_type> locker(lock);
  182. entry_manager entry(get_wait_entry(), internal_mutex);
  183. locker.unlock();
  184. bool woken=false;
  185. while(!woken)
  186. {
  187. if(!entry->wait(abs_time))
  188. {
  189. return false;
  190. }
  191. woken=entry->woken();
  192. }
  193. return woken;
  194. }
  195. template<typename lock_type,typename predicate_type>
  196. bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
  197. {
  198. while (!pred())
  199. {
  200. if(!do_wait(m, abs_time))
  201. return pred();
  202. }
  203. return true;
  204. }
  205. basic_condition_variable(const basic_condition_variable& other);
  206. basic_condition_variable& operator=(const basic_condition_variable& other);
  207. public:
  208. basic_condition_variable():
  209. total_count(0),active_generation_count(0),wake_sem(0)
  210. {}
  211. ~basic_condition_variable()
  212. {}
  213. void notify_one() BOOST_NOEXCEPT
  214. {
  215. if(detail::interlocked_read_acquire(&total_count))
  216. {
  217. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  218. if(!total_count)
  219. {
  220. return;
  221. }
  222. wake_waiters(1);
  223. for(generation_list::iterator it=generations.begin(),
  224. end=generations.end();
  225. it!=end;++it)
  226. {
  227. (*it)->release(1);
  228. }
  229. generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
  230. }
  231. }
  232. void notify_all() BOOST_NOEXCEPT
  233. {
  234. if(detail::interlocked_read_acquire(&total_count))
  235. {
  236. boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
  237. if(!total_count)
  238. {
  239. return;
  240. }
  241. wake_waiters(total_count);
  242. for(generation_list::iterator it=generations.begin(),
  243. end=generations.end();
  244. it!=end;++it)
  245. {
  246. (*it)->release_waiters();
  247. }
  248. generations.clear();
  249. wake_sem=detail::win32::handle(0);
  250. }
  251. }
  252. };
  253. }
  254. class condition_variable:
  255. private detail::basic_condition_variable
  256. {
  257. public:
  258. BOOST_THREAD_NO_COPYABLE(condition_variable)
  259. condition_variable()
  260. {}
  261. using detail::basic_condition_variable::notify_one;
  262. using detail::basic_condition_variable::notify_all;
  263. void wait(unique_lock<mutex>& m)
  264. {
  265. do_wait(m,detail::timeout::sentinel());
  266. }
  267. template<typename predicate_type>
  268. void wait(unique_lock<mutex>& m,predicate_type pred)
  269. {
  270. while(!pred()) wait(m);
  271. }
  272. #if defined BOOST_THREAD_USES_DATETIME
  273. bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
  274. {
  275. return do_wait(m,abs_time);
  276. }
  277. bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
  278. {
  279. return do_wait(m,system_time(abs_time));
  280. }
  281. template<typename duration_type>
  282. bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
  283. {
  284. if (wait_duration.is_pos_infinity())
  285. {
  286. wait(m); // or do_wait(m,detail::timeout::sentinel());
  287. return true;
  288. }
  289. if (wait_duration.is_special())
  290. {
  291. return true;
  292. }
  293. return do_wait(m,wait_duration.total_milliseconds());
  294. }
  295. template<typename predicate_type>
  296. bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
  297. {
  298. return do_wait(m,abs_time,pred);
  299. }
  300. template<typename predicate_type>
  301. bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
  302. {
  303. return do_wait(m,system_time(abs_time),pred);
  304. }
  305. template<typename duration_type,typename predicate_type>
  306. bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
  307. {
  308. if (wait_duration.is_pos_infinity())
  309. {
  310. while (!pred())
  311. {
  312. wait(m); // or do_wait(m,detail::timeout::sentinel());
  313. }
  314. return true;
  315. }
  316. if (wait_duration.is_special())
  317. {
  318. return pred();
  319. }
  320. return do_wait(m,wait_duration.total_milliseconds(),pred);
  321. }
  322. #endif
  323. #ifdef BOOST_THREAD_USES_CHRONO
  324. template <class Clock, class Duration>
  325. cv_status
  326. wait_until(
  327. unique_lock<mutex>& lock,
  328. const chrono::time_point<Clock, Duration>& t)
  329. {
  330. using namespace chrono;
  331. chrono::time_point<Clock, Duration> now = Clock::now();
  332. if (t<=now) {
  333. return cv_status::timeout;
  334. }
  335. do_wait(lock, ceil<milliseconds>(t-now).count());
  336. return Clock::now() < t ? cv_status::no_timeout :
  337. cv_status::timeout;
  338. }
  339. template <class Rep, class Period>
  340. cv_status
  341. wait_for(
  342. unique_lock<mutex>& lock,
  343. const chrono::duration<Rep, Period>& d)
  344. {
  345. using namespace chrono;
  346. if (d<=chrono::duration<Rep, Period>::zero()) {
  347. return cv_status::timeout;
  348. }
  349. steady_clock::time_point c_now = steady_clock::now();
  350. do_wait(lock, ceil<milliseconds>(d).count());
  351. return steady_clock::now() - c_now < d ? cv_status::no_timeout :
  352. cv_status::timeout;
  353. }
  354. template <class Clock, class Duration, class Predicate>
  355. bool
  356. wait_until(
  357. unique_lock<mutex>& lock,
  358. const chrono::time_point<Clock, Duration>& t,
  359. Predicate pred)
  360. {
  361. while (!pred())
  362. {
  363. if (wait_until(lock, t) == cv_status::timeout)
  364. return pred();
  365. }
  366. return true;
  367. }
  368. template <class Rep, class Period, class Predicate>
  369. bool
  370. wait_for(
  371. unique_lock<mutex>& lock,
  372. const chrono::duration<Rep, Period>& d,
  373. Predicate pred)
  374. {
  375. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  376. }
  377. #endif
  378. };
  379. class condition_variable_any:
  380. private detail::basic_condition_variable
  381. {
  382. public:
  383. BOOST_THREAD_NO_COPYABLE(condition_variable_any)
  384. condition_variable_any()
  385. {}
  386. using detail::basic_condition_variable::notify_one;
  387. using detail::basic_condition_variable::notify_all;
  388. template<typename lock_type>
  389. void wait(lock_type& m)
  390. {
  391. do_wait(m,detail::timeout::sentinel());
  392. }
  393. template<typename lock_type,typename predicate_type>
  394. void wait(lock_type& m,predicate_type pred)
  395. {
  396. while(!pred()) wait(m);
  397. }
  398. #if defined BOOST_THREAD_USES_DATETIME
  399. template<typename lock_type>
  400. bool timed_wait(lock_type& m,boost::system_time const& abs_time)
  401. {
  402. return do_wait(m,abs_time);
  403. }
  404. template<typename lock_type>
  405. bool timed_wait(lock_type& m,boost::xtime const& abs_time)
  406. {
  407. return do_wait(m,system_time(abs_time));
  408. }
  409. template<typename lock_type,typename duration_type>
  410. bool timed_wait(lock_type& m,duration_type const& wait_duration)
  411. {
  412. return do_wait(m,wait_duration.total_milliseconds());
  413. }
  414. template<typename lock_type,typename predicate_type>
  415. bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
  416. {
  417. return do_wait(m,abs_time,pred);
  418. }
  419. template<typename lock_type,typename predicate_type>
  420. bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
  421. {
  422. return do_wait(m,system_time(abs_time),pred);
  423. }
  424. template<typename lock_type,typename duration_type,typename predicate_type>
  425. bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
  426. {
  427. return do_wait(m,wait_duration.total_milliseconds(),pred);
  428. }
  429. #endif
  430. #ifdef BOOST_THREAD_USES_CHRONO
  431. template <class lock_type, class Clock, class Duration>
  432. cv_status
  433. wait_until(
  434. lock_type& lock,
  435. const chrono::time_point<Clock, Duration>& t)
  436. {
  437. using namespace chrono;
  438. chrono::time_point<Clock, Duration> now = Clock::now();
  439. if (t<=now) {
  440. return cv_status::timeout;
  441. }
  442. do_wait(lock, ceil<milliseconds>(t-now).count());
  443. return Clock::now() < t ? cv_status::no_timeout :
  444. cv_status::timeout;
  445. }
  446. template <class lock_type, class Rep, class Period>
  447. cv_status
  448. wait_for(
  449. lock_type& lock,
  450. const chrono::duration<Rep, Period>& d)
  451. {
  452. using namespace chrono;
  453. if (d<=chrono::duration<Rep, Period>::zero()) {
  454. return cv_status::timeout;
  455. }
  456. steady_clock::time_point c_now = steady_clock::now();
  457. do_wait(lock, ceil<milliseconds>(d).count());
  458. return steady_clock::now() - c_now < d ? cv_status::no_timeout :
  459. cv_status::timeout;
  460. }
  461. template <class lock_type, class Clock, class Duration, class Predicate>
  462. bool
  463. wait_until(
  464. lock_type& lock,
  465. const chrono::time_point<Clock, Duration>& t,
  466. Predicate pred)
  467. {
  468. while (!pred())
  469. {
  470. if (wait_until(lock, t) == cv_status::timeout)
  471. return pred();
  472. }
  473. return true;
  474. }
  475. template <class lock_type, class Rep, class Period, class Predicate>
  476. bool
  477. wait_for(
  478. lock_type& lock,
  479. const chrono::duration<Rep, Period>& d,
  480. Predicate pred)
  481. {
  482. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  483. }
  484. #endif
  485. };
  486. BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
  487. }
  488. #include <boost/config/abi_suffix.hpp>
  489. #endif