2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-24 18:32:32 +00:00

Merged revisions 41678-41775 via svnmerge from

https://svn.boost.org/svn/boost/trunk

........
  r41679 | anthonyw | 2007-12-03 23:57:23 -0800 (Mon, 03 Dec 2007) | 1 line
  
  fixed typo in condition_variable_any::timed_wait
........
  r41681 | anthonyw | 2007-12-04 01:15:37 -0800 (Tue, 04 Dec 2007) | 1 line
  
  changed boost::move to boost::detail::thread_move to fix issue #1492
........
  r41682 | anthonyw | 2007-12-04 02:04:30 -0800 (Tue, 04 Dec 2007) | 1 line
  
  split shared mutex tests in two to take less time
........
  r41683 | anthonyw | 2007-12-04 03:44:25 -0800 (Tue, 04 Dec 2007) | 1 line
  
  don't dllexport/dllimport inline functions
........
  r41684 | anthonyw | 2007-12-04 04:08:38 -0800 (Tue, 04 Dec 2007) | 1 line
  
  add explicit casts to remove warnings
........
  r41686 | anthonyw | 2007-12-04 05:02:58 -0800 (Tue, 04 Dec 2007) | 1 line
  
  Added test for thread move constructor; implemented move on pthreads
........
  r41687 | anthonyw | 2007-12-04 06:07:01 -0800 (Tue, 04 Dec 2007) | 1 line
  
  changed order of declaration to eliminate warnings
........
  r41688 | nesotto | 2007-12-04 06:41:44 -0800 (Tue, 04 Dec 2007) | 1 line
  
  ticket 1488
........
  r41696 | fmhess | 2007-12-04 11:42:08 -0800 (Tue, 04 Dec 2007) | 2 lines
  
  Make sure output filenames don't include any illegal characters.
........
  r41697 | fmhess | 2007-12-04 11:45:10 -0800 (Tue, 04 Dec 2007) | 4 lines
  
  Fixed printing of object name for nested classes (merge of
  revision 41421 from sandbox/boost_docs).
........
  r41698 | fmhess | 2007-12-04 11:55:50 -0800 (Tue, 04 Dec 2007) | 17 lines
  
  Made generated ids for functions and overloaded functions human-readable 
  which also results in (mostly) human-readable names for 
  their .html output files. Made generate.id template properly use 
  its node parameter (merge of parts of revision 41461 from sandbox/boost_docs). 
  
  Made class name in synopsis a link to class reference page, which is useful 
  for nested classes (merge of revision 41435 from sandbox/boost_docs). 
  
  Removed spurious new line in synopisis between a nested class 
  and the comment describing its purpose (merge of revision 41434 from
  sandbox/boost_docs). 
  
  Added a warning if an "inherit" element has 
  no "type" child element (partial merge of revision 41463 from
  sandbox/boost_docs). 
........
  r41701 | chris_kohlhoff | 2007-12-04 13:28:42 -0800 (Tue, 04 Dec 2007) | 2 lines
  
  Prevent deprecated function warnings for MSVC >= 8.
........
  r41703 | nasonov | 2007-12-04 13:49:51 -0800 (Tue, 04 Dec 2007) | 1 line
  
  Link to html version of [Tuning] and BOOST_LEXICAL_CAST_ASSUME_C_LOCALE synopsis
........
  r41704 | igaztanaga | 2007-12-04 14:05:28 -0800 (Tue, 04 Dec 2007) | 1 line
  
  Added Leopard workaround. _POSIX_THREAD_PROCESS_SHARED is defined but does not seem to work. For the moment, Mac OS will use emulation code
........
  r41705 | djenkins | 2007-12-04 14:19:58 -0800 (Tue, 04 Dec 2007) | 1 line
  
  Fix msvc-9.0 code analysis problem
........
  r41707 | noel_belcourt | 2007-12-04 15:18:38 -0800 (Tue, 04 Dec 2007) | 6 lines
  
  Fixes to get pgi shared libraries working, executables
  that don't core, and limiting the number of error
  messages emitted by the compiler so as to reduce the
  size of the log file.
........
  r41727 | grafik | 2007-12-04 16:32:04 -0800 (Tue, 04 Dec 2007) | 1 line
  
  Switch FTP site for results.
