Boost logo

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