Boost logo

Boost-Commit :

From: anthony_at_[hidden]
Date: 2007-11-30 13:38:22


Author: anthonyw
Date: 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
New Revision: 41505
URL: http://svn.boost.org/trac/boost/changeset/41505

Log:
interruptible_wait (and hence condition timed_wait) now uses a WaitableTimer where possible, to be robust in the face of clock changes
Added:
   trunk/libs/thread/test/condition_test_common.hpp (contents, props changed)
   trunk/libs/thread/test/test_condition_notify_all.cpp (contents, props changed)
   trunk/libs/thread/test/test_condition_notify_one.cpp (contents, props changed)
   trunk/libs/thread/test/test_condition_timed_wait_times_out.cpp (contents, props changed)
Text files modified:
   trunk/boost/thread/win32/condition_variable.hpp | 156 ++++++++++-----------------------------
   trunk/boost/thread/win32/shared_mutex.hpp | 8 +-
   trunk/boost/thread/win32/thread.hpp | 79 ++++++++++++++++++++
   trunk/libs/thread/src/win32/thread.cpp | 133 ++++++++++++++++++++++++++++++---
   trunk/libs/thread/src/win32/tss_pe.cpp | 3
   trunk/libs/thread/test/Jamfile.v2 | 4 +
   trunk/libs/thread/test/test_barrier.cpp | 2
   trunk/libs/thread/test/test_condition.cpp | 90 -----------------------
   trunk/libs/thread/test/test_shared_mutex.cpp | 2
   trunk/libs/thread/test/util.inl | 21 +++++
   10 files changed, 269 insertions(+), 229 deletions(-)

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-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -13,7 +13,6 @@
 #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
@@ -112,136 +111,65 @@
             };
             
 
- protected:
- struct timeout
+ template<typename lock_type>
+ void start_wait_loop_first_time(relocker<lock_type>& locker,
+ detail::win32::handle_manager& local_wake_sem)
             {
- 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
+ locker.unlock();
+ if(!wake_sem)
                 {
- 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
+ wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
+ BOOST_ASSERT(wake_sem);
+ }
+ local_wake_sem=detail::win32::duplicate_handle(wake_sem);
+
+ if(generations[0].notified)
                 {
- 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);
- }
+ shift_generations_down();
                 }
-
- static timeout sentinel()
+ else if(!active_generation_count)
                 {
- return timeout(sentinel_type());
+ active_generation_count=1;
                 }
- private:
- struct sentinel_type
- {};
-
- explicit timeout(sentinel_type):
- start(0),milliseconds(~uintmax_t(0)),relative(true)
- {}
- };
+ }
+
+ template<typename lock_type>
+ void start_wait_loop(relocker<lock_type>& locker,
+ detail::win32::handle_manager& local_wake_sem,
+ detail::win32::handle_manager& sem)
+ {
+ boost::mutex::scoped_lock internal_lock(internal_mutex);
+ detail::interlocked_write_release(&total_count,total_count+1);
+ if(!local_wake_sem)
+ {
+ start_wait_loop_first_time(locker,local_wake_sem);
+ }
+ if(!generations[0].semaphore)
+ {
+ generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
+ BOOST_ASSERT(generations[0].semaphore);
+ }
+ ++generations[0].count;
+ sem=detail::win32::duplicate_handle(generations[0].semaphore);
+ }
 
