Boost logo

Boost-Commit :

From: anthony_at_[hidden]
Date: 2008-05-29 05:02:05


Author: anthonyw
Date: 2008-05-29 05:02:05 EDT (Thu, 29 May 2008)
New Revision: 45897
URL: http://svn.boost.org/trac/boost/changeset/45897

Log:
More tests for generic locks, and a new range version
Text files modified:
   trunk/boost/thread/locks.hpp | 201 +++++++++++++++++++++
   trunk/libs/thread/test/test_generic_locks.cpp | 376 ++++++++++++++++++++++++++++++++++++++++
   2 files changed, 576 insertions(+), 1 deletions(-)

Modified: trunk/boost/thread/locks.hpp
==============================================================================
--- trunk/boost/thread/locks.hpp (original)
+++ trunk/boost/thread/locks.hpp 2008-05-29 05:02:05 EDT (Thu, 29 May 2008)
@@ -8,12 +8,77 @@
 #include <boost/thread/exceptions.hpp>
 #include <boost/thread/detail/move.hpp>
 #include <algorithm>
+#include <iterator>
 #include <boost/thread/thread_time.hpp>
+#include <boost/utility/enable_if.hpp>
 
 #include <boost/config/abi_prefix.hpp>
 
 namespace boost
 {
+ namespace detail
+ {
+ template<typename T>
+ struct has_member_lock
+ {
+ typedef char true_type;
+ struct false_type
+ {
+ true_type dummy[2];
+ };
+
+ template<typename U>
+ static true_type has_member(U*,void (U::*dummy)()=&U::lock);
+ static false_type has_member(void*);
+
+ BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_lock<T>::has_member((T*)NULL))==sizeof(true_type));
+ };
+
+ template<typename T>
+ struct has_member_unlock
+ {
+ typedef char true_type;
+ struct false_type
+ {
+ true_type dummy[2];
+ };
+
+ template<typename U>
+ static true_type has_member(U*,void (U::*dummy)()=&U::unlock);
+ static false_type has_member(void*);
+
+ BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_unlock<T>::has_member((T*)NULL))==sizeof(true_type));
+ };
+
+ template<typename T>
+ struct has_member_try_lock
+ {
+ typedef char true_type;
+ struct false_type
+ {
+ true_type dummy[2];
+ };
+
+ template<typename U>
+ static true_type has_member(U*,bool (U::*dummy)()=&U::try_lock);
+ static false_type has_member(void*);
+
+ BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_try_lock<T>::has_member((T*)NULL))==sizeof(true_type));
+ };
+
+ }
+
+
+ template<typename T>
+ struct is_mutex_type
+ {
+ BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
+ detail::has_member_unlock<T>::value &&
+ detail::has_member_try_lock<T>::value);
+
+ };
+
+
     struct defer_lock_t
     {};
     struct try_to_lock_t
@@ -766,7 +831,7 @@
     }
 
     template<typename MutexType1,typename MutexType2>
- void lock(MutexType1& m1,MutexType2& m2)
+ typename enable_if<is_mutex_type<MutexType1>, void>::type lock(MutexType1& m1,MutexType2& m2)
     {
         unsigned const lock_count=2;
         unsigned lock_first=0;
@@ -900,6 +965,140 @@
             }
         }
     }
+
+ template<typename MutexType1,typename MutexType2>
+ typename enable_if<is_mutex_type<MutexType1>, int>::type try_lock(MutexType1& m1,MutexType2& m2)
+ {
+ return ((int)detail::try_lock_internal(m1,m2))-1;
+ }
+
+ template<typename MutexType1,typename MutexType2,typename MutexType3>
+ int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3)
+ {
+ return ((int)detail::try_lock_internal(m1,m2,m3))-1;
+ }
+
+ template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4>
+ int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4)
+ {
+ return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1;
+ }
+
+ template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4,typename MutexType5>
+ int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5)
+ {
+ return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1;
+ }
+
+
+ template<typename Iterator>
+ typename disable_if<is_mutex_type<Iterator>, void>::type lock(Iterator begin,Iterator end);
+
+ namespace detail
+ {
+ template<typename Iterator>
+ struct range_lock_guard
+ {
+ Iterator begin;
+ Iterator end;
+
+ range_lock_guard(Iterator begin_,Iterator end_):
+ begin(begin_),end(end_)
+ {
+ lock(begin,end);
+ }
+
+ void release()
+ {
+ begin=end;
+ }
+
+ ~range_lock_guard()
+ {
+ for(;begin!=end;++begin)
+ {
+ begin->unlock();
+ }
+ }
+ };
+ }
+
+ template<typename Iterator>
+ typename disable_if<is_mutex_type<Iterator>, Iterator>::type try_lock(Iterator begin,Iterator end)
+ {
+ if(begin==end)
+ {
+ return end;
+ }
+ typedef typename std::iterator_traits<Iterator>::value_type lock_type;
+ unique_lock<lock_type> guard(*begin,try_to_lock);
+
+ if(!guard.owns_lock())
+ {
+ return begin;
+ }
+ Iterator const failed=try_lock(++begin,end);
+ if(failed==end)
+ {
+ guard.release();
+ }
+
+ return failed;
+ }
+
+ template<typename Iterator>
+ typename disable_if<is_mutex_type<Iterator>, void>::type lock(Iterator begin,Iterator end)
+ {
+ typedef typename std::iterator_traits<Iterator>::value_type lock_type;
+
+ if(begin==end)
+ {
+ return;
+ }
+ bool start_with_begin=true;
+ Iterator second=begin;
+ ++second;
+ Iterator next=second;
+
+ for(;;)
+ {
+ unique_lock<lock_type> begin_lock(*begin,defer_lock);
+ if(start_with_begin)
+ {
+ begin_lock.lock();
+ Iterator const failed_lock=try_lock(next,end);
+ if(failed_lock==end)
+ {
+ begin_lock.release();
+ return;
+ }
+ start_with_begin=false;
+ next=failed_lock;
+ }
+ else
+ {
+ detail::range_lock_guard<Iterator> guard(next,end);
+ if(begin_lock.try_lock())
+ {
+ Iterator const failed_lock=try_lock(second,next);
+ if(failed_lock==next)
+ {
+ begin_lock.release();
+ guard.release();
+ return;
+ }
+ start_with_begin=false;
+ next=failed_lock;
+ }
+ else
+ {
+ start_with_begin=true;
+ next=second;
+ }
+ }
+ }
+ }
+
 }
 
 #include <boost/config/abi_suffix.hpp>

