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
9 #include <boost/thread/win32/thread_primitives.hpp>
10 #include <boost/thread/win32/thread_data.hpp>
11 #include <boost/thread/win32/thread_data.hpp>
12 #include <boost/thread/win32/interlocked_read.hpp>
13 #include <boost/thread/cv_status.hpp>
14 #if defined BOOST_THREAD_USES_DATETIME
15 #include <boost/thread/xtime.hpp>
17 #include <boost/thread/mutex.hpp>
18 #include <boost/thread/thread_time.hpp>
19 #include <boost/thread/lock_guard.hpp>
20 #include <boost/thread/lock_types.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/intrusive_ptr.hpp>
25 #ifdef BOOST_THREAD_USES_CHRONO
26 #include <boost/chrono/system_clocks.hpp>
27 #include <boost/chrono/ceil.hpp>
34 #include <boost/config/abi_prefix.hpp>
40 class basic_cv_list_entry;
41 void intrusive_ptr_add_ref(basic_cv_list_entry * p);
42 void intrusive_ptr_release(basic_cv_list_entry * p);
44 class basic_cv_list_entry
47 detail::win32::handle_manager semaphore;
48 detail::win32::handle_manager wake_sem;
54 BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
55 explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
56 semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
57 wake_sem(wake_sem_.duplicate()),
58 waiters(1),notified(false),references(0)
61 static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
63 return !detail::interlocked_read_acquire(&entry->waiters);
68 BOOST_INTERLOCKED_INCREMENT(&waiters);
73 BOOST_INTERLOCKED_DECREMENT(&waiters);
76 void release(unsigned count_to_release)
79 detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
82 void release_waiters()
84 release(detail::interlocked_read_acquire(&waiters));
87 bool is_notified() const
92 bool wait(timeout abs_time)
94 return this_thread::interruptible_wait(semaphore,abs_time);
99 unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0);
100 BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
101 return woken_result==0;
104 friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
105 friend void intrusive_ptr_release(basic_cv_list_entry * p);
108 inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
110 BOOST_INTERLOCKED_INCREMENT(&p->references);
113 inline void intrusive_ptr_release(basic_cv_list_entry * p)
115 if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
121 class basic_condition_variable
123 boost::mutex internal_mutex;
125 unsigned active_generation_count;
127 typedef basic_cv_list_entry list_entry;
129 typedef boost::intrusive_ptr<list_entry> entry_ptr;
130 typedef std::vector<entry_ptr> generation_list;
132 generation_list generations;
133 detail::win32::handle_manager wake_sem;
135 void wake_waiters(long count_to_wake)
137 detail::interlocked_write_release(&total_count,total_count-count_to_wake);
138 detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
141 template<typename lock_type>
144 BOOST_THREAD_NO_COPYABLE(relocker)
148 relocker(lock_type& lock_):
149 lock(lock_),unlocked(false)
167 entry_ptr get_wait_entry()
169 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
173 wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
174 BOOST_ASSERT(wake_sem);
177 detail::interlocked_write_release(&total_count,total_count+1);
178 if(generations.empty() || generations.back()->is_notified())
180 entry_ptr new_entry(new list_entry(wake_sem));
181 generations.push_back(new_entry);
186 generations.back()->add_waiter();
187 return generations.back();
193 entry_ptr const entry;
194 boost::mutex& internal_mutex;
196 BOOST_THREAD_NO_COPYABLE(entry_manager)
197 entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
198 entry(entry_), internal_mutex(mutex_)
203 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
204 entry->remove_waiter();
207 list_entry* operator->()
215 template<typename lock_type>
216 bool do_wait(lock_type& lock,timeout abs_time)
218 relocker<lock_type> locker(lock);
220 entry_manager entry(get_wait_entry(), internal_mutex);
227 if(!entry->wait(abs_time))
232 woken=entry->woken();
237 template<typename lock_type,typename predicate_type>
238 bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
242 if(!do_wait(m, abs_time))
248 basic_condition_variable(const basic_condition_variable& other);
249 basic_condition_variable& operator=(const basic_condition_variable& other);
252 basic_condition_variable():
253 total_count(0),active_generation_count(0),wake_sem(0)
256 ~basic_condition_variable()
259 void notify_one() BOOST_NOEXCEPT
261 if(detail::interlocked_read_acquire(&total_count))
263 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
270 for(generation_list::iterator it=generations.begin(),
271 end=generations.end();
276 generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
280 void notify_all() BOOST_NOEXCEPT
282 if(detail::interlocked_read_acquire(&total_count))
284 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
289 wake_waiters(total_count);
290 for(generation_list::iterator it=generations.begin(),
291 end=generations.end();
294 (*it)->release_waiters();
297 wake_sem=detail::win32::handle(0);
304 class condition_variable:
305 private detail::basic_condition_variable
308 BOOST_THREAD_NO_COPYABLE(condition_variable)
312 using detail::basic_condition_variable::notify_one;
313 using detail::basic_condition_variable::notify_all;
315 void wait(unique_lock<mutex>& m)
317 do_wait(m,detail::timeout::sentinel());
320 template<typename predicate_type>
321 void wait(unique_lock<mutex>& m,predicate_type pred)
323 while(!pred()) wait(m);
327 #if defined BOOST_THREAD_USES_DATETIME
328 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
330 return do_wait(m,abs_time);
333 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
335 return do_wait(m,system_time(abs_time));
337 template<typename duration_type>
338 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
340 if (wait_duration.is_pos_infinity())
342 wait(m); // or do_wait(m,detail::timeout::sentinel());
345 if (wait_duration.is_special())
349 return do_wait(m,wait_duration.total_milliseconds());
352 template<typename predicate_type>
353 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
355 return do_wait(m,abs_time,pred);
357 template<typename predicate_type>
358 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
360 return do_wait(m,system_time(abs_time),pred);
362 template<typename duration_type,typename predicate_type>
363 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
365 return do_wait(m,wait_duration.total_milliseconds(),pred);
368 #ifdef BOOST_THREAD_USES_CHRONO
370 template <class Clock, class Duration>
373 unique_lock<mutex>& lock,
374 const chrono::time_point<Clock, Duration>& t)
376 using namespace chrono;
377 chrono::time_point<Clock, Duration> now = Clock::now();
379 return cv_status::timeout;
381 do_wait(lock, ceil<milliseconds>(t-now).count());
382 return Clock::now() < t ? cv_status::no_timeout :
386 template <class Rep, class Period>
389 unique_lock<mutex>& lock,
390 const chrono::duration<Rep, Period>& d)
392 using namespace chrono;
393 if (d<=chrono::duration<Rep, Period>::zero()) {
394 return cv_status::timeout;
397 steady_clock::time_point c_now = steady_clock::now();
398 do_wait(lock, ceil<milliseconds>(d).count());
399 return steady_clock::now() - c_now < d ? cv_status::no_timeout :
403 template <class Clock, class Duration, class Predicate>
406 unique_lock<mutex>& lock,
407 const chrono::time_point<Clock, Duration>& t,
412 if (wait_until(lock, t) == cv_status::timeout)
417 template <class Rep, class Period, class Predicate>
420 unique_lock<mutex>& lock,
421 const chrono::duration<Rep, Period>& d,
424 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
429 class condition_variable_any:
430 private detail::basic_condition_variable
433 BOOST_THREAD_NO_COPYABLE(condition_variable_any)
434 condition_variable_any()
437 using detail::basic_condition_variable::notify_one;
438 using detail::basic_condition_variable::notify_all;
440 template<typename lock_type>
441 void wait(lock_type& m)
443 do_wait(m,detail::timeout::sentinel());
446 template<typename lock_type,typename predicate_type>
447 void wait(lock_type& m,predicate_type pred)
449 while(!pred()) wait(m);
452 #if defined BOOST_THREAD_USES_DATETIME
453 template<typename lock_type>
454 bool timed_wait(lock_type& m,boost::system_time const& abs_time)
456 return do_wait(m,abs_time);
459 template<typename lock_type>
460 bool timed_wait(lock_type& m,boost::xtime const& abs_time)
462 return do_wait(m,system_time(abs_time));
465 template<typename lock_type,typename duration_type>
466 bool timed_wait(lock_type& m,duration_type const& wait_duration)
468 return do_wait(m,wait_duration.total_milliseconds());
471 template<typename lock_type,typename predicate_type>
472 bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
474 return do_wait(m,abs_time,pred);
477 template<typename lock_type,typename predicate_type>
478 bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
480 return do_wait(m,system_time(abs_time),pred);
483 template<typename lock_type,typename duration_type,typename predicate_type>
484 bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
486 return do_wait(m,wait_duration.total_milliseconds(),pred);
489 #ifdef BOOST_THREAD_USES_CHRONO
491 template <class lock_type, class Clock, class Duration>
495 const chrono::time_point<Clock, Duration>& t)
497 using namespace chrono;
498 chrono::time_point<Clock, Duration> now = Clock::now();
500 return cv_status::timeout;
502 do_wait(lock, ceil<milliseconds>(t-now).count());
503 return Clock::now() < t ? cv_status::no_timeout :
507 template <class lock_type, class Rep, class Period>
511 const chrono::duration<Rep, Period>& d)
513 using namespace chrono;
514 if (d<=chrono::duration<Rep, Period>::zero()) {
515 return cv_status::timeout;
517 steady_clock::time_point c_now = steady_clock::now();
518 do_wait(lock, ceil<milliseconds>(d).count());
519 return steady_clock::now() - c_now < d ? cv_status::no_timeout :
523 template <class lock_type, class Clock, class Duration, class Predicate>
527 const chrono::time_point<Clock, Duration>& t,
532 if (wait_until(lock, t) == cv_status::timeout)
538 template <class lock_type, class Rep, class Period, class Predicate>
542 const chrono::duration<Rep, Period>& d,
545 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
550 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
553 #include <boost/config/abi_suffix.hpp>