+ protected:
             template<typename lock_type>
             bool do_wait(lock_type& lock,timeout wait_until)
             {
                 detail::win32::handle_manager local_wake_sem;
                 detail::win32::handle_manager sem;
- bool first_loop=true;
                 bool woken=false;
 
                 relocker<lock_type> locker(lock);
             
                 while(!woken)
                 {
+ start_wait_loop(locker,local_wake_sem,sem);
+
+ if(!this_thread::interruptible_wait(sem,wait_until))
                     {
- boost::mutex::scoped_lock internal_lock(internal_mutex);
- detail::interlocked_write_release(&total_count,total_count+1);
- if(first_loop)
- {
- locker.unlock();
- if(!wake_sem)
- {
- wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
- BOOST_ASSERT(wake_sem);
- }
- local_wake_sem=detail::win32::duplicate_handle(wake_sem);
-
- if(generations[0].notified)
- {
- shift_generations_down();
- }
- else if(!active_generation_count)
- {
- active_generation_count=1;
- }
-
- first_loop=false;
- }
- if(!generations[0].semaphore)
- {
- generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
- BOOST_ASSERT(generations[0].semaphore);
- }
- ++generations[0].count;
- sem=detail::win32::duplicate_handle(generations[0].semaphore);
- }
- while(true)
- {
- 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;
- }
+ return false;
                     }
                 
                     unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
@@ -333,7 +261,7 @@
     public:
         void wait(unique_lock<mutex>& m)
         {
- do_wait(m,timeout::sentinel());
+ do_wait(m,detail::timeout::sentinel());
         }
 
         template<typename predicate_type>
@@ -372,7 +300,7 @@
         template<typename lock_type>
         void wait(lock_type& m)
         {
- do_wait(m,timeout::sentinel());
+ do_wait(m,detail::timeout::sentinel());
         }
 
         template<typename lock_type,typename predicate_type>

Modified: trunk/boost/thread/win32/shared_mutex.hpp
==============================================================================
--- trunk/boost/thread/win32/shared_mutex.hpp (original)
+++ trunk/boost/thread/win32/shared_mutex.hpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -48,10 +48,10 @@
         }
 
         state_data state;
- void* semaphores[2];
- void* &unlock_sem;
- void* &exclusive_sem;
- void* upgrade_sem;
+ detail::win32::handle semaphores[2];
+ detail::win32::handle &unlock_sem;
+ detail::win32::handle &exclusive_sem;
+ detail::win32::handle upgrade_sem;
 
         void release_waiters(state_data old_state)
         {

Modified: trunk/boost/thread/win32/thread.hpp
==============================================================================
--- trunk/boost/thread/win32/thread.hpp (original)
+++ trunk/boost/thread/win32/thread.hpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -19,6 +19,7 @@
 #include <list>
 #include <algorithm>
 #include <boost/ref.hpp>
+#include <boost/cstdint.hpp>
 
 namespace boost
 {
@@ -73,6 +74,82 @@
         };
 
         typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
+
+ 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(is_sentinel())
+ {
+ 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-now).total_milliseconds()+1);
+ }
+ }
+
+ bool is_sentinel() const
+ {
+ return milliseconds==~uintmax_t(0);
+ }
+
+
+ static timeout sentinel()
+ {
+ return timeout(sentinel_type());
+ }
+ private:
+ struct sentinel_type
+ {};
+
+ explicit timeout(sentinel_type):
+ start(0),milliseconds(~uintmax_t(0)),relative(true)
+ {}
+ };
     }
 
     class BOOST_THREAD_DECL thread
@@ -210,7 +287,7 @@
 
         thread::id BOOST_THREAD_DECL get_id();
 
- bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds);
+ bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
         inline bool interruptible_wait(unsigned long milliseconds)
         {
             return interruptible_wait(detail::win32::invalid_handle_value,milliseconds);

Modified: trunk/libs/thread/src/win32/thread.cpp
==============================================================================
--- trunk/libs/thread/src/win32/thread.cpp (original)
+++ trunk/libs/thread/src/win32/thread.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -4,6 +4,9 @@
 // (C) Copyright 2007 Anthony Williams
 // (C) Copyright 2007 David Deakins
 
+#define _WIN32_WINNT 0x400
+#define WINVER 0x400
+
 #include <boost/thread/thread.hpp>
 #include <algorithm>
 #include <windows.h>
@@ -15,6 +18,7 @@
 #include <boost/thread/tss.hpp>
 #include <boost/assert.hpp>
 #include <boost/thread/detail/tss_hooks.hpp>
+#include <boost/date_time/posix_time/conversion.hpp>
 
 namespace boost
 {
@@ -63,11 +67,11 @@
         typedef void* uintptr_t;
 
         inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
- void* arglist, unsigned initflag, unsigned* thrdaddr)
+ void* arglist, unsigned initflag, unsigned* thrdaddr)
         {
             DWORD threadID;
             HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
- new ThreadProxyData(start_address,arglist),initflag,&threadID);
+ new ThreadProxyData(start_address,arglist),initflag,&threadID);
             if (hthread!=0)
                 *thrdaddr=threadID;
             return reinterpret_cast<uintptr_t const>(hthread);
