|
Boost-Commit : |
From: anthony_at_[hidden]
Date: 2007-11-27 09:24:30
Author: anthonyw
Date: 2007-11-27 09:24:29 EST (Tue, 27 Nov 2007)
New Revision: 41413
URL: http://svn.boost.org/trac/boost/changeset/41413
Log:
add support for relative timeouts to condition timed_wait
Text files modified:
trunk/boost/thread/pthread/condition_variable.hpp | 14 +++
trunk/boost/thread/pthread/condition_variable_fwd.hpp | 14 +++
trunk/boost/thread/win32/condition_variable.hpp | 141 +++++++++++++++++++++++++++++++++++----
trunk/boost/thread/win32/thread_primitives.hpp | 3
trunk/libs/thread/test/test_condition.cpp | 50 +++++++++++++
5 files changed, 201 insertions(+), 21 deletions(-)
Modified: trunk/boost/thread/pthread/condition_variable.hpp
==============================================================================
--- trunk/boost/thread/pthread/condition_variable.hpp (original)
+++ trunk/boost/thread/pthread/condition_variable.hpp 2007-11-27 09:24:29 EST (Tue, 27 Nov 2007)
@@ -5,11 +5,9 @@
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
-#include <boost/thread/mutex.hpp>
#include <limits.h>
#include <boost/assert.hpp>
#include <algorithm>
-#include <boost/thread/thread_time.hpp>
#include <pthread.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
@@ -150,6 +148,18 @@
return true;
}
+ template<typename lock_type,typename predicate_type>
+ bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
+ {
+ return timed_wait(m,system_time(wait_until),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 timed_wait(m,get_system_time()+wait_duration,pred);
+ }
+
void notify_one()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
Modified: trunk/boost/thread/pthread/condition_variable_fwd.hpp
==============================================================================
--- trunk/boost/thread/pthread/condition_variable_fwd.hpp (original)
+++ trunk/boost/thread/pthread/condition_variable_fwd.hpp 2007-11-27 09:24:29 EST (Tue, 27 Nov 2007)
@@ -6,8 +6,10 @@
// (C) Copyright 2007 Anthony Williams
#include <pthread.h>
+#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
+#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -44,6 +46,18 @@
return true;
}
+ template<typename predicate_type>
+ bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
+ {
+ return timed_wait(m,system_time(wait_until),pred);
+ }
+
+ template<typename duration_type,typename predicate_type>
+ bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
+ {
+ return timed_wait(m,get_system_time()+wait_duration,pred);
+ }
+
void notify_one();
void notify_all();
};
Modified: trunk/boost/thread/win32/condition_variable.hpp
==============================================================================
--- trunk/boost/thread/win32/condition_variable.hpp (original)
+++ trunk/boost/thread/win32/condition_variable.hpp 2007-11-27 09:24:29 EST (Tue, 27 Nov 2007)
@@ -13,6 +13,8 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
+#include <boost/cstdint.hpp>
+#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -111,8 +113,78 @@
protected:
+ struct timeout
+ {
+ unsigned long start;
+ uintmax_t milliseconds;
+ bool relative;
+ boost::system_time abs_time;
+
+ static unsigned long const max_non_infinite_wait=0xfffffffe;
+
+ timeout(uintmax_t milliseconds_):
+ start(win32::GetTickCount()),
+ milliseconds(milliseconds_),
+ relative(true),
+ abs_time(boost::get_system_time())
+ {}
+
+ timeout(boost::system_time const& abs_time_):
+ start(win32::GetTickCount()),
+ milliseconds(0),
+ relative(false),
+ abs_time(abs_time_)
+ {}
+
+ struct remaining_time
+ {
+ bool more;
+ unsigned long milliseconds;
+
+ remaining_time(uintmax_t remaining):
+ more(remaining>max_non_infinite_wait),
+ milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
+ {}
+ };
+
+ remaining_time remaining_milliseconds() const
+ {
+ if(milliseconds==~uintmax_t(0))
+ {
+ return remaining_time(win32::infinite);
+ }
+ else if(relative)
+ {
+ unsigned long const now=win32::GetTickCount();
+ unsigned long const elapsed=now-start;
+ return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
+ }
+ else
+ {
+ system_time const now=get_system_time();
+ if(abs_time<now)
+ {
+ return remaining_time(0);
+ }
+ return remaining_time((abs_time-get_system_time()).total_milliseconds()+1);
+ }
+ }
+
+ static timeout sentinel()
+ {
+ return timeout(sentinel_type());
+ }
+ private:
+ struct sentinel_type
+ {};
+
+ explicit timeout(sentinel_type):
+ start(0),milliseconds(~uintmax_t(0)),relative(true)
+ {}
+ };
+
template<typename lock_type>
- bool do_wait(lock_type& lock,::boost::system_time const& wait_until)
+ bool do_wait(lock_type& lock,timeout wait_until)
{
detail::win32::handle_manager local_wake_sem;
detail::win32::handle_manager sem;
@@ -155,9 +227,21 @@
++generations[0].count;
sem=detail::win32::duplicate_handle(generations[0].semaphore);
}
- if(!this_thread::interruptible_wait(sem,::boost::detail::get_milliseconds_until(wait_until)))
+ while(true)
{
- break;
+ timeout::remaining_time const remaining=wait_until.remaining_milliseconds();
+ if(this_thread::interruptible_wait(sem,remaining.milliseconds))
+ {
+ break;
+ }
+ else if(!remaining.more)
+ {
+ return false;
+ }
+ if(wait_until.relative)
+ {
+ wait_until.milliseconds-=timeout::max_non_infinite_wait;
+ }
}
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
@@ -167,6 +251,17 @@
}
return woken;
}
+
+ template<typename lock_type,typename predicate_type>
+ bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
+ {
+ while (!pred())
+ {
+ if(!do_wait(m, wait_until))
+ return false;
+ }
+ return true;
+ }
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
@@ -238,7 +333,7 @@
public:
void wait(unique_lock<mutex>& m)
{
- do_wait(m,::boost::detail::get_system_time_sentinel());
+ do_wait(m,timeout::sentinel());
}
template<typename predicate_type>
@@ -256,12 +351,17 @@
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
{
- while (!pred())
- {
- if(!timed_wait(m, wait_until))
- return false;
- }
- return true;
+ return do_wait(m,wait_until,pred);
+ }
+ template<typename predicate_type>
+ bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
+ {
+ return do_wait(m,system_time(wait_until),pred);
+ }
+ template<typename duration_type,typename predicate_type>
+ bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
+ {
+ return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};
@@ -272,7 +372,7 @@
template<typename lock_type>
void wait(lock_type& m)
{
- do_wait(m,::boost::detail::get_system_time_sentinel());
+ do_wait(m,timeout::sentinel());
}
template<typename lock_type,typename predicate_type>
@@ -290,12 +390,19 @@
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
{
- while (!pred())
- {
- if(!timed_wait(m, wait_until))
- return false;
- }
- return true;
+ return do_wait(m,wait_until,pred);
+ }
+
+ template<typename lock_type,typename predicate_type>
+ bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
+ {
+ return do_wait(m,system_time(wait_until),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 timed_wait(m,wait_duration.total_milliseconds(),pred);
}
};
Modified: trunk/boost/thread/win32/thread_primitives.hpp
==============================================================================
--- trunk/boost/thread/win32/thread_primitives.hpp (original)
+++ trunk/boost/thread/win32/thread_primitives.hpp 2007-11-27 09:24:29 EST (Tue, 27 Nov 2007)
@@ -53,6 +53,7 @@
using ::SleepEx;
using ::Sleep;
using ::QueueUserAPC;
+ using ::GetTickCount;
}
}
}
@@ -120,6 +121,8 @@
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
+ __declspec(dllimport) unsigned long __stdcall GetTickCount();
+
# ifndef UNDER_CE
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
Modified: trunk/libs/thread/test/test_condition.cpp
==============================================================================
--- trunk/libs/thread/test/test_condition.cpp (original)
+++ trunk/libs/thread/test/test_condition.cpp 2007-11-27 09:24:29 EST (Tue, 27 Nov 2007)
@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
+// Copyright (C) 2007 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,7 +20,7 @@
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
- boost::condition condition;
+ boost::condition_variable condition;
int notified;
int awoken;
};
@@ -82,6 +83,15 @@
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
+
+ // Test predicate timed_wait with relative timeout
+ cond_predicate pred_rel(data->notified, 5);
+ BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK(pred_rel());
+ BOOST_CHECK_EQUAL(data->notified, 5);
+ data->awoken++;
+ data->condition.notify_one();
}
void do_test_condition_notify_one()
@@ -185,10 +195,19 @@
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
+
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 5)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 5);
}
thread.join();
- BOOST_CHECK_EQUAL(data.awoken, 4);
+ BOOST_CHECK_EQUAL(data.awoken, 5);
}
void test_condition_waits()
@@ -216,6 +235,32 @@
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
+bool fake_predicate()
+{
+ return false;
+}
+
+
+void do_test_timed_wait_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(5);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ bool const res=cond.timed_wait(lock,delay,fake_predicate);
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK(!res);
+ BOOST_CHECK((delay-boost::posix_time::milliseconds(10))<=(end-start));
+}
+
+
+void test_timed_wait_times_out()
+{
+ timed_test(&do_test_timed_wait_times_out, 15);
+}
+
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
@@ -226,6 +271,7 @@
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
test->add(BOOST_TEST_CASE(&test_condition_waits));
test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));
+ test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
return test;
}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk