diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index ba4bb655..4c90abc3 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -8,25 +8,29 @@ namespace boost { - template - struct move_t + namespace detail { - T& t; - move_t(T& t_): - t(t_) - {} - - T* operator->() const + template + struct thread_move_t { - return &t; - } - }; + T& t; + thread_move_t(T& t_): + t(t_) + {} - template - move_t move(T& t) - { - return move_t(t); + T* operator->() const + { + return &t; + } + }; + + template + thread_move_t thread_move(T& t) + { + return thread_move_t(t); + } } + } diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index b56c996e..999b87f8 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -86,21 +86,21 @@ namespace boost { timed_lock(target_time); } - unique_lock(boost::move_t > other): + unique_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; } - unique_lock(boost::move_t > other); + unique_lock(detail::thread_move_t > other); - unique_lock& operator=(boost::move_t > other) + unique_lock& operator=(detail::thread_move_t > other) { unique_lock temp(other); swap(temp); return *this; } - unique_lock& operator=(boost::move_t > other) + unique_lock& operator=(detail::thread_move_t > other) { unique_lock temp(other); swap(temp); @@ -112,7 +112,7 @@ namespace boost std::swap(m,other.m); std::swap(is_locked,other.is_locked); } - void swap(boost::move_t > other) + void swap(detail::thread_move_t > other) { std::swap(m,other->m); std::swap(is_locked,other->is_locked); @@ -228,13 +228,13 @@ namespace boost timed_lock(target_time); } - shared_lock(boost::move_t > other): + shared_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; } - shared_lock(boost::move_t > other): + shared_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; @@ -244,7 +244,7 @@ namespace boost } } - shared_lock(boost::move_t > other): + shared_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; @@ -254,21 +254,21 @@ namespace boost } } - shared_lock& operator=(boost::move_t > other) + shared_lock& operator=(detail::thread_move_t > other) { shared_lock temp(other); swap(temp); return *this; } - shared_lock& operator=(boost::move_t > other) + shared_lock& operator=(detail::thread_move_t > other) { shared_lock temp(other); swap(temp); return *this; } - shared_lock& operator=(boost::move_t > other) + shared_lock& operator=(detail::thread_move_t > other) { shared_lock temp(other); swap(temp); @@ -364,13 +364,13 @@ namespace boost lock(); } } - upgrade_lock(boost::move_t > other): + upgrade_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; } - upgrade_lock(boost::move_t > other): + upgrade_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; @@ -380,14 +380,14 @@ namespace boost } } - upgrade_lock& operator=(boost::move_t > other) + upgrade_lock& operator=(detail::thread_move_t > other) { upgrade_lock temp(other); swap(temp); return *this; } - upgrade_lock& operator=(boost::move_t > other) + upgrade_lock& operator=(detail::thread_move_t > other) { upgrade_lock temp(other); swap(temp); @@ -453,7 +453,7 @@ namespace boost }; template - unique_lock::unique_lock(boost::move_t > other): + unique_lock::unique_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { other->is_locked=false; @@ -474,23 +474,23 @@ namespace boost upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&); public: explicit upgrade_to_unique_lock(upgrade_lock& m_): - source(&m_),exclusive(boost::move(*source)) + source(&m_),exclusive(detail::thread_move(*source)) {} ~upgrade_to_unique_lock() { if(source) { - *source=boost::move(exclusive); + *source=detail::thread_move(exclusive); } } - upgrade_to_unique_lock(boost::move_t > other): - source(other->source),exclusive(boost::move(other->exclusive)) + upgrade_to_unique_lock(detail::thread_move_t > other): + source(other->source),exclusive(detail::thread_move(other->exclusive)) { other->source=0; } - upgrade_to_unique_lock& operator=(boost::move_t > other) + upgrade_to_unique_lock& operator=(detail::thread_move_t > other) { upgrade_to_unique_lock temp(other); swap(temp); diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp index d86e3465..ad497230 100644 --- a/include/boost/thread/pthread/thread.hpp +++ b/include/boost/thread/pthread/thread.hpp @@ -97,7 +97,7 @@ namespace boost thread_data(F f_): f(f_) {} - thread_data(boost::move_t f_): + thread_data(detail::thread_move_t f_): f(f_) {} @@ -127,16 +127,16 @@ namespace boost start_thread(); } template - thread(boost::move_t f): + thread(detail::thread_move_t f): thread_info(new thread_data(f)) { start_thread(); } - explicit thread(boost::move_t x); - thread& operator=(boost::move_t x); - operator boost::move_t(); - boost::move_t move(); + thread(detail::thread_move_t x); + thread& operator=(detail::thread_move_t x); + operator detail::thread_move_t(); + detail::thread_move_t move(); void swap(thread& x); @@ -208,7 +208,7 @@ namespace boost ~restore_interruption(); }; - BOOST_THREAD_DECL inline thread::id get_id() + inline thread::id get_id() { return thread::id(pthread_self()); } @@ -217,13 +217,13 @@ namespace boost BOOST_THREAD_DECL bool interruption_enabled(); BOOST_THREAD_DECL bool interruption_requested(); - BOOST_THREAD_DECL inline void yield() + inline void yield() { thread::yield(); } template - BOOST_THREAD_DECL inline void sleep(TimeDuration const& rel_time) + inline void sleep(TimeDuration const& rel_time) { thread::sleep(get_system_time()+rel_time); } diff --git a/include/boost/thread/pthread/tss.hpp b/include/boost/thread/pthread/tss.hpp index c33e6d34..36c385c5 100644 --- a/include/boost/thread/pthread/tss.hpp +++ b/include/boost/thread/pthread/tss.hpp @@ -6,6 +6,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007 Anthony Williams +#include #include namespace boost diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index beebcf62..3a29ef1c 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -330,7 +330,7 @@ namespace boost template bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) { - return timed_wait(m,wait_duration.total_milliseconds(),pred); + return do_wait(m,wait_duration.total_milliseconds(),pred); } }; diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp index 93a44792..14d93f83 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/win32/thread.hpp @@ -169,7 +169,7 @@ namespace boost thread_data(F f_): f(f_) {} - thread_data(boost::move_t f_): + thread_data(detail::thread_move_t f_): f(f_) {} @@ -200,16 +200,16 @@ namespace boost start_thread(); } template - explicit thread(boost::move_t f): + thread(detail::thread_move_t f): thread_info(detail::heap_new >(f)) { start_thread(); } - thread(boost::move_t x); - thread& operator=(boost::move_t x); - operator boost::move_t(); - boost::move_t move(); + thread(detail::thread_move_t x); + thread& operator=(detail::thread_move_t x); + operator detail::thread_move_t(); + detail::thread_move_t move(); void swap(thread& x); diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 8a074db4..77aebcfd 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -188,6 +188,37 @@ namespace boost detach(); } + thread::thread(detail::thread_move_t x) + { + lock_guard lock(x->thread_info_mutex); + thread_info=x->thread_info; + x->thread_info.reset(); + } + + thread& thread::operator=(detail::thread_move_t x) + { + thread new_thread(x); + swap(new_thread); + return *this; + } + + thread::operator detail::thread_move_t() + { + return move(); + } + + detail::thread_move_t thread::move() + { + detail::thread_move_t x(*this); + return x; + } + + void thread::swap(thread& x) + { + thread_info.swap(x.thread_info); + } + + bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index d2ec1dbe..d64c78dd 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -244,30 +244,28 @@ namespace boost detach(); } - thread::thread(boost::move_t x) + thread::thread(detail::thread_move_t x) { - { - boost::mutex::scoped_lock l(x->thread_info_mutex); - thread_info=x->thread_info; - } - x->release_handle(); + lock_guard lock(x->thread_info_mutex); + thread_info=x->thread_info; + x->thread_info=0; } - thread& thread::operator=(boost::move_t x) + thread& thread::operator=(detail::thread_move_t x) { thread new_thread(x); swap(new_thread); return *this; } - thread::operator boost::move_t() + thread::operator detail::thread_move_t() { return move(); } - boost::move_t thread::move() + detail::thread_move_t thread::move() { - boost::move_t x(*this); + detail::thread_move_t x(*this); return x; } @@ -317,7 +315,7 @@ namespace boost void thread::release_handle() { - boost::mutex::scoped_lock l1(thread_info_mutex); + lock_guard l1(thread_info_mutex); thread_info=0; } @@ -379,9 +377,9 @@ namespace boost target_system_time.wYear=target_time.abs_time.date().year(); target_system_time.wMonth=target_time.abs_time.date().month(); target_system_time.wDay=target_time.abs_time.date().day(); - target_system_time.wHour=target_time.abs_time.time_of_day().hours(); - target_system_time.wMinute=target_time.abs_time.time_of_day().minutes(); - target_system_time.wSecond=target_time.abs_time.time_of_day().seconds(); + target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours(); + target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes(); + target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds(); if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time))) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index be5fea7b..4ff2d48f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -35,6 +35,7 @@ rule thread-run ( sources ) { test-suite "threads" : [ thread-run test_thread.cpp ] + [ thread-run test_thread_move.cpp ] [ thread-run test_mutex.cpp ] [ thread-run test_condition_notify_one.cpp ] [ thread-run test_condition_timed_wait_times_out.cpp ] @@ -45,6 +46,7 @@ rule thread-run ( sources ) [ thread-run test_xtime.cpp ] [ thread-run test_barrier.cpp ] [ thread-run test_shared_mutex.cpp ] + [ thread-run test_shared_mutex_part_2.cpp ] [ thread-run test_lock_concept.cpp ] ; } diff --git a/test/shared_mutex_locking_thread.hpp b/test/shared_mutex_locking_thread.hpp new file mode 100644 index 00000000..1fccbddf --- /dev/null +++ b/test/shared_mutex_locking_thread.hpp @@ -0,0 +1,62 @@ +#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP +#define SHARED_MUTEX_LOCKING_THREAD_HPP + +#include +#include +#include + +template +class locking_thread +{ + boost::shared_mutex& rw_mutex; + unsigned& unblocked_count; + boost::condition_variable& unblocked_condition; + 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::condition_variable& unblocked_condition_, + boost::mutex& finish_mutex_, + unsigned& simultaneous_running_count_, + unsigned& max_simultaneous_running_): + rw_mutex(rw_mutex_), + unblocked_count(unblocked_count_), + unblocked_condition(unblocked_condition_), + simultaneous_running_count(simultaneous_running_count_), + max_simultaneous_running(max_simultaneous_running_), + unblocked_count_mutex(unblocked_count_mutex_), + finish_mutex(finish_mutex_) + {} + + 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; + unblocked_condition.notify_one(); + ++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; + } + } +}; + + +#endif diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp index 08170fd2..ed2c2571 100644 --- a/test/test_mutex.cpp +++ b/test/test_mutex.cpp @@ -102,6 +102,11 @@ struct test_timedlock typedef M mutex_type; typedef typename M::scoped_timed_lock timed_lock_type; + static bool fake_predicate() + { + return false; + } + void operator()() { mutex_type mutex; @@ -123,14 +128,17 @@ struct test_timedlock BOOST_CHECK(lock ? true : false); // Construct and initialize an xtime for a fast time out. - boost::xtime xt = delay(0, 100); + boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100); // Test the lock and the mutex with condition variables. // No one is going to notify this condition variable. We expect to // time out. - BOOST_CHECK(!condition.timed_wait(lock, xt)); + BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate)); BOOST_CHECK(lock ? true : false); - BOOST_CHECK(in_range(xt)); + + boost::system_time now=boost::get_system_time(); + boost::posix_time::milliseconds const timeout_resolution(20); + BOOST_CHECK((now-timeout_resolution) #include -#include -#include -#include #include #include "util.inl" -#include -#include +#include "shared_mutex_locking_thread.hpp" #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ { \ @@ -19,65 +15,6 @@ BOOST_CHECK_EQUAL(value,expected_value); \ } - -namespace -{ - template - 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::condition_variable& unblocked_condition; - boost::mutex& finish_mutex; - public: - locking_thread(boost::shared_mutex& rw_mutex_, - unsigned& unblocked_count_, - boost::mutex& unblocked_count_mutex_, - boost::condition_variable& unblocked_condition_, - boost::mutex& finish_mutex_, - unsigned& simultaneous_running_count_, - unsigned& max_simultaneous_running_): - rw_mutex(rw_mutex_), - unblocked_count(unblocked_count_), - unblocked_condition(unblocked_condition_), - simultaneous_running_count(simultaneous_running_count_), - max_simultaneous_running(max_simultaneous_running_), - unblocked_count_mutex(unblocked_count_mutex_), - finish_mutex(finish_mutex_) - {} - - 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; - unblocked_condition.notify_one(); - ++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; @@ -328,250 +265,11 @@ void test_unlocking_last_reader_only_unblocks_one_writer() throw; } - 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,1u); } -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::condition_variable unblocked_condition; - boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); - - try - { - for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - 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(); - } - catch(...) - { - pool.interrupt_all(); - pool.join_all(); - throw; - } - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); -} - -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::condition_variable unblocked_condition; - boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); - - unsigned const reader_count=100; - - try - { - for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - } - boost::thread::sleep(delay(1)); - pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count<(reader_count+1)) - { - unblocked_condition.wait(lk); - } - } - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); - - finish_lock.unlock(); - pool.join_all(); - } - catch(...) - { - pool.interrupt_all(); - pool.join_all(); - throw; - } - - - 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 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::this_thread::sleep(boost::posix_time::seconds(1)); - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); - - 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 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,1u); - - 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,1u); - - boost::system_time const start=boost::get_system_time(); - boost::system_time const timeout=start+boost::posix_time::milliseconds(2000); - bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); - BOOST_CHECK(in_range(boost::get_xtime(timeout),1)); - 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 = @@ -582,12 +280,6 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) 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; } diff --git a/test/test_shared_mutex_part_2.cpp b/test/test_shared_mutex_part_2.cpp new file mode 100644 index 00000000..5666a956 --- /dev/null +++ b/test/test_shared_mutex_part_2.cpp @@ -0,0 +1,271 @@ +// (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 +#include +#include +#include "util.inl" +#include "shared_mutex_locking_thread.hpp" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + + +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::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + 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(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +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::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=100; + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + boost::thread::sleep(delay(1)); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<(reader_count+1)) + { + unblocked_condition.wait(lk); + } + } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + + finish_lock.unlock(); + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + + 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 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::this_thread::sleep(boost::posix_time::seconds(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + 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 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,1u); + + 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,1u); + + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+boost::posix_time::milliseconds(2000); + boost::posix_time::milliseconds const timeout_resolution(20); + bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); + BOOST_CHECK((timeout-timeout_resolution)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; +} diff --git a/test/test_thread_move.cpp b/test/test_thread_move.cpp new file mode 100644 index 00000000..dc8f964f --- /dev/null +++ b/test/test_thread_move.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2007 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 +#include + +void do_nothing() +{} + +void test_move_on_construction() +{ + boost::thread x=boost::thread(do_nothing); + x.join(); +} + +boost::thread make_thread() +{ + return boost::thread(do_nothing); +} + +void test_move_from_function_return() +{ + boost::thread x=make_thread(); + x.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: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_move_on_construction)); + test->add(BOOST_TEST_CASE(test_move_from_function_return)); + return test; +}