2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 09:42:16 +00:00

Compare commits

...

23 Commits

Author SHA1 Message Date
Jonathan Turkanis
870d154ca1 Branch for Iostreams development
[SVN r42144]
2007-12-18 20:08:11 +00:00
Anthony Williams
25ad6e3f8f boost::move support for locks
[SVN r42118]
2007-12-17 12:52:50 +00:00
Anthony Williams
df0197b617 Updated move function test to be fair to Borland
[SVN r42117]
2007-12-17 11:24:13 +00:00
Anthony Williams
a89c4f01ad explicit move functions for threads, with a test
[SVN r42087]
2007-12-15 22:36:43 +00:00
Anthony Williams
ae67099633 added timed_wait overloads that take a duration
[SVN r42086]
2007-12-15 22:34:30 +00:00
Anthony Williams
57542d3a5c fixed order of comparison in timeout check
[SVN r41819]
2007-12-07 08:11:11 +00:00
Anthony Williams
9a1da14116 improved timeout checks
[SVN r41741]
2007-12-05 10:58:45 +00:00
Anthony Williams
ed050d753d added missing include of detail/config.hpp
[SVN r41738]
2007-12-05 08:27:44 +00:00
Anthony Williams
8bec363710 changed order of declaration to eliminate warnings
[SVN r41687]
2007-12-04 14:07:01 +00:00
Anthony Williams
7c68e190a9 Added test for thread move constructor; implemented move on pthreads
[SVN r41686]
2007-12-04 13:02:58 +00:00
Anthony Williams
7ebf5ea3d1 add explicit casts to remove warnings
[SVN r41684]
2007-12-04 12:08:38 +00:00
Anthony Williams
11e0435a4b don't dllexport/dllimport inline functions
[SVN r41683]
2007-12-04 11:44:25 +00:00
Anthony Williams
d15ee57cd1 split shared mutex tests in two to take less time
[SVN r41682]
2007-12-04 10:04:30 +00:00
Anthony Williams
56d660b7fd changed boost::move to boost::detail::thread_move to fix issue #1492
[SVN r41681]
2007-12-04 09:15:37 +00:00
Anthony Williams
792958e693 fixed typo in condition_variable_any::timed_wait
[SVN r41679]
2007-12-04 07:57:23 +00:00
Anthony Williams
914e67dc04 check predicate before returning if we time out on a predicated version of timed_wait
[SVN r41668]
2007-12-03 22:00:26 +00:00
Anthony Williams
b50a7ccb61 interruptible_wait (and hence condition timed_wait) now uses a WaitableTimer where possible, to be robust in the face of clock changes
[SVN r41505]
2007-11-30 18:38:21 +00:00
Anthony Williams
f827709d42 add support for relative timeouts to condition timed_wait
[SVN r41413]
2007-11-27 14:24:29 +00:00
Anthony Williams
36abb42175 reverted accidental checkin of new timed_wait functions on condition_variable
[SVN r41405]
2007-11-26 21:15:04 +00:00
Anthony Williams
40f3b1b4c8 once_flag uses zero-initialization on POSIX as well as windows
[SVN r41401]
2007-11-26 17:01:08 +00:00
Anthony Williams
4f35e25688 fixed import/export declarations so new once code works with pthread-win32
[SVN r41398]
2007-11-26 15:44:07 +00:00
Anthony Williams
270e88edd7 Don't compare native_handle_t against 0 --- do appropriate checks in create_native_thread for platforms where pthread_t is not comparable
[SVN r41396]
2007-11-26 13:29:15 +00:00
Anthony Williams
5ded171247 workaround for Borland compiler
[SVN r41395]
2007-11-26 12:17:45 +00:00
33 changed files with 1510 additions and 546 deletions

View File

@@ -157,6 +157,7 @@ rule usage-requirements ( properties * )
rule requirements ( properties * )
{
local result ;
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
@@ -201,5 +202,7 @@ lib boost_thread
: thread_sources
: <conditional>@requirements
:
: <conditional>@usage-requirements
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
<link>static:<define>BOOST_THREAD_USE_LIB=1
<conditional>@usage-requirements
;

View File

@@ -17,8 +17,7 @@
# pragma warn -8066 // Unreachable code
#endif
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#include "platform.hpp"
// compatibility with the rest of Boost's auto-linking code:
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
@@ -31,7 +30,7 @@
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
#else //Use default
# if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_THREAD_PLATFORM_WIN32)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib

View File

@@ -8,25 +8,23 @@
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;
}
};
}
}