........
  r41734 | noel_belcourt | 2007-12-04 19:11:25 -0800 (Tue, 04 Dec 2007) | 5 lines
  
  Pgi compilers can't accept shared library with Boost version 
  suffix appended to it.  Add logic to tag rule in Jamroot to 
  suppress appending version suffix for pgi toolset.
........
  r41735 | noel_belcourt | 2007-12-04 19:20:30 -0800 (Tue, 04 Dec 2007) | 3 lines
  
  Patch pgi shared library use.
........
  r41736 | grafik | 2007-12-04 20:33:36 -0800 (Tue, 04 Dec 2007) | 1 line
  
  Fix parsing of macosx version numbers from detected SDKs.
........
  r41738 | anthonyw | 2007-12-05 00:27:44 -0800 (Wed, 05 Dec 2007) | 1 line
  
  added missing include of detail/config.hpp
........
  r41739 | t_schwinger | 2007-12-05 02:24:21 -0800 (Wed, 05 Dec 2007) | 3 lines
  
  clarifies #error message
........
  r41740 | t_schwinger | 2007-12-05 02:26:16 -0800 (Wed, 05 Dec 2007) | 2 lines
  
  updates function_types failures
........
  r41741 | anthonyw | 2007-12-05 02:58:45 -0800 (Wed, 05 Dec 2007) | 1 line
  
  improved timeout checks
........
  r41742 | t_schwinger | 2007-12-05 05:20:13 -0800 (Wed, 05 Dec 2007) | 3 lines
  
  attempts to fix strange problems with Pathscale compilers
........
  r41762 | chris_kohlhoff | 2007-12-05 13:46:19 -0800 (Wed, 05 Dec 2007) | 2 lines
  
  Don't use deprecated function workaround when compiling for Windows CE.
........
  r41770 | ramey | 2007-12-05 18:33:59 -0800 (Wed, 05 Dec 2007) | 2 lines
  
  change to fix failures with gcc 4.1+
  modification to string input primitives
........
  r41775 | djenkins | 2007-12-05 22:23:55 -0800 (Wed, 05 Dec 2007) | 1 line
  
  Avoid bug in Microsoft Code Analysis
........


[SVN r41776]
This commit is contained in:
Eric Niebler
2007-12-06 07:20:07 +00:00
parent df4283a230
commit 23100a0181
14 changed files with 484 additions and 378 deletions

View File

@@ -8,25 +8,29 @@
namespace boost
{
template<typename T>
struct move_t
namespace detail
{
T& t;
move_t(T& t_):
t(t_)
{}
T* operator->() const
template<typename T>
struct thread_move_t
{
return &t;
}
};
T& t;
thread_move_t(T& t_):
t(t_)
{}
template<typename T>
move_t<T> move(T& t)
{
return move_t<T>(t);
T* operator->() const
{
return &t;
}
};
template<typename T>
thread_move_t<T> thread_move(T& t)
{
return thread_move_t<T>(t);
}
}
}

View File

