condition_variable.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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::WaitForSingleObject(wake_sem,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. return do_wait(m,wait_duration.total_milliseconds());
  285. }
  286. template<typename predicate_type>
  287. bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
  288. {
  289. return do_wait(m,abs_time,pred);
  290. }
  291. template<typename predicate_type>
  292. bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
  293. {
  294. return do_wait(m,system_time(abs_time),pred);
  295. }
  296. template<typename duration_type,typename predicate_type>
  297. bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
  298. {
  299. return do_wait(m,wait_duration.total_milliseconds(),pred);
  300. }
  301. #endif
  302. #ifdef BOOST_THREAD_USES_CHRONO
  303. template <class Clock, class Duration>
  304. cv_status
  305. wait_until(
  306. unique_lock<mutex>& lock,
  307. const chrono::time_point<Clock, Duration>& t)
  308. {
  309. using namespace chrono;
  310. chrono::time_point<Clock, Duration> now = Clock::now();
  311. if (t<=now) {
  312. return cv_status::timeout;
  313. }
  314. do_wait(lock, ceil<milliseconds>(t-now).count());
  315. return Clock::now() < t ? cv_status::no_timeout :
  316. cv_status::timeout;
  317. }
  318. template <class Rep, class Period>
  319. cv_status
  320. wait_for(
  321. unique_lock<mutex>& lock,
  322. const chrono::duration<Rep, Period>& d)
  323. {
  324. using namespace chrono;
  325. if (d<=chrono::duration<Rep, Period>::zero()) {
  326. return cv_status::timeout;
  327. }
  328. steady_clock::time_point c_now = steady_clock::now();
  329. do_wait(lock, ceil<milliseconds>(d).count());
  330. return steady_clock::now() - c_now < d ? cv_status::no_timeout :
  331. cv_status::timeout;
  332. }
  333. template <class Clock, class Duration, class Predicate>
  334. bool
  335. wait_until(
  336. unique_lock<mutex>& lock,
  337. const chrono::time_point<Clock, Duration>& t,
  338. Predicate pred)
  339. {
  340. while (!pred())
  341. {
  342. if (wait_until(lock, t) == cv_status::timeout)
  343. return pred();
  344. }
  345. return true;
  346. }
  347. template <class Rep, class Period, class Predicate>
  348. bool
  349. wait_for(
  350. unique_lock<mutex>& lock,
  351. const chrono::duration<Rep, Period>& d,
  352. Predicate pred)
  353. {
  354. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  355. }
  356. #endif
  357. };
  358. class condition_variable_any:
  359. private detail::basic_condition_variable
  360. {
  361. public:
  362. BOOST_THREAD_NO_COPYABLE(condition_variable_any)
  363. condition_variable_any()
  364. {}
  365. using detail::basic_condition_variable::notify_one;
  366. using detail::basic_condition_variable::notify_all;
  367. template<typename lock_type>
  368. void wait(lock_type& m)
  369. {
  370. do_wait(m,detail::timeout::sentinel());
  371. }
  372. template<typename lock_type,typename predicate_type>
  373. void wait(lock_type& m,predicate_type pred)
  374. {
  375. while(!pred()) wait(m);
  376. }
  377. #if defined BOOST_THREAD_USES_DATETIME
  378. template<typename lock_type>
  379. bool timed_wait(lock_type& m,boost::system_time const& abs_time)
  380. {
  381. return do_wait(m,abs_time);
  382. }
  383. template<typename lock_type>
  384. bool timed_wait(lock_type& m,boost::xtime const& abs_time)
  385. {
  386. return do_wait(m,system_time(abs_time));
  387. }
  388. template<typename lock_type,typename duration_type>
  389. bool timed_wait(lock_type& m,duration_type const& wait_duration)
  390. {
  391. return do_wait(m,wait_duration.total_milliseconds());
  392. }
  393. template<typename lock_type,typename predicate_type>
  394. bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
  395. {
  396. return do_wait(m,abs_time,pred);
  397. }
  398. template<typename lock_type,typename predicate_type>
  399. bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
  400. {
  401. return do_wait(m,system_time(abs_time),pred);
  402. }
  403. template<typename lock_type,typename duration_type,typename predicate_type>
  404. bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
  405. {
  406. return do_wait(m,wait_duration.total_milliseconds(),pred);
  407. }
  408. #endif
  409. #ifdef BOOST_THREAD_USES_CHRONO
  410. template <class lock_type, class Clock, class Duration>
  411. cv_status
  412. wait_until(
  413. lock_type& lock,
  414. const chrono::time_point<Clock, Duration>& t)
  415. {
  416. using namespace chrono;
  417. chrono::time_point<Clock, Duration> now = Clock::now();
  418. if (t<=now) {
  419. return cv_status::timeout;
  420. }
  421. do_wait(lock, ceil<milliseconds>(t-now).count());
  422. return Clock::now() < t ? cv_status::no_timeout :
  423. cv_status::timeout;
  424. }
  425. template <class lock_type, class Rep, class Period>
  426. cv_status
  427. wait_for(
  428. lock_type& lock,
  429. const chrono::duration<Rep, Period>& d)
  430. {
  431. using namespace chrono;
  432. if (d<=chrono::duration<Rep, Period>::zero()) {
  433. return cv_status::timeout;
  434. }
  435. steady_clock::time_point c_now = steady_clock::now();
  436. do_wait(lock, ceil<milliseconds>(d).count());
  437. return steady_clock::now() - c_now < d ? cv_status::no_timeout :
  438. cv_status::timeout;
  439. }
  440. template <class lock_type, class Clock, class Duration, class Predicate>
  441. bool
  442. wait_until(
  443. lock_type& lock,
  444. const chrono::time_point<Clock, Duration>& t,
  445. Predicate pred)
  446. {
  447. while (!pred())
  448. {
  449. if (wait_until(lock, t) == cv_status::timeout)
  450. return pred();
  451. }
  452. return true;
  453. }
  454. template <class lock_type, class Rep, class Period, class Predicate>
  455. bool
  456. wait_for(
  457. lock_type& lock,
  458. const chrono::duration<Rep, Period>& d,
  459. Predicate pred)
  460. {
  461. return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
  462. }
  463. #endif
  464. };
  465. BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
  466. }
  467. #include <boost/config/abi_suffix.hpp>
  468. #endif