View File

@@ -86,21 +86,32 @@ 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;
other->m=0;
}
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)
operator detail::thread_move_t<unique_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<unique_lock<Mutex> > move()
{
return detail::thread_move_t<unique_lock<Mutex> >(*this);
}
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 +123,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);
@@ -196,6 +207,18 @@ namespace boost
friend class upgrade_lock<Mutex>;
};
template<typename Mutex>
inline detail::thread_move_t<unique_lock<Mutex> > move(unique_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<unique_lock<Mutex> > move(detail::thread_move_t<unique_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
class shared_lock
{
@@ -228,13 +251,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 +267,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 +277,32 @@ namespace boost
}
}
shared_lock& operator=(boost::move_t<shared_lock<Mutex> > other)
operator detail::thread_move_t<shared_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<shared_lock<Mutex> > move()
{
return detail::thread_move_t<shared_lock<Mutex> >(*this);
}
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);
@@ -341,6 +375,19 @@ namespace boost
};
template<typename Mutex>
inline detail::thread_move_t<shared_lock<Mutex> > move(shared_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<shared_lock<Mutex> > move(detail::thread_move_t<shared_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
class upgrade_lock
{
@@ -364,13 +411,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 +427,25 @@ namespace boost
}
}
upgrade_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
operator detail::thread_move_t<upgrade_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<upgrade_lock<Mutex> > move()
{
return detail::thread_move_t<upgrade_lock<Mutex> >(*this);
}
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);
@@ -452,8 +510,21 @@ namespace boost
friend class unique_lock<Mutex>;
};
template<typename Mutex>
unique_lock<Mutex>::unique_lock(boost::move_t<upgrade_lock<Mutex> > other):
inline detail::thread_move_t<upgrade_lock<Mutex> > move(upgrade_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<upgrade_lock<Mutex> > move(detail::thread_move_t<upgrade_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
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 +545,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(move(*source))
{}
~upgrade_to_unique_lock()
{
if(source)
{
*source=boost::move(exclusive);
*source=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(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);
@@ -515,6 +586,7 @@ namespace boost
return exclusive.owns_lock();
}
};
}
#endif

View File

@@ -5,11 +5,9 @@
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/mutex.hpp>
#include <limits.h>
#include <boost/assert.hpp>
#include <algorithm>
#include <boost/thread/thread_time.hpp>
#include <pthread.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
@@ -145,11 +143,23 @@ namespace boost
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
return pred();
}
return true;
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
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,get_system_time()+wait_duration,pred);
}
void notify_one()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);

View File

@@ -6,8 +6,10 @@
// (C) Copyright 2007 Anthony Williams
#include <pthread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -39,11 +41,23 @@ namespace boost
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
return pred();
}
return true;
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
void notify_one();
void notify_all();
};

View File