@@ -86,21 +86,21 @@ namespace boost
{
timed_lock(target_time);
}
unique_lock(boost::move_t<unique_lock<Mutex> > other):
unique_lock(detail::thread_move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
}
unique_lock(boost::move_t<upgrade_lock<Mutex> > other);
unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other);
unique_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
{
unique_lock temp(other);
swap(temp);
return *this;
}
unique_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > 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<unique_lock<Mutex> > other)
void swap(detail::thread_move_t<unique_lock<Mutex> > 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<shared_lock<Mutex> > other):
shared_lock(detail::thread_move_t<shared_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
}
shared_lock(boost::move_t<unique_lock<Mutex> > other):
shared_lock(detail::thread_move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -244,7 +244,7 @@ namespace boost
}
}
shared_lock(boost::move_t<upgrade_lock<Mutex> > other):
shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > 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<shared_lock<Mutex> > other)
shared_lock& operator=(detail::thread_move_t<shared_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
return *this;
}
shared_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
shared_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
return *this;
}
shared_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
shared_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
@@ -364,13 +364,13 @@ namespace boost
lock();
}
}
upgrade_lock(boost::move_t<upgrade_lock<Mutex> > other):
upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
}
upgrade_lock(boost::move_t<unique_lock<Mutex> > other):
upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > 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<upgrade_lock<Mutex> > other)
upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
{
upgrade_lock temp(other);
swap(temp);
return *this;
}
upgrade_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
upgrade_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
{
upgrade_lock temp(other);
swap(temp);
@@ -453,7 +453,7 @@ namespace boost
};
template<typename Mutex>
unique_lock<Mutex>::unique_lock(boost::move_t<upgrade_lock<Mutex> > other):
unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > 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<Mutex>& 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<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(boost::move(other->exclusive))
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(detail::thread_move(other->exclusive))
{
other->source=0;
}
upgrade_to_unique_lock& operator=(boost::move_t<upgrade_to_unique_lock<Mutex> > other)
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other)
{
upgrade_to_unique_lock temp(other);
swap(temp);

View File

@@ -97,7 +97,7 @@ namespace boost
thread_data(F f_):
f(f_)
{}
thread_data(boost::move_t<F> f_):
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
@@ -127,16 +127,16 @@ namespace boost
start_thread();
}
template <class F>
thread(boost::move_t<F> f):
thread(detail::thread_move_t<F> f):
thread_info(new thread_data<F>(f))
{
start_thread();
}
explicit thread(boost::move_t<thread> x);
thread& operator=(boost::move_t<thread> x);
operator boost::move_t<thread>();
boost::move_t<thread> move();
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> 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<typename TimeDuration>
BOOST_THREAD_DECL inline void sleep(TimeDuration const& rel_time)
inline void sleep(TimeDuration const& rel_time)
{
thread::sleep(get_system_time()+rel_time);
}

View File

@@ -6,6 +6,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
namespace boost

View File

@@ -330,7 +330,7 @@ namespace boost
template<typename lock_type,typename duration_type,typename predicate_type>
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);
}
};

View File

@@ -169,7 +169,7 @@ namespace boost
thread_data(F f_):
f(f_)
{}
thread_data(boost::move_t<F> f_):
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
@@ -200,16 +200,16 @@ namespace boost
start_thread();
}
template <class F>
explicit thread(boost::move_t<F> f):
thread(detail::thread_move_t<F> f):
thread_info(detail::heap_new<thread_data<F> >(f))
{
start_thread();
}
thread(boost::move_t<thread> x);
thread& operator=(boost::move_t<thread> x);
operator boost::move_t<thread>();
boost::move_t<thread> move();
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
void swap(thread& x);

View File

@@ -188,6 +188,37 @@ namespace boost
detach();
}
thread::thread(detail::thread_move_t<thread> x)
{
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& thread::operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> thread::move()
{
detail::thread_move_t<thread> 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();

View File

@@ -244,30 +244,28 @@ namespace boost
detach();
}
thread::thread(boost::move_t<thread> x)
thread::thread(detail::thread_move_t<thread> x)
{
{
boost::mutex::scoped_lock l(x->thread_info_mutex);
thread_info=x->thread_info;
}
x->release_handle();
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info=0;
}
thread& thread::operator=(boost::move_t<thread> x)
thread& thread::operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator boost::move_t<thread>()
thread::operator detail::thread_move_t<thread>()
{
return move();
}
boost::move_t<thread> thread::move()
detail::thread_move_t<thread> thread::move()
{
boost::move_t<thread> x(*this);
detail::thread_move_t<thread> x(*this);
return x;
}
@@ -317,7 +315,7 @@ namespace boost
void thread::release_handle()
{
boost::mutex::scoped_lock l1(thread_info_mutex);
lock_guard<mutex> 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)))
{

View File

@@ -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 ]
;
}

View File

@@ -0,0 +1,62 @@
#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
#define SHARED_MUTEX_LOCKING_THREAD_HPP
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/shared_mutex.hpp>
template<typename lock_type>
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

View File

@@ -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)<timeout);
// Test the lock, unlock and timedlock methods.
lock.unlock();

View File

@@ -5,13 +5,9 @@
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#include <iostream>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#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<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::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<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(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<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(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<boost::upgrade_lock<boost::shared_mutex> >(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<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::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<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,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;
}

View File

@@ -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 <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#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<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(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<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(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<boost::upgrade_lock<boost::shared_mutex> >(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<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::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<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,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)<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_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;
}

37
test/test_thread_move.cpp Normal file
View File

@@ -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 <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
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;
}