@@ -287,7 +291,7 @@
         detail::thread_data_ptr local_thread_info=get_thread_info();
         if(local_thread_info)
         {
- this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite);
+ this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
             release_handle();
         }
     }
@@ -353,13 +357,57 @@
 
     namespace this_thread
     {
- bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds)
+ namespace
         {
- detail::win32::handle handles[2]={0};
+ LARGE_INTEGER get_due_time(detail::timeout const& target_time)
+ {
+ LARGE_INTEGER due_time={0};
+ if(target_time.relative)
+ {
+ unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
+ LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
+ LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
+
+ if(remaining_milliseconds>0)
+ {
+ due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
+ }
+ }
+ else
+ {
+ SYSTEMTIME target_system_time={0};
+ target_system_time.wYear=target_time.abs_time.date().year();
+ target_system_time.wMonth=target_time.abs_time.date().month();
+ target_system_time.wDay=target_time.abs_time.date().day();
+ target_system_time.wHour=target_time.abs_time.time_of_day().hours();
+ target_system_time.wMinute=target_time.abs_time.time_of_day().minutes();
+ target_system_time.wSecond=target_time.abs_time.time_of_day().seconds();
+
+ if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
+ {
+ due_time.QuadPart=0;
+ }
+ else
+ {
+ long const hundred_nanoseconds_in_one_second=10000000;
+ due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
+ }
+ }
+ return due_time;
+ }
+ }
+
+
+ bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
+ {
+ detail::win32::handle handles[3]={0};
             unsigned handle_count=0;
+ unsigned wait_handle_index=~0U;
             unsigned interruption_index=~0U;
+ unsigned timeout_index=~0U;
             if(handle_to_wait_for!=detail::win32::invalid_handle_value)
             {
+ wait_handle_index=handle_count;
                 handles[handle_count++]=handle_to_wait_for;
             }
             if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
@@ -367,24 +415,79 @@
                 interruption_index=handle_count;
                 handles[handle_count++]=get_current_thread_data()->interruption_handle;
             }
-
- if(handle_count)
+
+ detail::win32::handle_manager timer_handle;
+
+#ifndef UNDER_CE
+ unsigned const min_timer_wait_period=20;
+
+ if(!target_time.is_sentinel())
             {
- unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds);
- if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index)
+ detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
+ if(time_left.milliseconds > min_timer_wait_period)
                 {
- return true;
+ // for a long-enough timeout, use a waitable timer (which tracks clock changes)
+ timer_handle=CreateWaitableTimer(NULL,false,NULL);
+ if(timer_handle!=0)
+ {
+ LARGE_INTEGER due_time=get_due_time(target_time);
+
+ bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
+ if(set_time_succeeded)
+ {
+ timeout_index=handle_count;
+ handles[handle_count++]=timer_handle;
+ }
+ }
                 }
- else if(notified_index==interruption_index)
+ else if(!target_time.relative)
                 {
- detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
- throw thread_interrupted();
+ // convert short absolute-time timeouts into relative ones, so we don't race against clock changes
+ target_time=detail::timeout(time_left.milliseconds);
                 }
             }
- else
+#endif
+
+ bool const using_timer=timeout_index!=~0u;
+ detail::timeout::remaining_time time_left(0);
+
+ do
             {
- detail::win32::Sleep(milliseconds);
+ if(!using_timer)
+ {
+ time_left=target_time.remaining_milliseconds();
+ }
+
+ if(handle_count)
+ {
+ unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
+ if(notified_index<handle_count)
+ {
+ if(notified_index==wait_handle_index)
+ {
+ return true;
+ }
+ else if(notified_index==interruption_index)
+ {
+ detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
+ throw thread_interrupted();
+ }
+ else if(notified_index==timeout_index)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ detail::win32::Sleep(time_left.milliseconds);
+ }
+ if(target_time.relative)
+ {
+ target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
+ }
             }
+ while(time_left.more);
             return false;
         }
 

