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:
@@ -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
173
test/test_lock_concept.cpp
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
460
test/test_shared_mutex.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user