2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-09 11:32:12 +00:00

Merge from trunk

[SVN r39987]
This commit is contained in:
Nicola Musatti
2007-10-13 21:25:29 +00:00
parent bfaeda36c7
commit bf46b2ee96
22 changed files with 1746 additions and 1869 deletions

View File

@@ -40,6 +40,7 @@ rule thread-run ( sources )
[ thread-run test_once.cpp ]
[ thread-run test_xtime.cpp ]
[ thread-run test_barrier.cpp ]
# [ thread-run test_read_write_mutex.cpp ]
[ thread-run test_shared_mutex.cpp ]
[ thread-run test_lock_concept.cpp ]
;
}

173
test/test_lock_concept.cpp Normal file
View File

@@ -0,0 +1,173 @@
// (C) Copyright 2006-7 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/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
template<typename Mutex,typename Lock>
struct test_initially_locked
{
void operator()() const
{
Mutex m;
Lock lock(m);
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_initially_unlocked_with_defer_lock_parameter
{
void operator()() const
{
Mutex m;
Lock lock(m,boost::defer_lock);
BOOST_CHECK(!lock);
BOOST_CHECK(!lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_initially_locked_with_adopt_lock_parameter
{
void operator()() const
{
Mutex m;
m.lock();
Lock lock(m,boost::adopt_lock);
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_unlocked_after_unlock_called
{
void operator()() const
{
Mutex m;
Lock lock(m);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK(!lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_locked_after_lock_called
{
void operator()() const
{
Mutex m;
Lock lock(m,boost::defer_lock);
lock.lock();
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_locked_after_try_lock_called
{
void operator()() const
{
Mutex m;
Lock lock(m,boost::defer_lock);
lock.try_lock();
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_throws_if_lock_called_when_already_locked
{
void operator()() const
{
Mutex m;
Lock lock(m);
BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
}
};
template<typename Mutex,typename Lock>
struct test_throws_if_try_lock_called_when_already_locked
{
void operator()() const
{
Mutex m;
Lock lock(m);
BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
}
};
template<typename Mutex,typename Lock>
struct test_throws_if_unlock_called_when_already_unlocked
{
void operator()() const
{
Mutex m;
Lock lock(m);
lock.unlock();
BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
}
};
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
{
typedef typename Mutex::scoped_lock Lock;
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
test_unlocked_after_unlock_called<Mutex,Lock>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
{
typedef typename Mutex::scoped_try_lock Lock;
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
test_unlocked_after_unlock_called<Mutex,Lock>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_locked_after_try_lock_called<Mutex,Lock>()();
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types;
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types));
typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
boost::recursive_try_mutex,boost::recursive_timed_mutex> try_mutex_types;
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,try_mutex_types));
return test;
}

View File

@@ -8,7 +8,7 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/condition.hpp>
#include <boost/test/unit_test.hpp>
@@ -29,7 +29,7 @@ struct test_lock
// Test the lock's constructors.
{
lock_type lock(mutex, false);
lock_type lock(mutex, boost::defer_lock);
BOOST_CHECK(!lock);
}
lock_type lock(mutex);
@@ -69,10 +69,10 @@ struct test_trylock
BOOST_CHECK(lock ? true : false);
}
{
try_lock_type lock(mutex, false);
try_lock_type lock(mutex, boost::defer_lock);
BOOST_CHECK(!lock);
}
try_lock_type lock(mutex, true);
try_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
@@ -110,16 +110,16 @@ struct test_timedlock
// Test the lock's constructors.
{
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
timed_lock_type lock(mutex, xt);
BOOST_CHECK(lock ? true : false);
}
{
timed_lock_type lock(mutex, false);
timed_lock_type lock(mutex, boost::defer_lock);
BOOST_CHECK(!lock);
}
timed_lock_type lock(mutex, true);
timed_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
@@ -139,8 +139,8 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
xt = delay(0, 100);
BOOST_CHECK(lock.timed_lock(xt));
boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
BOOST_CHECK(lock.timed_lock(target));
BOOST_CHECK(lock ? true : false);
}
};

View File

@@ -49,6 +49,103 @@ void test_call_once()
BOOST_CHECK_EQUAL(var_to_init,1);
}
int var_to_init_with_functor=0;
struct increment_value
{
int* value;
explicit increment_value(int* value_):
value(value_)
{}
void operator()() const
{
boost::mutex::scoped_lock lock(m);
++(*value);
}
};
void call_once_with_functor()
{
unsigned const loop_count=100;
int my_once_value=0;
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
for(unsigned i=0;i<loop_count;++i)
{
boost::call_once(functor_flag, increment_value(&var_to_init_with_functor));
my_once_value=var_to_init_with_functor;
if(my_once_value!=1)
{
break;
}
}
boost::mutex::scoped_lock lock(m);
BOOST_CHECK_EQUAL(my_once_value, 1);
}
void test_call_once_arbitrary_functor()
{
unsigned const num_threads=100;
boost::thread_group group;
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_functor);
}
group.join_all();
BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
}
struct throw_before_third_pass
{
struct my_exception
{};
static unsigned pass_counter;
void operator()() const
{
boost::mutex::scoped_lock lock(m);
++pass_counter;
if(pass_counter<3)
{
throw my_exception();
}
}
};
unsigned throw_before_third_pass::pass_counter=0;
unsigned exception_counter=0;
void call_once_with_exception()
{
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
try
{
boost::call_once(functor_flag, throw_before_third_pass());
}
catch(throw_before_third_pass::my_exception)
{
boost::mutex::scoped_lock lock(m);
++exception_counter;
}
}
void test_call_once_retried_on_exception()
{
unsigned const num_threads=100;
boost::thread_group group;
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_exception);
}
group.join_all();
BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3);
BOOST_CHECK_EQUAL(exception_counter,2);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
@@ -56,6 +153,8 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
test->add(BOOST_TEST_CASE(test_call_once));
test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor));
test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception));
return test;
}