Modified: trunk/libs/thread/src/win32/tss_pe.cpp
==============================================================================
--- trunk/libs/thread/src/win32/tss_pe.cpp (original)
+++ trunk/libs/thread/src/win32/tss_pe.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -230,13 +230,10 @@
 
         void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv)
         {
- OutputDebugString("on_tls_callback\n");
-
             switch (dwReason)
             {
                 case DLL_THREAD_DETACH:
                 {
- OutputDebugString("on_tls_callback: thread_exit\n");
                     on_thread_exit();
                     break;
                 }

Modified: trunk/libs/thread/test/Jamfile.v2
==============================================================================
--- trunk/libs/thread/test/Jamfile.v2 (original)
+++ trunk/libs/thread/test/Jamfile.v2 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -1,4 +1,5 @@
 # (C) Copyright William E. Kempf 2001.
+# (C) Copyright 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)
 #
@@ -35,6 +36,9 @@
     test-suite "threads"
         : [ thread-run test_thread.cpp ]
           [ thread-run test_mutex.cpp ]
+ [ thread-run test_condition_notify_one.cpp ]
+ [ thread-run test_condition_timed_wait_times_out.cpp ]
+ [ thread-run test_condition_notify_all.cpp ]
           [ thread-run test_condition.cpp ]
           [ thread-run test_tss.cpp ]
           [ thread-run test_once.cpp ]

Added: trunk/libs/thread/test/condition_test_common.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/condition_test_common.hpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -0,0 +1,95 @@
+#ifndef CONDITION_TEST_COMMON_HPP
+#define CONDITION_TEST_COMMON_HPP
+// 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)
+
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+
+unsigned const timeout_seconds=5;
+
+struct wait_for_flag
+{
+ boost::mutex mutex;
+ boost::condition_variable cond_var;
+ bool flag;
+ unsigned woken;
+
+ wait_for_flag():
+ flag(false),woken(0)
+ {}
+
+ struct check_flag
+ {
+ bool const& flag;
+
+ check_flag(bool const& flag_):
+ flag(flag_)
+ {}
+
+ bool operator()() const
+ {
+ return flag;
+ }
+ };
+
+
+ void wait_without_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ while(!flag)
+ {
+ cond_var.wait(lock);
+ }
+ ++woken;
+ }
+
+ void wait_with_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ cond_var.wait(lock,check_flag(flag));
+ if(flag)
+ {
+ ++woken;
+ }
+ }
+
+ void timed_wait_without_predicate()
+ {
+ boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
+
+ boost::mutex::scoped_lock lock(mutex);
+ while(!flag)
+ {
+ if(!cond_var.timed_wait(lock,timeout))
+ {
+ return;
+ }
+ }
+ ++woken;
+ }
+
+ void timed_wait_with_predicate()
+ {
+ boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
+ boost::mutex::scoped_lock lock(mutex);
+ if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
+ {
+ ++woken;
+ }
+ }
+ void relative_timed_wait_with_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
+ {
+ ++woken;
+ }
+ }
+};
+
+
+#endif

Modified: trunk/libs/thread/test/test_barrier.cpp
==============================================================================
--- trunk/libs/thread/test/test_barrier.cpp (original)
+++ trunk/libs/thread/test/test_barrier.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -52,7 +52,7 @@
         throw;
     }
     
- BOOST_CHECK(global_parameter == 5);
+ BOOST_CHECK_EQUAL(global_parameter,5);
 }
 
 boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

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-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -94,66 +94,6 @@
     data->condition.notify_one();
 }
 