@@ -14,8 +14,8 @@
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/cstdint.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
namespace boost {
@@ -27,12 +27,12 @@ namespace boost {
namespace detail
{
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
extern BOOST_THREAD_DECL boost::uintmax_t once_global_epoch;
extern BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex;
extern BOOST_THREAD_DECL pthread_cond_t once_epoch_cv;
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
}
#define BOOST_ONCE_INITIAL_FLAG_VALUE -1
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
@@ -42,15 +42,15 @@ namespace boost {
void call_once(once_flag& flag,Function f)
{
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
static boost::uintmax_t const being_initialized=uninitialized_flag-1;
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
boost::uintmax_t const epoch=flag.epoch;
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
if(epoch>this_thread_epoch)
if(epoch<this_thread_epoch)
{
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
while(flag.epoch>=being_initialized)
while(flag.epoch<=being_initialized)
{
if(flag.epoch==uninitialized_flag)
{
@@ -66,7 +66,7 @@ namespace boost {
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
throw;
}
flag.epoch=++detail::once_global_epoch;
flag.epoch=--detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
}
else

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);
@@ -169,6 +169,17 @@ namespace boost
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
@@ -208,7 +219,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 +228,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

@@ -13,6 +13,7 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -110,54 +111,65 @@ namespace boost
};
template<typename lock_type>
void start_wait_loop_first_time(relocker<lock_type>& locker,
detail::win32::handle_manager& local_wake_sem)
{
locker.unlock();
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(wake_sem);
}
local_wake_sem=detail::win32::duplicate_handle(wake_sem);
if(generations[0].notified)
{
shift_generations_down();
}
else if(!active_generation_count)
{
active_generation_count=1;
}
}
template<typename lock_type>
void start_wait_loop(relocker<lock_type>& locker,
detail::win32::handle_manager& local_wake_sem,
detail::win32::handle_manager& sem)
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
detail::interlocked_write_release(&total_count,total_count+1);
if(!local_wake_sem)
{
start_wait_loop_first_time(locker,local_wake_sem);
}
if(!generations[0].semaphore)
{
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(generations[0].semaphore);
}
++generations[0].count;
sem=detail::win32::duplicate_handle(generations[0].semaphore);
}
protected:
template<typename lock_type>
bool do_wait(lock_type& lock,::boost::system_time const& wait_until)
bool do_wait(lock_type& lock,timeout wait_until)
{
detail::win32::handle_manager local_wake_sem;
detail::win32::handle_manager sem;
bool first_loop=true;
bool woken=false;
relocker<lock_type> locker(lock);
while(!woken)
{
start_wait_loop(locker,local_wake_sem,sem);
if(!this_thread::interruptible_wait(sem,wait_until))
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
detail::interlocked_write_release(&total_count,total_count+1);
if(first_loop)
{
locker.unlock();
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(wake_sem);
}
local_wake_sem=detail::win32::duplicate_handle(wake_sem);
if(generations[0].notified)
{
shift_generations_down();
}
else if(!active_generation_count)
{
active_generation_count=1;
}
first_loop=false;
}
if(!generations[0].semaphore)
{
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(generations[0].semaphore);
}
++generations[0].count;
sem=detail::win32::duplicate_handle(generations[0].semaphore);
}
if(!this_thread::interruptible_wait(sem,::boost::detail::get_milliseconds_until(wait_until)))
{
break;
return false;
}
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
@@ -167,6 +179,17 @@ namespace boost
}
return woken;
}
template<typename lock_type,typename predicate_type>
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!do_wait(m, wait_until))
return pred();
}
return true;
}
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
@@ -238,7 +261,7 @@ namespace boost
public:
void wait(unique_lock<mutex>& m)
{
do_wait(m,::boost::detail::get_system_time_sentinel());
do_wait(m,detail::timeout::sentinel());
}
template<typename predicate_type>
@@ -253,15 +276,30 @@ namespace boost
return do_wait(m,wait_until);
}
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
}
return true;
return do_wait(m,wait_until,pred);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};
@@ -272,7 +310,7 @@ namespace boost
template<typename lock_type>
void wait(lock_type& m)
{
do_wait(m,::boost::detail::get_system_time_sentinel());
do_wait(m,detail::timeout::sentinel());
}
template<typename lock_type,typename predicate_type>
@@ -287,15 +325,34 @@ namespace boost
return do_wait(m,wait_until);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
}
return true;
return do_wait(m,wait_until,pred);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
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 do_wait(m,wait_duration.total_milliseconds(),pred);
}
};

View File