460
test/test_shared_mutex.cpp Normal file
View File

@@ -0,0 +1,460 @@
// (C) Copyright 2006-7 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/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
boost::mutex::scoped_lock lock(mutex_name); \
BOOST_CHECK_EQUAL(value,expected_value); \
}
namespace
{
template<typename lock_type>
class locking_thread
{
boost::shared_mutex& rw_mutex;
unsigned& unblocked_count;
unsigned& simultaneous_running_count;
unsigned& max_simultaneous_running;
boost::mutex& unblocked_count_mutex;
boost::mutex& finish_mutex;
public:
locking_thread(boost::shared_mutex& rw_mutex_,
unsigned& unblocked_count_,
boost::mutex& unblocked_count_mutex_,
boost::mutex& finish_mutex_,
unsigned& simultaneous_running_count_,
unsigned& max_simultaneous_running_):
rw_mutex(rw_mutex_),
unblocked_count(unblocked_count_),
unblocked_count_mutex(unblocked_count_mutex_),
finish_mutex(finish_mutex_),
simultaneous_running_count(simultaneous_running_count_),
max_simultaneous_running(max_simultaneous_running_)
{}
void operator()()
{
// acquire lock
lock_type lock(rw_mutex);
// increment count to show we're unblocked
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
++unblocked_count;
++simultaneous_running_count;
if(simultaneous_running_count>max_simultaneous_running)
{
max_simultaneous_running=simultaneous_running_count;
}
}
// wait to finish
boost::mutex::scoped_lock finish_lock(finish_mutex);
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
--simultaneous_running_count;
}
}
};
}
void test_multiple_readers()
{
unsigned const number_of_threads=100;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
}
void test_only_one_writer_permitted()
{
unsigned const number_of_threads=100;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1);
}
void test_reader_blocks_writer()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1);
}
void test_unlocking_writer_unblocks_all_readers()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex);
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
write_lock.unlock();
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
}
void test_unlocking_last_reader_only_unblocks_one_writer()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_readers=0;
unsigned max_simultaneous_readers=0;
unsigned simultaneous_running_writers=0;
unsigned max_simultaneous_writers=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_reading_mutex;
boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
boost::mutex finish_writing_mutex;
boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
unsigned const reader_count=100;
unsigned const writer_count=100;
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
}
for(unsigned i=0;i<writer_count;++i)
{
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_reading_lock.unlock();
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_writing_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1);
}
void test_only_one_upgrade_lock_permitted()
{
unsigned const number_of_threads=100;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1);
}
void test_can_lock_upgrade_if_currently_locked_shared()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
}
namespace
{
class simple_writing_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
public:
simple_writing_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::unique_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
}
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
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));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
}
namespace
{
class simple_reading_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
public:
simple_reading_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::shared_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
}
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_timed_lock_shared_times_out_if_write_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
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));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(100);
bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK(timeout<=boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_multiple_readers));
test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted));
test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
return test;
}