// (C) Copyright 2008 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) #define BOOST_THREAD_VERSION 2 #define BOOST_TEST_MODULE Boost.Threads: generic locks test suite #include #include #include #include #include #include #include BOOST_AUTO_TEST_CASE(test_lock_two_uncontended) { boost::mutex m1,m2; boost::unique_lock l1(m1,boost::defer_lock), l2(m2,boost::defer_lock); BOOST_CHECK(!l1.owns_lock()); BOOST_CHECK(!l2.owns_lock()); boost::lock(l1,l2); BOOST_CHECK(l1.owns_lock()); BOOST_CHECK(l2.owns_lock()); } struct wait_data { boost::mutex m; bool flag; boost::condition_variable cond; wait_data(): flag(false) {} void wait() { boost::unique_lock l(m); while(!flag) { cond.wait(l); } } template bool timed_wait(Duration d) { boost::system_time const target=boost::get_system_time()+d; boost::unique_lock l(m); while(!flag) { if(!cond.timed_wait(l,target)) { return flag; } } return true; } void signal() { boost::unique_lock l(m); flag=true; cond.notify_all(); } }; void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit) { boost::lock_guard l1(*m1); boost::this_thread::sleep(boost::posix_time::milliseconds(500)); boost::lock_guard l2(*m2); locked->signal(); quit->wait(); } void lock_pair(boost::mutex* m1,boost::mutex* m2) { boost::lock(*m1,*m2); boost::unique_lock l1(*m1,boost::adopt_lock), l2(*m2,boost::adopt_lock); } BOOST_AUTO_TEST_CASE(test_lock_two_other_thread_locks_in_order) { boost::mutex m1,m2; wait_data locked; wait_data release; boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); boost::this_thread::sleep(boost::posix_time::milliseconds(10)); boost::thread t2(lock_pair,&m1,&m2); BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); release.signal(); BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); t.join(); } BOOST_AUTO_TEST_CASE(test_lock_two_other_thread_locks_in_opposite_order) { boost::mutex m1,m2; wait_data locked; wait_data release; boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); boost::this_thread::sleep(boost::posix_time::milliseconds(10)); boost::thread t2(lock_pair,&m2,&m1); BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); release.signal(); BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); t.join(); } BOOST_AUTO_TEST_CASE(test_lock_five_uncontended) { boost::mutex m1,m2,m3,m4,m5; boost::unique_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 l1(*m1); boost::this_thread::sleep(boost::posix_time::milliseconds(500)); boost::lock_guard l2(*m2); boost::this_thread::sleep(boost::posix_time::milliseconds(500)); boost::lock_guard l3(*m3); boost::this_thread::sleep(boost::posix_time::milliseconds(500)); boost::lock_guard l4(*m4); boost::this_thread::sleep(boost::posix_time::milliseconds(500)); boost::lock_guard 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(); } BOOST_AUTO_TEST_CASE(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(); } BOOST_AUTO_TEST_CASE(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 struct is_mutex_type { BOOST_STATIC_CONSTANT(bool, value = true); }; } BOOST_AUTO_TEST_CASE(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() const { return p; } dummy_iterator operator++(int) { dummy_iterator temp(*this); ++p; return temp; } dummy_iterator& operator++() { ++p; return *this; } }; BOOST_AUTO_TEST_CASE(test_lock_five_in_range_custom_iterator) { unsigned const num_mutexes=5; dummy_mutex mutexes[num_mutexes]; boost::lock(dummy_iterator(mutexes),dummy_iterator(mutexes+num_mutexes)); for(unsigned i=0;i 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()); } BOOST_AUTO_TEST_CASE(test_try_lock_two_second_locked) { dummy_mutex m1,m2; m2.lock(); boost::unique_lock 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()); } BOOST_AUTO_TEST_CASE(test_try_lock_three) { int const num_mutexes=3; for(int i=-1;i=0) { mutexes[i].lock(); } boost::unique_lock 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=0) { mutexes[i].lock(); } boost::unique_lock 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=0) { mutexes[i].lock(); } boost::unique_lock 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