summaryrefslogtreecommitdiff
path: root/boost/thread/win32/condition_variable.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/thread/win32/condition_variable.hpp')
-rw-r--r--boost/thread/win32/condition_variable.hpp341
1 files changed, 239 insertions, 102 deletions
diff --git a/boost/thread/win32/condition_variable.hpp b/boost/thread/win32/condition_variable.hpp
index 5ff342f1fa..5cf975a534 100644
--- a/boost/thread/win32/condition_variable.hpp
+++ b/boost/thread/win32/condition_variable.hpp
@@ -18,6 +18,7 @@
#include <boost/thread/thread_time.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/lock_types.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#include <boost/assert.hpp>
#include <boost/intrusive_ptr.hpp>
@@ -76,7 +77,7 @@ namespace boost
void release(unsigned count_to_release)
{
notified=true;
- detail::winapi::ReleaseSemaphore(semaphore,count_to_release,0);
+ winapi::ReleaseSemaphore(semaphore,count_to_release,0);
}
void release_waiters()
@@ -89,14 +90,14 @@ namespace boost
return notified;
}
- bool wait(timeout abs_time)
+ bool interruptible_wait(detail::internal_platform_timepoint const &timeout)
{
- return this_thread::interruptible_wait(semaphore,abs_time);
+ return this_thread::interruptible_wait(semaphore, timeout);
}
bool woken()
{
- unsigned long const woken_result=detail::winapi::WaitForSingleObjectEx(wake_sem,0,0);
+ unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0);
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
return woken_result==0;
}
@@ -135,7 +136,7 @@ namespace boost
void wake_waiters(long count_to_wake)
{
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
- detail::winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
+ winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
}
template<typename lock_type>
@@ -230,10 +231,29 @@ namespace boost
}
};
-
protected:
+ basic_condition_variable(const basic_condition_variable& other);
+ basic_condition_variable& operator=(const basic_condition_variable& other);
+
+ public:
+ basic_condition_variable():
+ total_count(0),active_generation_count(0),wake_sem(0)
+ {}
+
+ ~basic_condition_variable()
+ {}
+
+ // When this function returns true:
+ // * A notification (or sometimes a spurious OS signal) has been received
+ // * Do not assume that the timeout has not been reached
+ // * Do not assume that the predicate has been changed
+ //
+ // When this function returns false:
+ // * The timeout has been reached
+ // * Do not assume that a notification has not been received
+ // * Do not assume that the predicate has not been changed
template<typename lock_type>
- bool do_wait(lock_type& lock,timeout abs_time)
+ bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout)
{
relocker<lock_type> locker(lock);
entry_manager entry(get_wait_entry(), internal_mutex);
@@ -242,7 +262,7 @@ namespace boost
bool woken=false;
while(!woken)
{
- if(!entry->wait(abs_time))
+ if(!entry->interruptible_wait(timeout))
{
return false;
}
@@ -252,31 +272,9 @@ namespace boost
// do it here to avoid throwing on the destructor
entry.remove_waiter_and_reset();
locker.lock();
- return woken;
- }
-
- template<typename lock_type,typename predicate_type>
- bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
- {
- while (!pred())
- {
- if(!do_wait(m, abs_time))
- return pred();
- }
- return true;
+ return true;
}
- basic_condition_variable(const basic_condition_variable& other);
- basic_condition_variable& operator=(const basic_condition_variable& other);
-
- public:
- basic_condition_variable():
- total_count(0),active_generation_count(0),wake_sem(0)
- {}
-
- ~basic_condition_variable()
- {}
-
void notify_one() BOOST_NOEXCEPT
{
if(detail::interlocked_read_acquire(&total_count))
@@ -330,75 +328,115 @@ namespace boost
condition_variable()
{}
+ using detail::basic_condition_variable::do_wait_until;
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
void wait(unique_lock<mutex>& m)
{
- do_wait(m,detail::timeout::sentinel());
+ do_wait_until(m, detail::internal_platform_timepoint::getMax());
}
template<typename predicate_type>
void wait(unique_lock<mutex>& m,predicate_type pred)
{
- while(!pred()) wait(m);
+ while (!pred())
+ {
+ wait(m);
+ }
}
-
#if defined BOOST_THREAD_USES_DATETIME
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
{
- return do_wait(m,abs_time);
+ // The system time may jump while this function is waiting. To compensate for this and time
+ // out near the correct time, we could call do_wait_until() in a loop with a short timeout
+ // and recheck the time remaining each time through the loop. However, because we can't
+ // check the predicate each time do_wait_until() completes, this introduces the possibility
+ // of not exiting the function when a notification occurs, since do_wait_until() may report
+ // that it timed out even though a notification was received. The best this function can do
+ // is report correctly whether or not it reached the timeout time.
+ const detail::real_platform_timepoint ts(abs_time);
+ const detail::platform_duration d(ts - detail::real_platform_clock::now());
+ do_wait_until(m, detail::internal_platform_clock::now() + d);
+ return ts > detail::real_platform_clock::now();
}
-
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
{
- return do_wait(m,system_time(abs_time));
+ return timed_wait(m, system_time(abs_time));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
- if (wait_duration.is_pos_infinity())
- {
- wait(m); // or do_wait(m,detail::timeout::sentinel());
- return true;
- }
- if (wait_duration.is_special())
- {
- return true;
- }
- return do_wait(m,wait_duration.total_milliseconds());
+ if (wait_duration.is_pos_infinity())
+ {
+ wait(m);
+ return true;
+ }
+ if (wait_duration.is_special())
+ {
+ return true;
+ }
+ const detail::platform_duration d(wait_duration);
+ return do_wait_until(m, detail::internal_platform_clock::now() + d);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
{
- return do_wait(m,abs_time,pred);
+ // The system time may jump while this function is waiting. To compensate for this
+ // and time out near the correct time, we call do_wait_until() in a loop with a
+ // short timeout and recheck the time remaining each time through the loop.
+ const detail::real_platform_timepoint ts(abs_time);
+ while (!pred())
+ {
+ detail::platform_duration d(ts - detail::real_platform_clock::now());
+ if (d <= detail::platform_duration::zero()) break; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ do_wait_until(m, detail::internal_platform_clock::now() + d);
+ }
+ return pred();
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
{
- return do_wait(m,system_time(abs_time),pred);
+ return timed_wait(m, system_time(abs_time), pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
if (wait_duration.is_pos_infinity())
{
- while (!pred())
- {
- wait(m); // or do_wait(m,detail::timeout::sentinel());
- }
- return true;
+ while (!pred())
+ {
+ wait(m);
+ }
+ return true;
}
if (wait_duration.is_special())
{
- return pred();
+ return pred();
}
- return do_wait(m,wait_duration.total_milliseconds(),pred);
+ const detail::platform_duration d(wait_duration);
+ const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
+ while (!pred())
+ {
+ if (!do_wait_until(m, ts)) break; // timeout occurred
+ }
+ return pred();
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Duration>
+ cv_status
+ wait_until(
+ unique_lock<mutex>& lock,
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
+ {
+ const detail::internal_platform_timepoint ts(t);
+ if (do_wait_until(lock, ts)) return cv_status::no_timeout;
+ else return cv_status::timeout;
+ }
template <class Clock, class Duration>
cv_status
@@ -406,14 +444,18 @@ namespace boost
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t)
{
- using namespace chrono;
- chrono::time_point<Clock, Duration> now = Clock::now();
- if (t<=now) {
- return cv_status::timeout;
- }
- do_wait(lock, ceil<milliseconds>(t-now).count());
- return Clock::now() < t ? cv_status::no_timeout :
- cv_status::timeout;
+ // The system time may jump while this function is waiting. To compensate for this and time
+ // out near the correct time, we could call do_wait_until() in a loop with a short timeout
+ // and recheck the time remaining each time through the loop. However, because we can't
+ // check the predicate each time do_wait_until() completes, this introduces the possibility
+ // of not exiting the function when a notification occurs, since do_wait_until() may report
+ // that it timed out even though a notification was received. The best this function can do
+ // is report correctly whether or not it reached the timeout time.
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ common_duration d(t - Clock::now());
+ do_wait_until(lock, detail::internal_chrono_clock::now() + d);
+ if (t > Clock::now()) return cv_status::no_timeout;
+ else return cv_status::timeout;
}
template <class Rep, class Period>
@@ -422,15 +464,22 @@ namespace boost
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d)
{
- using namespace chrono;
- if (d<=chrono::duration<Rep, Period>::zero()) {
- return cv_status::timeout;
- }
+ return wait_until(lock, chrono::steady_clock::now() + d);
+ }
- steady_clock::time_point c_now = steady_clock::now();
- do_wait(lock, ceil<milliseconds>(d).count());
- return steady_clock::now() - c_now < d ? cv_status::no_timeout :
- cv_status::timeout;
+ template <class Duration, class Predicate>
+ bool
+ wait_until(
+ unique_lock<mutex>& lock,
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
+ Predicate pred)
+ {
+ const detail::internal_platform_timepoint ts(t);
+ while (!pred())
+ {
+ if (!do_wait_until(lock, ts)) break; // timeout occurred
+ }
+ return pred();
}
template <class Clock, class Duration, class Predicate>
@@ -440,13 +489,20 @@ namespace boost
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
+ // The system time may jump while this function is waiting. To compensate for this
+ // and time out near the correct time, we call do_wait_until() in a loop with a
+ // short timeout and recheck the time remaining each time through the loop.
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
while (!pred())
{
- if (wait_until(lock, t) == cv_status::timeout)
- return pred();
+ common_duration d(t - Clock::now());
+ if (d <= common_duration::zero()) break; // timeout occurred
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
- return true;
+ return pred();
}
+
template <class Rep, class Period, class Predicate>
bool
wait_for(
@@ -467,59 +523,122 @@ namespace boost
condition_variable_any()
{}
+ using detail::basic_condition_variable::do_wait_until;
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
template<typename lock_type>
void wait(lock_type& m)
{
- do_wait(m,detail::timeout::sentinel());
+ do_wait_until(m, detail::internal_platform_timepoint::getMax());
}
template<typename lock_type,typename predicate_type>
void wait(lock_type& m,predicate_type pred)
{
- while(!pred()) wait(m);
+ while (!pred())
+ {
+ wait(m);
+ }
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time)
{
- return do_wait(m,abs_time);
+ // The system time may jump while this function is waiting. To compensate for this and time
+ // out near the correct time, we could call do_wait_until() in a loop with a short timeout
+ // and recheck the time remaining each time through the loop. However, because we can't
+ // check the predicate each time do_wait_until() completes, this introduces the possibility
+ // of not exiting the function when a notification occurs, since do_wait_until() may report
+ // that it timed out even though a notification was received. The best this function can do
+ // is report correctly whether or not it reached the timeout time.
+ const detail::real_platform_timepoint ts(abs_time);
+ const detail::platform_duration d(ts - detail::real_platform_clock::now());
+ do_wait_until(m, detail::internal_platform_clock::now() + d);
+ return ts > detail::real_platform_clock::now();
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::xtime const& abs_time)
{
- return do_wait(m,system_time(abs_time));
+ return timed_wait(m, system_time(abs_time));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
- return do_wait(m,wait_duration.total_milliseconds());
+ if (wait_duration.is_pos_infinity())
+ {
+ wait(m);
+ return true;
+ }
+ if (wait_duration.is_special())
+ {
+ return true;
+ }
+ const detail::platform_duration d(wait_duration);
+ return do_wait_until(m, detail::internal_platform_clock::now() + d);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
{
- return do_wait(m,abs_time,pred);
+ // The system time may jump while this function is waiting. To compensate for this
+ // and time out near the correct time, we call do_wait_until() in a loop with a
+ // short timeout and recheck the time remaining each time through the loop.
+ const detail::real_platform_timepoint ts(abs_time);
+ while (!pred())
+ {
+ detail::platform_duration d(ts - detail::real_platform_clock::now());
+ if (d <= detail::platform_duration::zero()) break; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ do_wait_until(m, detail::internal_platform_clock::now() + d);
+ }
+ return pred();
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
{
- return do_wait(m,system_time(abs_time),pred);
+ return timed_wait(m, system_time(abs_time), pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
- return do_wait(m,wait_duration.total_milliseconds(),pred);
+ if (wait_duration.is_pos_infinity())
+ {
+ while (!pred())
+ {
+ wait(m);
+ }
+ return true;
+ }
+ if (wait_duration.is_special())
+ {
+ return pred();
+ }
+ const detail::platform_duration d(wait_duration);
+ const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
+ while (!pred())
+ {
+ if (!do_wait_until(m, ts)) break; // timeout occurred
+ }
+ return pred();
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
+ template <class lock_type,class Duration>
+ cv_status
+ wait_until(
+ lock_type& lock,
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
+ {
+ const detail::internal_platform_timepoint ts(t);
+ if (do_wait_until(lock, ts)) return cv_status::no_timeout;
+ else return cv_status::timeout;
+ }
template <class lock_type, class Clock, class Duration>
cv_status
@@ -527,14 +646,18 @@ namespace boost
lock_type& lock,
const chrono::time_point<Clock, Duration>& t)
{
- using namespace chrono;
- chrono::time_point<Clock, Duration> now = Clock::now();
- if (t<=now) {
- return cv_status::timeout;
- }
- do_wait(lock, ceil<milliseconds>(t-now).count());
- return Clock::now() < t ? cv_status::no_timeout :
- cv_status::timeout;
+ // The system time may jump while this function is waiting. To compensate for this and time
+ // out near the correct time, we could call do_wait_until() in a loop with a short timeout
+ // and recheck the time remaining each time through the loop. However, because we can't
+ // check the predicate each time do_wait_until() completes, this introduces the possibility
+ // of not exiting the function when a notification occurs, since do_wait_until() may report
+ // that it timed out even though a notification was received. The best this function can do
+ // is report correctly whether or not it reached the timeout time.
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ common_duration d(t - Clock::now());
+ do_wait_until(lock, detail::internal_chrono_clock::now() + d);
+ if (t > Clock::now()) return cv_status::no_timeout;
+ else return cv_status::timeout;
}
template <class lock_type, class Rep, class Period>
@@ -543,14 +666,22 @@ namespace boost
lock_type& lock,
const chrono::duration<Rep, Period>& d)
{
- using namespace chrono;
- if (d<=chrono::duration<Rep, Period>::zero()) {
- return cv_status::timeout;
- }
- steady_clock::time_point c_now = steady_clock::now();
- do_wait(lock, ceil<milliseconds>(d).count());
- return steady_clock::now() - c_now < d ? cv_status::no_timeout :
- cv_status::timeout;
+ return wait_until(lock, chrono::steady_clock::now() + d);
+ }
+
+ template <class lock_type, class Clock, class Duration, class Predicate>
+ bool
+ wait_until(
+ lock_type& lock,
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
+ Predicate pred)
+ {
+ const detail::internal_platform_timepoint ts(t);
+ while (!pred())
+ {
+ if (!do_wait_until(lock, ts)) break; // timeout occurred
+ }
+ return pred();
}
template <class lock_type, class Clock, class Duration, class Predicate>
@@ -560,12 +691,18 @@ namespace boost
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
+ // The system time may jump while this function is waiting. To compensate for this
+ // and time out near the correct time, we call do_wait_until() in a loop with a
+ // short timeout and recheck the time remaining each time through the loop.
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
while (!pred())
{
- if (wait_until(lock, t) == cv_status::timeout)
- return pred();
+ common_duration d(t - Clock::now());
+ if (d <= common_duration::zero()) break; // timeout occurred
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
- return true;
+ return pred();
}
template <class lock_type, class Rep, class Period, class Predicate>