123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- // (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 <boost/test/unit_test.hpp>
- #include <boost/thread/mutex.hpp>
- #include <boost/thread/thread_only.hpp>
- #include <boost/thread/locks.hpp>
- #include <boost/thread/condition_variable.hpp>
- #include <iterator>
- #include <cstddef>
- BOOST_AUTO_TEST_CASE(test_lock_two_uncontended)
- {
- boost::mutex m1,m2;
- boost::unique_lock<boost::mutex> 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<boost::mutex> l(m);
- while(!flag)
- {
- cond.wait(l);
- }
- }
- template<typename Duration>
- bool timed_wait(Duration d)
- {
- boost::system_time const target=boost::get_system_time()+d;
- boost::unique_lock<boost::mutex> l(m);
- while(!flag)
- {
- if(!cond.timed_wait(l,target))
- {
- return flag;
- }
- }
- return true;
- }
- void signal()
- {
- boost::unique_lock<boost::mutex> 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<boost::mutex> l1(*m1);
- boost::this_thread::sleep(boost::posix_time::milliseconds(500));
- boost::lock_guard<boost::mutex> l2(*m2);
- locked->signal();
- quit->wait();
- }
- void lock_pair(boost::mutex* m1,boost::mutex* m2)
- {
- boost::lock(*m1,*m2);
- boost::unique_lock<boost::mutex> 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<boost::mutex> 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();
- }
- 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<count;++i)
- {
- mutexes[i].unlock();
- }
- }
- BOOST_AUTO_TEST_CASE(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;
- }
- };
- namespace boost
- {
- template<>
- struct is_mutex_type<dummy_mutex>
- {
- 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<num_mutexes;++i)
- {
- BOOST_CHECK(mutexes[i].is_locked);
- }
- }
- class dummy_iterator
- {
- private:
- dummy_mutex* p;
- public:
- typedef std::forward_iterator_tag iterator_category;
- typedef dummy_mutex value_type;
- typedef std::ptrdiff_t difference_type;
- typedef dummy_mutex* pointer;
- typedef dummy_mutex& reference;
- explicit dummy_iterator(dummy_mutex* p_):
- p(p_)
- {}
- bool operator==(dummy_iterator const& other) const
- {
- return p==other.p;
- }
- bool operator!=(dummy_iterator const& other) const
- {
- return p!=other.p;
- }
- bool operator<(dummy_iterator const& other) const
- {
- return p<other.p;
- }
- dummy_mutex& operator*() const
- {
- return *p;
- }
- dummy_mutex* operator->() 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<num_mutexes;++i)
- {
- BOOST_CHECK(mutexes[i].is_locked);
- }
- }
- class dummy_mutex2:
- public dummy_mutex
- {};
- BOOST_AUTO_TEST_CASE(test_lock_ten_in_range_inherited_mutex)
- {
- unsigned const num_mutexes=10;
- dummy_mutex2 mutexes[num_mutexes];
- boost::lock(mutexes,mutexes+num_mutexes);
- for(unsigned i=0;i<num_mutexes;++i)
- {
- BOOST_CHECK(mutexes[i].is_locked);
- }
- }
- BOOST_AUTO_TEST_CASE(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);
- }
- BOOST_AUTO_TEST_CASE(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());
- }
- BOOST_AUTO_TEST_CASE(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());
- }
- BOOST_AUTO_TEST_CASE(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());
- }
- }
- }
- BOOST_AUTO_TEST_CASE(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());
- }
- }
- }
- BOOST_AUTO_TEST_CASE(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());
- }
- }
- }
|