|
Boost-Commit : |
From: anthony_at_[hidden]
Date: 2008-04-11 04:52:11
Author: anthonyw
Date: 2008-04-11 04:52:09 EDT (Fri, 11 Apr 2008)
New Revision: 44168
URL: http://svn.boost.org/trac/boost/changeset/44168
Log:
Added test and fix for win32 condition_variable broadcast bug similar to #1803
Text files modified:
trunk/boost/thread/win32/condition_variable.hpp | 38 ++++++++++++++++++++++-------------
trunk/libs/thread/test/test_condition_notify_all.cpp | 42 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+), 14 deletions(-)
Modified: trunk/boost/thread/win32/condition_variable.hpp
==============================================================================
--- trunk/boost/thread/win32/condition_variable.hpp (original)
+++ trunk/boost/thread/win32/condition_variable.hpp 2008-04-11 04:52:09 EDT (Fri, 11 Apr 2008)
@@ -35,9 +35,9 @@
semaphore(0),count(0),notified(0)
{}
- void release(unsigned count=1)
+ void release(unsigned count_to_release=1)
{
- detail::win32::ReleaseSemaphore(semaphore,count,0);
+ detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
}
};
@@ -47,6 +47,13 @@
list_entry generations[generation_count];
detail::win32::handle wake_sem;
+ void wake_waiters(long count_to_wake)
+ {
+ detail::interlocked_write_release(&total_count,total_count-count_to_wake);
+ detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
+ }
+
+
static bool no_waiters(list_entry const& entry)
{
return entry.count==0;
@@ -57,7 +64,7 @@
list_entry* const last_active_entry=std::remove_if(generations,generations+generation_count,no_waiters);
if(last_active_entry==generations+generation_count)
{
- broadcast_entry(generations[generation_count-1],false);
+ broadcast_entry(generations[generation_count-1]);
}
else
{
@@ -75,15 +82,9 @@
generations[0]=list_entry();
}
- void broadcast_entry(list_entry& entry,bool wake)
+ void broadcast_entry(list_entry& entry)
{
- long const count_to_wake=entry.count;
- detail::interlocked_write_release(&total_count,total_count-count_to_wake);
- if(wake)
- {
- detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
- }
- entry.release(count_to_wake);
+ entry.release(entry.count);
entry.count=0;
dispose_entry(entry);
}
@@ -237,8 +238,7 @@
{
return;
}
- detail::win32::ReleaseSemaphore(wake_sem,1,0);
- detail::interlocked_write_release(&total_count,total_count-1);
+ wake_waiters(1);
unsigned waiting_count=0;
@@ -262,6 +262,7 @@
}
if(waiting_count<=total_count)
{
+ shift_generations_down();
ensure_generation_present();
generations[0].release();
}
@@ -273,14 +274,23 @@
if(detail::interlocked_read_acquire(&total_count))
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
+ long waiting_count=total_count;
+
+ wake_waiters(total_count);
for(unsigned generation=active_generation_count;generation!=0;--generation)
{
list_entry& entry=generations[generation-1];
if(entry.count)
{
- broadcast_entry(entry,true);
+ waiting_count-=entry.count;
+ broadcast_entry(entry);
}
}
+ if(waiting_count)
+ {
+ ensure_generation_present();
+ generations[0].release(waiting_count);
+ }
active_generation_count=0;
}
}
Modified: trunk/libs/thread/test/test_condition_notify_all.cpp
==============================================================================
--- trunk/libs/thread/test/test_condition_notify_all.cpp (original)
+++ trunk/libs/thread/test/test_condition_notify_all.cpp 2008-04-11 04:52:09 EDT (Fri, 11 Apr 2008)
@@ -159,6 +159,47 @@
}
}
+namespace
+{
+ boost::mutex multiple_wake_mutex;
+ boost::condition_variable multiple_wake_cond;
+ unsigned multiple_wake_count=0;
+
+ void wait_for_condvar_and_increase_count()
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ multiple_wake_cond.wait(lk);
+ ++multiple_wake_count;
+ }
+
+}
+
+
+void do_test_notify_all_following_notify_one_wakes_all_threads()
+{
+ boost::thread thread1(wait_for_condvar_and_increase_count);
+ boost::thread thread2(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+
+ boost::thread thread3(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+ multiple_wake_cond.notify_all();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ BOOST_CHECK(multiple_wake_count==3);
+ }
+
+ thread1.join();
+ thread2.join();
+ thread3.join();
+}
+
void test_condition_notify_all()
{
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
@@ -166,6 +207,7 @@
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);
+ timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
}
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