-void do_test_condition_notify_one()
-{
- condition_test_data data;
-
- boost::thread thread(bind(&condition_test_thread, &data));
-
- {
- boost::mutex::scoped_lock lock(data.mutex);
- BOOST_CHECK(lock ? true : false);
- data.notified++;
- data.condition.notify_one();
- }
-
- thread.join();
- BOOST_CHECK_EQUAL(data.awoken, 1);
-}
-
-void test_condition_notify_one()
-{
- timed_test(&do_test_condition_notify_one, 100, execution_monitor::use_mutex);
-}
-
-void do_test_condition_notify_all()
-{
- const int NUMTHREADS = 5;
- boost::thread_group threads;
- condition_test_data data;
-
- try
- {
- for (int i = 0; i < NUMTHREADS; ++i)
- threads.create_thread(bind(&condition_test_thread, &data));
-
- {
- boost::mutex::scoped_lock lock(data.mutex);
- BOOST_CHECK(lock ? true : false);
- data.notified++;
- data.condition.notify_all();
- }
-
- threads.join_all();
- }
- catch(...)
- {
- threads.interrupt_all();
- threads.join_all();
- throw;
- }
-
- BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
-}
-
-void test_condition_notify_all()
-{
- // We should have already tested notify_one here, so
- // a timed test with the default execution_monitor::use_condition
- // should be OK, and gives the fastest performance
- timed_test(&do_test_condition_notify_all, 100);
-}
-
 void do_test_condition_waits()
 {
     condition_test_data data;
@@ -235,43 +175,13 @@
     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*[])
 {
     boost::unit_test_framework::test_suite* test =
         BOOST_TEST_SUITE("Boost.Threads: condition test suite");
 
- test->add(BOOST_TEST_CASE(&test_condition_notify_one));
- 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;
 }

Added: trunk/libs/thread/test/test_condition_notify_all.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/test_condition_notify_all.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -0,0 +1,180 @@
+// 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+#include "condition_test_common.hpp"
+
+unsigned const number_of_test_threads=5;
+
+void do_test_condition_notify_all_wakes_from_wait()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_timed_wait()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void test_condition_notify_all()
+{
+ timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_notify_all));
+
+ return test;
+}

Added: trunk/libs/thread/test/test_condition_notify_one.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/test_condition_notify_one.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -0,0 +1,113 @@
+// 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+#include "condition_test_common.hpp"
+
+void do_test_condition_notify_one_wakes_from_wait()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_timed_wait()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void test_condition_notify_one()
+{
+ timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_notify_one));
+
+ return test;
+}

Added: trunk/libs/thread/test/test_condition_timed_wait_times_out.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/test_condition_timed_wait_times_out.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -0,0 +1,89 @@
+// 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include "util.inl"
+
+bool fake_predicate()
+{
+ return false;
+}
+
+unsigned const timeout_seconds=5;
+unsigned const timeout_grace=1;
+boost::posix_time::milliseconds const timeout_resolution(100);
+
+
+void do_test_timed_wait_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+delay;
+
+ while(cond.timed_wait(lock,timeout));
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_timed_wait_with_predicate_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+delay;
+
+ bool const res=cond.timed_wait(lock,timeout,fake_predicate);
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK(!res);
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_relative_timed_wait_with_predicate_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ 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-timeout_resolution)<=(end-start));
+}
+
+
+void test_timed_wait_times_out()
+{
+ timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
+
+ return test;
+}

Modified: trunk/libs/thread/test/test_shared_mutex.cpp
==============================================================================
--- trunk/libs/thread/test/test_shared_mutex.cpp (original)
+++ trunk/libs/thread/test/test_shared_mutex.cpp 2007-11-30 13:38:21 EST (Fri, 30 Nov 2007)
@@ -466,7 +466,7 @@
     unsigned unblocked_count=0;
     boost::mutex::scoped_lock finish_lock(finish_mutex);
     boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
- boost::thread::sleep(delay(1));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
     CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
 
     bool const try_succeeded=rw_mutex.try_lock_shared();

Modified: trunk/libs/thread/test/util.inl
==============================================================================
--- trunk/libs/thread/test/util.inl (original)
+++ trunk/libs/thread/test/util.inl 2007-11-30 13:38:21 EST (Fri, 30 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)
@@ -154,6 +155,26 @@
 {
     return thread_binder<F, T>(func, param);
 }
+
+template <typename R, typename T>
+class thread_member_binder
+{
+public:
+ thread_member_binder(R (T::*func)(), T& param)
+ : func(func), param(param) { }
+ void operator()() const { (param.*func)(); }
+
+private:
+ R (T::*func)();
+ T& param;
+};
+
+
+template <typename R, typename T>
+thread_member_binder<R, T> bind(R (T::*func)(), T& param)
+{
+ return thread_member_binder<R, T>(func, param);
+}
 } // namespace
 
 #endif


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