@@ -48,10 +48,10 @@ namespace boost
}
state_data state;
void* semaphores[2];
void* &unlock_sem;
void* &exclusive_sem;
void* upgrade_sem;
detail::win32::handle semaphores[2];
detail::win32::handle &unlock_sem;
detail::win32::handle &exclusive_sem;
detail::win32::handle upgrade_sem;
void release_waiters(state_data old_state)
{

View File

@@ -19,6 +19,7 @@
#include <list>
#include <algorithm>
#include <boost/ref.hpp>
#include <boost/cstdint.hpp>
namespace boost
{
@@ -73,6 +74,82 @@ namespace boost
};
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
{
unsigned long start;
uintmax_t milliseconds;
bool relative;
boost::system_time abs_time;
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct remaining_time
{
bool more;
unsigned long milliseconds;
remaining_time(uintmax_t remaining):
more(remaining>max_non_infinite_wait),
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
{}
};
remaining_time remaining_milliseconds() const
{
if(is_sentinel())
{
return remaining_time(win32::infinite);
}
else if(relative)
{
unsigned long const now=win32::GetTickCount();
unsigned long const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}
else
{
system_time const now=get_system_time();
if(abs_time<=now)
{
return remaining_time(0);
}
return remaining_time((abs_time-now).total_milliseconds()+1);
}
}
bool is_sentinel() const
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
return timeout(sentinel_type());
}
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
}
class BOOST_THREAD_DECL thread
@@ -92,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_)
{}
@@ -123,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);
@@ -168,6 +245,16 @@ namespace boost
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
@@ -210,7 +297,7 @@ namespace boost
thread::id BOOST_THREAD_DECL get_id();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds);
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline bool interruptible_wait(unsigned long milliseconds)
{
return interruptible_wait(detail::win32::invalid_handle_value,milliseconds);

View File

@@ -53,6 +53,7 @@ namespace boost
using ::SleepEx;
using ::Sleep;
using ::QueueUserAPC;
using ::GetTickCount;
}
}
}
@@ -120,6 +121,8 @@ namespace boost
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
__declspec(dllimport) unsigned long __stdcall GetTickCount();
# ifndef UNDER_CE
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();

View File

@@ -3,6 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define __STDC_CONSTANT_MACROS
#include <boost/thread/once.hpp>
#include <boost/assert.hpp>
#include <pthread.h>
@@ -12,9 +13,9 @@ namespace boost
{
namespace detail
{
boost::uintmax_t once_global_epoch=0;
pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
namespace
{
@@ -41,11 +42,10 @@ namespace boost
{
data=malloc(sizeof(boost::uintmax_t));
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
*static_cast<boost::uintmax_t*>(data)=0;
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
}
return *static_cast<boost::uintmax_t*>(data);
}
}
}

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

@@ -4,6 +4,9 @@
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
#define _WIN32_WINNT 0x400
#define WINVER 0x400
#include <boost/thread/thread.hpp>
#include <algorithm>
#include <windows.h>
@@ -15,6 +18,7 @@
#include <boost/thread/tss.hpp>
#include <boost/assert.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
namespace boost
{
@@ -63,11 +67,11 @@ namespace boost
typedef void* uintptr_t;
inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
void* arglist, unsigned initflag, unsigned* thrdaddr)
void* arglist, unsigned initflag, unsigned* thrdaddr)
{
DWORD threadID;
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
new ThreadProxyData(start_address,arglist),initflag,&threadID);
new ThreadProxyData(start_address,arglist),initflag,&threadID);
if (hthread!=0)
*thrdaddr=threadID;
return reinterpret_cast<uintptr_t const>(hthread);
@@ -240,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;
}
@@ -287,7 +289,7 @@ namespace boost
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite);
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
release_handle();
}
}
@@ -313,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;
}
@@ -353,13 +355,57 @@ namespace boost
namespace this_thread
{
bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds)
namespace
{
detail::win32::handle handles[2]={0};
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={0};
if(target_time.relative)
{
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
if(remaining_milliseconds>0)
{
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
}
}
else
{
SYSTEMTIME target_system_time={0};
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=(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)))
{
due_time.QuadPart=0;
}
else
{
long const hundred_nanoseconds_in_one_second=10000000;
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
}
}
return due_time;
}
}
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
{
detail::win32::handle handles[3]={0};
unsigned handle_count=0;
unsigned wait_handle_index=~0U;
unsigned interruption_index=~0U;
unsigned timeout_index=~0U;
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
{
wait_handle_index=handle_count;
handles[handle_count++]=handle_to_wait_for;
}
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
@@ -367,24 +413,79 @@ namespace boost
interruption_index=handle_count;
handles[handle_count++]=get_current_thread_data()->interruption_handle;
}
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
if(time_left.milliseconds > min_timer_wait_period)
{
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
if(set_time_succeeded)
{
timeout_index=handle_count;
handles[handle_count++]=timer_handle;
}
}
}
else if(!target_time.relative)
{
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
target_time=detail::timeout(time_left.milliseconds);
}
}
#endif
if(handle_count)
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds);
if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index)
if(!using_timer)
{
return true;
time_left=target_time.remaining_milliseconds();
}
else if(notified_index==interruption_index)
if(handle_count)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
{
return true;
}
else if(notified_index==interruption_index)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
else if(notified_index==timeout_index)
{
return false;
}
}
}
else
{
detail::win32::Sleep(time_left.milliseconds);
}
if(target_time.relative)
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
}
}
else
{
detail::win32::Sleep(milliseconds);
}
while(time_left.more);
return false;
}
@@ -494,7 +595,7 @@ namespace boost
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func)
if(cleanup_existing && current_node->func.get())
{
(*current_node->func)(current_node->value);
}