Modified: trunk/libs/thread/test/test_generic_locks.cpp
==============================================================================
--- trunk/libs/thread/test/test_generic_locks.cpp (original)
+++ trunk/libs/thread/test/test_generic_locks.cpp 2008-05-29 05:02:05 EDT (Thu, 29 May 2008)
@@ -123,6 +123,370 @@
     t.join();
 }
 
+void test_lock_five_uncontended()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+
+ boost::mutex::scoped_lock l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock),
+ l3(m3,boost::defer_lock),
+ l4(m4,boost::defer_lock),
+ l5(m5,boost::defer_lock);
+
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ BOOST_CHECK(!l5.owns_lock());
+
+ boost::lock(l1,l2,l3,l4,l5);
+
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ BOOST_CHECK(l5.owns_lock());
+}
+
+void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
+ wait_data* locked,wait_data* quit)
+{
+ boost::lock_guard<boost::mutex> l1(*m1);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l2(*m2);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l3(*m3);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l4(*m4);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l5(*m5);
+ locked->signal();
+ quit->wait();
+}
+
+void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
+{
+ boost::lock(*m1,*m2,*m3,*m4,*m5);
+ m1->unlock();
+ m2->unlock();
+ m3->unlock();
+ m4->unlock();
+ m5->unlock();
+}
+
+void test_lock_five_other_thread_locks_in_order()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+void test_lock_five_other_thread_locks_in_different_order()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+void lock_n(boost::mutex* mutexes,unsigned count)
+{
+ boost::lock(mutexes,mutexes+count);
+ for(unsigned i=0;i<count;++i)
+ {
+ mutexes[i].unlock();
+ }
+}
+
+
+void test_lock_ten_other_thread_locks_in_different_order()
+{
+ unsigned const num_mutexes=10;
+
+ boost::mutex mutexes[num_mutexes];
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_n,mutexes,num_mutexes);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+struct dummy_mutex
+{
+ bool is_locked;
+
+ dummy_mutex():
+ is_locked(false)
+ {}
+
+ void lock()
+ {
+ is_locked=true;
+ }
+
+ bool try_lock()
+ {
+ if(is_locked)
+ {
+ return false;
+ }
+ is_locked=true;
+ return true;
+ }
+
+ void unlock()
+ {
+ is_locked=false;
+ }
+};
+
+
+void test_lock_five_in_range()
+{
+ unsigned const num_mutexes=5;
+ dummy_mutex mutexes[num_mutexes];
+
+ boost::lock(mutexes,mutexes+num_mutexes);
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+void test_lock_ten_in_range()
+{
+ unsigned const num_mutexes=10;
+ dummy_mutex mutexes[num_mutexes];
+
+ boost::lock(mutexes,mutexes+num_mutexes);
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+void test_try_lock_two_uncontended()
+{
+ dummy_mutex m1,m2;
+
+ int const res=boost::try_lock(m1,m2);
+
+ BOOST_CHECK(res==-1);
+ BOOST_CHECK(m1.is_locked);
+ BOOST_CHECK(m2.is_locked);
+}
+void test_try_lock_two_first_locked()
+{
+ dummy_mutex m1,m2;
+ m1.lock();
+
+ boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2);
+
+ BOOST_CHECK(res==0);
+ BOOST_CHECK(m1.is_locked);
+ BOOST_CHECK(!m2.is_locked);
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+}
+void test_try_lock_two_second_locked()
+{
+ dummy_mutex m1,m2;
+ m2.lock();
+
+ boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2);
+
+ BOOST_CHECK(res==1);
+ BOOST_CHECK(!m1.is_locked);
+ BOOST_CHECK(m2.is_locked);
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+}
+
+void test_try_lock_three()
+{
+ int const num_mutexes=3;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ }
+ }
+}
+
+void test_try_lock_four()
+{
+ int const num_mutexes=4;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock),
+ l4(mutexes[3],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3,l4);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ }
+ }
+}
+
+void test_try_lock_five()
+{
+ int const num_mutexes=5;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock),
+ l4(mutexes[3],boost::defer_lock),
+ l5(mutexes[4],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3,l4,l5);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ BOOST_CHECK(l5.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ BOOST_CHECK(!l5.owns_lock());
+ }
+ }
+}
+
+
 
 boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
 {
@@ -132,6 +496,18 @@
     test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
     test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order));
     test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_uncontended));
+ test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
+ test->add(BOOST_TEST_CASE(&test_lock_ten_in_range));
+ test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked));
+ test->add(BOOST_TEST_CASE(&test_try_lock_three));
+ test->add(BOOST_TEST_CASE(&test_try_lock_four));
+ test->add(BOOST_TEST_CASE(&test_try_lock_five));
 
     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