File indexing completed on 2025-12-16 10:10:03
0001 #ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
0002 #define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
0003
0004
0005
0006
0007
0008
0009 #include <boost/thread/win32/thread_primitives.hpp>
0010 #include <boost/thread/win32/thread_data.hpp>
0011 #include <boost/thread/win32/thread_data.hpp>
0012 #include <boost/thread/win32/interlocked_read.hpp>
0013 #include <boost/thread/cv_status.hpp>
0014 #if defined BOOST_THREAD_USES_DATETIME
0015 #include <boost/thread/xtime.hpp>
0016 #endif
0017 #include <boost/thread/mutex.hpp>
0018 #include <boost/thread/thread_time.hpp>
0019 #include <boost/thread/lock_guard.hpp>
0020 #include <boost/thread/lock_types.hpp>
0021 #include <boost/thread/detail/platform_time.hpp>
0022
0023 #include <boost/assert.hpp>
0024 #include <boost/intrusive_ptr.hpp>
0025
0026 #ifdef BOOST_THREAD_USES_CHRONO
0027 #include <boost/chrono/system_clocks.hpp>
0028 #include <boost/chrono/ceil.hpp>
0029 #endif
0030
0031 #include <limits.h>
0032 #include <algorithm>
0033 #include <vector>
0034
0035 #include <boost/config/abi_prefix.hpp>
0036
0037 namespace boost
0038 {
0039 namespace detail
0040 {
0041 class basic_cv_list_entry;
0042 void intrusive_ptr_add_ref(basic_cv_list_entry * p);
0043 void intrusive_ptr_release(basic_cv_list_entry * p);
0044
0045 class basic_cv_list_entry
0046 {
0047 private:
0048 detail::win32::handle_manager semaphore;
0049 detail::win32::handle_manager wake_sem;
0050 long waiters;
0051 bool notified;
0052 long references;
0053
0054 public:
0055 BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
0056 explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
0057 semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
0058 wake_sem(wake_sem_.duplicate()),
0059 waiters(1),notified(false),references(0)
0060 {}
0061
0062 static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
0063 {
0064 return !detail::interlocked_read_acquire(&entry->waiters);
0065 }
0066
0067 void add_waiter()
0068 {
0069 BOOST_INTERLOCKED_INCREMENT(&waiters);
0070 }
0071
0072 void remove_waiter()
0073 {
0074 BOOST_INTERLOCKED_DECREMENT(&waiters);
0075 }
0076
0077 void release(unsigned count_to_release)
0078 {
0079 notified=true;
0080 winapi::ReleaseSemaphore(semaphore,count_to_release,0);
0081 }
0082
0083 void release_waiters()
0084 {
0085 release(detail::interlocked_read_acquire(&waiters));
0086 }
0087
0088 bool is_notified() const
0089 {
0090 return notified;
0091 }
0092
0093 bool interruptible_wait(detail::internal_platform_timepoint const &timeout)
0094 {
0095 return this_thread::interruptible_wait(semaphore, timeout);
0096 }
0097
0098 bool woken()
0099 {
0100 unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0);
0101 BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
0102 return woken_result==0;
0103 }
0104
0105 friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
0106 friend void intrusive_ptr_release(basic_cv_list_entry * p);
0107 };
0108
0109 inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
0110 {
0111 BOOST_INTERLOCKED_INCREMENT(&p->references);
0112 }
0113
0114 inline void intrusive_ptr_release(basic_cv_list_entry * p)
0115 {
0116 if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
0117 {
0118 delete p;
0119 }
0120 }
0121
0122 class basic_condition_variable
0123 {
0124 boost::mutex internal_mutex;
0125 long total_count;
0126 unsigned active_generation_count;
0127
0128 typedef basic_cv_list_entry list_entry;
0129
0130 typedef boost::intrusive_ptr<list_entry> entry_ptr;
0131 typedef std::vector<entry_ptr> generation_list;
0132
0133 generation_list generations;
0134 detail::win32::handle_manager wake_sem;
0135
0136 void wake_waiters(long count_to_wake)
0137 {
0138 detail::interlocked_write_release(&total_count,total_count-count_to_wake);
0139 winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
0140 }
0141
0142 template<typename lock_type>
0143 struct relocker
0144 {
0145 BOOST_THREAD_NO_COPYABLE(relocker)
0146 lock_type& _lock;
0147 bool _unlocked;
0148
0149 relocker(lock_type& lock_):
0150 _lock(lock_), _unlocked(false)
0151 {}
0152 void unlock()
0153 {
0154 if ( ! _unlocked )
0155 {
0156 _lock.unlock();
0157 _unlocked=true;
0158 }
0159 }
0160 void lock()
0161 {
0162 if ( _unlocked )
0163 {
0164 _lock.lock();
0165 _unlocked=false;
0166 }
0167 }
0168 ~relocker() BOOST_NOEXCEPT_IF(false)
0169 {
0170 lock();
0171 }
0172 };
0173
0174
0175 entry_ptr get_wait_entry()
0176 {
0177 boost::lock_guard<boost::mutex> lk(internal_mutex);
0178 if(!wake_sem)
0179 {
0180 wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
0181 BOOST_ASSERT(wake_sem);
0182 }
0183
0184 detail::interlocked_write_release(&total_count,total_count+1);
0185 if(generations.empty() || generations.back()->is_notified())
0186 {
0187 entry_ptr new_entry(new list_entry(wake_sem));
0188 generations.push_back(new_entry);
0189 return new_entry;
0190 }
0191 else
0192 {
0193 generations.back()->add_waiter();
0194 return generations.back();
0195 }
0196 }
0197
0198 struct entry_manager
0199 {
0200 entry_ptr entry;
0201 boost::mutex& internal_mutex;
0202
0203
0204 BOOST_THREAD_NO_COPYABLE(entry_manager)
0205 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0206 entry_manager(entry_ptr&& entry_, boost::mutex& mutex_):
0207 entry(static_cast< entry_ptr&& >(entry_)), internal_mutex(mutex_)
0208 {}
0209 #else
0210 entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
0211 entry(entry_), internal_mutex(mutex_)
0212 {}
0213 #endif
0214
0215 void remove_waiter_and_reset()
0216 {
0217 if (entry) {
0218 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
0219 entry->remove_waiter();
0220 entry.reset();
0221 }
0222 }
0223 ~entry_manager() BOOST_NOEXCEPT_IF(false)
0224 {
0225 remove_waiter_and_reset();
0226 }
0227
0228 list_entry* operator->()
0229 {
0230 return entry.get();
0231 }
0232 };
0233
0234 protected:
0235 basic_condition_variable(const basic_condition_variable& other);
0236 basic_condition_variable& operator=(const basic_condition_variable& other);
0237
0238 public:
0239 basic_condition_variable():
0240 total_count(0),active_generation_count(0),wake_sem(0)
0241 {}
0242
0243 ~basic_condition_variable()
0244 {}
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255 template<typename lock_type>
0256 bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout)
0257 {
0258 relocker<lock_type> locker(lock);
0259 entry_manager entry(get_wait_entry(), internal_mutex);
0260 locker.unlock();
0261
0262 bool woken=false;
0263 while(!woken)
0264 {
0265 if(!entry->interruptible_wait(timeout))
0266 {
0267 return false;
0268 }
0269
0270 woken=entry->woken();
0271 }
0272
0273 entry.remove_waiter_and_reset();
0274 locker.lock();
0275 return true;
0276 }
0277
0278 void notify_one() BOOST_NOEXCEPT
0279 {
0280 if(detail::interlocked_read_acquire(&total_count))
0281 {
0282 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
0283 if(!total_count)
0284 {
0285 return;
0286 }
0287 wake_waiters(1);
0288
0289 for(generation_list::iterator it=generations.begin(),
0290 end=generations.end();
0291 it!=end;++it)
0292 {
0293 (*it)->release(1);
0294 }
0295 generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
0296 }
0297 }
0298
0299 void notify_all() BOOST_NOEXCEPT
0300 {
0301 if(detail::interlocked_read_acquire(&total_count))
0302 {
0303 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
0304 if(!total_count)
0305 {
0306 return;
0307 }
0308 wake_waiters(total_count);
0309 for(generation_list::iterator it=generations.begin(),
0310 end=generations.end();
0311 it!=end;++it)
0312 {
0313 (*it)->release_waiters();
0314 }
0315 generations.clear();
0316 wake_sem=detail::win32::handle(0);
0317 }
0318 }
0319
0320 };
0321 }
0322
0323 class condition_variable:
0324 private detail::basic_condition_variable
0325 {
0326 public:
0327 BOOST_THREAD_NO_COPYABLE(condition_variable)
0328 condition_variable()
0329 {}
0330
0331 using detail::basic_condition_variable::do_wait_until;
0332 using detail::basic_condition_variable::notify_one;
0333 using detail::basic_condition_variable::notify_all;
0334
0335 void wait(unique_lock<mutex>& m)
0336 {
0337 do_wait_until(m, detail::internal_platform_timepoint::getMax());
0338 }
0339
0340 template<typename predicate_type>
0341 void wait(unique_lock<mutex>& m,predicate_type pred)
0342 {
0343 while (!pred())
0344 {
0345 wait(m);
0346 }
0347 }
0348
0349 #if defined BOOST_THREAD_USES_DATETIME
0350 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
0351 {
0352
0353
0354
0355
0356
0357
0358
0359 const detail::real_platform_timepoint ts(abs_time);
0360 const detail::platform_duration d(ts - detail::real_platform_clock::now());
0361 do_wait_until(m, detail::internal_platform_clock::now() + d);
0362 return ts > detail::real_platform_clock::now();
0363 }
0364 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
0365 {
0366 return timed_wait(m, system_time(abs_time));
0367 }
0368 template<typename duration_type>
0369 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
0370 {
0371 if (wait_duration.is_pos_infinity())
0372 {
0373 wait(m);
0374 return true;
0375 }
0376 if (wait_duration.is_special())
0377 {
0378 return true;
0379 }
0380 const detail::platform_duration d(wait_duration);
0381 return do_wait_until(m, detail::internal_platform_clock::now() + d);
0382 }
0383
0384 template<typename predicate_type>
0385 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
0386 {
0387
0388
0389
0390 const detail::real_platform_timepoint ts(abs_time);
0391 while (!pred())
0392 {
0393 detail::platform_duration d(ts - detail::real_platform_clock::now());
0394 if (d <= detail::platform_duration::zero()) break;
0395 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0396 do_wait_until(m, detail::internal_platform_clock::now() + d);
0397 }
0398 return pred();
0399 }
0400 template<typename predicate_type>
0401 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
0402 {
0403 return timed_wait(m, system_time(abs_time), pred);
0404 }
0405 template<typename duration_type,typename predicate_type>
0406 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
0407 {
0408 if (wait_duration.is_pos_infinity())
0409 {
0410 while (!pred())
0411 {
0412 wait(m);
0413 }
0414 return true;
0415 }
0416 if (wait_duration.is_special())
0417 {
0418 return pred();
0419 }
0420 const detail::platform_duration d(wait_duration);
0421 const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
0422 while (!pred())
0423 {
0424 if (!do_wait_until(m, ts)) break;
0425 }
0426 return pred();
0427 }
0428 #endif
0429 #ifdef BOOST_THREAD_USES_CHRONO
0430 template <class Duration>
0431 cv_status
0432 wait_until(
0433 unique_lock<mutex>& lock,
0434 const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
0435 {
0436 const detail::internal_platform_timepoint ts(t);
0437 if (do_wait_until(lock, ts)) return cv_status::no_timeout;
0438 else return cv_status::timeout;
0439 }
0440
0441 template <class Clock, class Duration>
0442 cv_status
0443 wait_until(
0444 unique_lock<mutex>& lock,
0445 const chrono::time_point<Clock, Duration>& t)
0446 {
0447
0448
0449
0450
0451
0452
0453
0454 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0455 common_duration d(t - Clock::now());
0456 do_wait_until(lock, detail::internal_chrono_clock::now() + d);
0457 if (t > Clock::now()) return cv_status::no_timeout;
0458 else return cv_status::timeout;
0459 }
0460
0461 template <class Rep, class Period>
0462 cv_status
0463 wait_for(
0464 unique_lock<mutex>& lock,
0465 const chrono::duration<Rep, Period>& d)
0466 {
0467 return wait_until(lock, chrono::steady_clock::now() + d);
0468 }
0469
0470 template <class Duration, class Predicate>
0471 bool
0472 wait_until(
0473 unique_lock<mutex>& lock,
0474 const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
0475 Predicate pred)
0476 {
0477 const detail::internal_platform_timepoint ts(t);
0478 while (!pred())
0479 {
0480 if (!do_wait_until(lock, ts)) break;
0481 }
0482 return pred();
0483 }
0484
0485 template <class Clock, class Duration, class Predicate>
0486 bool
0487 wait_until(
0488 unique_lock<mutex>& lock,
0489 const chrono::time_point<Clock, Duration>& t,
0490 Predicate pred)
0491 {
0492
0493
0494
0495 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0496 while (!pred())
0497 {
0498 common_duration d(t - Clock::now());
0499 if (d <= common_duration::zero()) break;
0500 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0501 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
0502 }
0503 return pred();
0504 }
0505
0506 template <class Rep, class Period, class Predicate>
0507 bool
0508 wait_for(
0509 unique_lock<mutex>& lock,
0510 const chrono::duration<Rep, Period>& d,
0511 Predicate pred)
0512 {
0513 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
0514 }
0515 #endif
0516 };
0517
0518 class condition_variable_any:
0519 private detail::basic_condition_variable
0520 {
0521 public:
0522 BOOST_THREAD_NO_COPYABLE(condition_variable_any)
0523 condition_variable_any()
0524 {}
0525
0526 using detail::basic_condition_variable::do_wait_until;
0527 using detail::basic_condition_variable::notify_one;
0528 using detail::basic_condition_variable::notify_all;
0529
0530 template<typename lock_type>
0531 void wait(lock_type& m)
0532 {
0533 do_wait_until(m, detail::internal_platform_timepoint::getMax());
0534 }
0535
0536 template<typename lock_type,typename predicate_type>
0537 void wait(lock_type& m,predicate_type pred)
0538 {
0539 while (!pred())
0540 {
0541 wait(m);
0542 }
0543 }
0544
0545 #if defined BOOST_THREAD_USES_DATETIME
0546 template<typename lock_type>
0547 bool timed_wait(lock_type& m,boost::system_time const& abs_time)
0548 {
0549
0550
0551
0552
0553
0554
0555
0556 const detail::real_platform_timepoint ts(abs_time);
0557 const detail::platform_duration d(ts - detail::real_platform_clock::now());
0558 do_wait_until(m, detail::internal_platform_clock::now() + d);
0559 return ts > detail::real_platform_clock::now();
0560 }
0561
0562 template<typename lock_type>
0563 bool timed_wait(lock_type& m,boost::xtime const& abs_time)
0564 {
0565 return timed_wait(m, system_time(abs_time));
0566 }
0567
0568 template<typename lock_type,typename duration_type>
0569 bool timed_wait(lock_type& m,duration_type const& wait_duration)
0570 {
0571 if (wait_duration.is_pos_infinity())
0572 {
0573 wait(m);
0574 return true;
0575 }
0576 if (wait_duration.is_special())
0577 {
0578 return true;
0579 }
0580 const detail::platform_duration d(wait_duration);
0581 return do_wait_until(m, detail::internal_platform_clock::now() + d);
0582 }
0583
0584 template<typename lock_type,typename predicate_type>
0585 bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
0586 {
0587
0588
0589
0590 const detail::real_platform_timepoint ts(abs_time);
0591 while (!pred())
0592 {
0593 detail::platform_duration d(ts - detail::real_platform_clock::now());
0594 if (d <= detail::platform_duration::zero()) break;
0595 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0596 do_wait_until(m, detail::internal_platform_clock::now() + d);
0597 }
0598 return pred();
0599 }
0600
0601 template<typename lock_type,typename predicate_type>
0602 bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
0603 {
0604 return timed_wait(m, system_time(abs_time), pred);
0605 }
0606
0607 template<typename lock_type,typename duration_type,typename predicate_type>
0608 bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
0609 {
0610 if (wait_duration.is_pos_infinity())
0611 {
0612 while (!pred())
0613 {
0614 wait(m);
0615 }
0616 return true;
0617 }
0618 if (wait_duration.is_special())
0619 {
0620 return pred();
0621 }
0622 const detail::platform_duration d(wait_duration);
0623 const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
0624 while (!pred())
0625 {
0626 if (!do_wait_until(m, ts)) break;
0627 }
0628 return pred();
0629 }
0630 #endif
0631 #ifdef BOOST_THREAD_USES_CHRONO
0632 template <class lock_type,class Duration>
0633 cv_status
0634 wait_until(
0635 lock_type& lock,
0636 const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
0637 {
0638 const detail::internal_platform_timepoint ts(t);
0639 if (do_wait_until(lock, ts)) return cv_status::no_timeout;
0640 else return cv_status::timeout;
0641 }
0642
0643 template <class lock_type, class Clock, class Duration>
0644 cv_status
0645 wait_until(
0646 lock_type& lock,
0647 const chrono::time_point<Clock, Duration>& t)
0648 {
0649
0650
0651
0652
0653
0654
0655
0656 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0657 common_duration d(t - Clock::now());
0658 do_wait_until(lock, detail::internal_chrono_clock::now() + d);
0659 if (t > Clock::now()) return cv_status::no_timeout;
0660 else return cv_status::timeout;
0661 }
0662
0663 template <class lock_type, class Rep, class Period>
0664 cv_status
0665 wait_for(
0666 lock_type& lock,
0667 const chrono::duration<Rep, Period>& d)
0668 {
0669 return wait_until(lock, chrono::steady_clock::now() + d);
0670 }
0671
0672 template <class lock_type, class Clock, class Duration, class Predicate>
0673 bool
0674 wait_until(
0675 lock_type& lock,
0676 const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
0677 Predicate pred)
0678 {
0679 const detail::internal_platform_timepoint ts(t);
0680 while (!pred())
0681 {
0682 if (!do_wait_until(lock, ts)) break;
0683 }
0684 return pred();
0685 }
0686
0687 template <class lock_type, class Clock, class Duration, class Predicate>
0688 bool
0689 wait_until(
0690 lock_type& lock,
0691 const chrono::time_point<Clock, Duration>& t,
0692 Predicate pred)
0693 {
0694
0695
0696
0697 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0698 while (!pred())
0699 {
0700 common_duration d(t - Clock::now());
0701 if (d <= common_duration::zero()) break;
0702 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0703 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
0704 }
0705 return pred();
0706 }
0707
0708 template <class lock_type, class Rep, class Period, class Predicate>
0709 bool
0710 wait_for(
0711 lock_type& lock,
0712 const chrono::duration<Rep, Period>& d,
0713 Predicate pred)
0714 {
0715 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
0716 }
0717 #endif
0718 };
0719
0720 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
0721 }
0722
0723 #include <boost/config/abi_suffix.hpp>
0724
0725 #endif