View File

@@ -230,13 +230,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv)
{
OutputDebugString("on_tls_callback\n");
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
OutputDebugString("on_tls_callback: thread_exit\n");
on_thread_exit();
break;
}

View File

@@ -1,4 +1,5 @@
# (C) Copyright William E. Kempf 2001.
# (C) Copyright 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)
#
@@ -34,13 +35,19 @@ rule thread-run ( sources )
{
test-suite "threads"
: [ thread-run test_thread.cpp ]
[ thread-run test_thread_move.cpp ]
[ thread-run test_move_function.cpp ]
[ thread-run test_mutex.cpp ]
[ thread-run test_condition_notify_one.cpp ]
[ thread-run test_condition_timed_wait_times_out.cpp ]
[ thread-run test_condition_notify_all.cpp ]
[ thread-run test_condition.cpp ]
[ thread-run test_tss.cpp ]
[ thread-run test_once.cpp ]
[ 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,95 @@
#ifndef CONDITION_TEST_COMMON_HPP
#define CONDITION_TEST_COMMON_HPP
// 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/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread_time.hpp>
unsigned const timeout_seconds=5;
struct wait_for_flag
{
boost::mutex mutex;
boost::condition_variable cond_var;
bool flag;
unsigned woken;
wait_for_flag():
flag(false),woken(0)
{}
struct check_flag
{
bool const& flag;
check_flag(bool const& flag_):
flag(flag_)
{}
bool operator()() const
{
return flag;
}
};
void wait_without_predicate()
{
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
cond_var.wait(lock);
}
++woken;
}
void wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
cond_var.wait(lock,check_flag(flag));
if(flag)
{
++woken;
}
}
void timed_wait_without_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
if(!cond_var.timed_wait(lock,timeout))
{
return;
}
}
++woken;
}
void timed_wait_with_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
{
++woken;
}
}
void relative_timed_wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
{
++woken;
}
}
};
#endif

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

@@ -52,7 +52,7 @@ void test_barrier()
throw;
}
BOOST_CHECK(global_parameter == 5);
BOOST_CHECK_EQUAL(global_parameter,5);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// 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)
@@ -19,7 +20,7 @@ struct condition_test_data
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
boost::condition_variable condition;
int notified;
int awoken;
};
@@ -82,66 +83,15 @@ void condition_test_waits(condition_test_data* data)
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_one();
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 1);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one, 100, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
try
{
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_all();
}
threads.join_all();
}
catch(...)
{
threads.interrupt_all();
threads.join_all();
throw;
}
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
}
void test_condition_notify_all()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_notify_all, 100);
// Test predicate timed_wait with relative timeout
cond_predicate pred_rel(data->notified, 5);
BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred_rel());
BOOST_CHECK_EQUAL(data->notified, 5);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_waits()
@@ -185,10 +135,19 @@ void do_test_condition_waits()
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
boost::thread::sleep(delay(1));
data.notified++;
data.condition.notify_one();
while (data.awoken != 5)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 4);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
void test_condition_waits()
@@ -216,14 +175,11 @@ void test_condition_wait_is_a_interruption_point()
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
test->add(BOOST_TEST_CASE(&test_condition_waits));
test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));

View File

@@ -0,0 +1,180 @@
// 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/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
unsigned const number_of_test_threads=5;
void do_test_condition_notify_all_wakes_from_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void test_condition_notify_all()
{
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
return test;
}

View File

@@ -0,0 +1,113 @@
// 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/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
void do_test_condition_notify_one_wakes_from_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
return test;
}

View File

@@ -0,0 +1,89 @@
// 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/detail/config.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include "util.inl"
bool fake_predicate()
{
return false;
}
unsigned const timeout_seconds=5;
unsigned const timeout_grace=1;
boost::posix_time::milliseconds const timeout_resolution(100);
void do_test_timed_wait_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
while(cond.timed_wait(lock,timeout));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_relative_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
bool const res=cond.timed_wait(lock,delay,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void test_timed_wait_times_out()
{
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
return test;
}

View File

@@ -0,0 +1,54 @@
// 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>
#include <boost/thread/mutex.hpp>
void do_nothing()
{}
void test_thread_move_from_lvalue_on_construction()
{
boost::thread src(do_nothing);
boost::thread::id src_id=src.get_id();
boost::thread dest(boost::move(src));
boost::thread::id dest_id=dest.get_id();
BOOST_CHECK(src_id==dest_id);
BOOST_CHECK(src.get_id()==boost::thread::id());
dest.join();
}
void test_thread_move_from_rvalue_on_construction()
{
boost::thread x(boost::move(boost::thread(do_nothing)));
BOOST_CHECK(x.get_id()!=boost::thread::id());
x.join();
}
void test_unique_lock_move_from_lvalue_on_construction()
{
boost::mutex m;
boost::unique_lock<boost::mutex> l(m);
BOOST_CHECK(l.owns_lock());
BOOST_CHECK(l.mutex()==&m);
boost::unique_lock<boost::mutex> l2(boost::move(l));
BOOST_CHECK(!l.owns_lock());
BOOST_CHECK(!l.mutex());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l2.mutex()==&m);
}
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_thread_move_from_lvalue_on_construction));
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
return test;
}

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

View File

@@ -19,6 +19,7 @@ void initialize_variable()
++var_to_init;
}
void call_once_thread()
{
unsigned const loop_count=100;

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::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_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;
}

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// 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)
@@ -73,7 +74,7 @@ void test_tss_thread()
native_thread_t create_native_thread(void)
{
return CreateThread(
native_thread_t const res=CreateThread(
0, //security attributes (0 = not inheritable)
0, //stack size (0 = default)
&test_tss_thread_native, //function to execute
@@ -81,6 +82,8 @@ void test_tss_thread()
0, //creation flags (0 = run immediately)
0 //thread id (0 = thread id not returned)
);
BOOST_CHECK(res!=0);
return res;
}
void join_native_thread(native_thread_t thread)
@@ -154,19 +157,10 @@ void do_test_tss()
tss_total = 0;
native_thread_t thread1 = create_native_thread();
BOOST_CHECK(thread1 != 0);
native_thread_t thread2 = create_native_thread();
BOOST_CHECK(thread2 != 0);
native_thread_t thread3 = create_native_thread();
BOOST_CHECK(thread3 != 0);
native_thread_t thread4 = create_native_thread();
BOOST_CHECK(thread3 != 0);
native_thread_t thread5 = create_native_thread();
BOOST_CHECK(thread3 != 0);
join_native_thread(thread5);
join_native_thread(thread4);

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// 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)
@@ -154,6 +155,26 @@ thread_binder<F, T> bind(const F& func, const T& param)
{
return thread_binder<F, T>(func, param);
}
template <typename R, typename T>
class thread_member_binder
{
public:
thread_member_binder(R (T::*func)(), T& param)
: func(func), param(param) { }
void operator()() const { (param.*func)(); }
private:
R (T::*func)();
T& param;
};
template <typename R, typename T>
thread_member_binder<R, T> bind(R (T::*func)(), T& param)
{
return thread_member_binder<R, T>(func, param);
}
} // namespace
#endif