mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
23 Commits
boost-1.36
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
870d154ca1 | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 |
@@ -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
|
||||
;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ]
|
||||
;
|
||||
}
|
||||
|
||||
95
test/condition_test_common.hpp
Normal file
95
test/condition_test_common.hpp
Normal 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
|
||||
62
test/shared_mutex_locking_thread.hpp
Normal file
62
test/shared_mutex_locking_thread.hpp
Normal 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
|
||||
@@ -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*[])
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
180
test/test_condition_notify_all.cpp
Normal file
180
test/test_condition_notify_all.cpp
Normal 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;
|
||||
}
|
||||
113
test/test_condition_notify_one.cpp
Normal file
113
test/test_condition_notify_one.cpp
Normal 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;
|
||||
}
|
||||
89
test/test_condition_timed_wait_times_out.cpp
Normal file
89
test/test_condition_timed_wait_times_out.cpp
Normal 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;
|
||||
}
|
||||
54
test/test_move_function.cpp
Normal file
54
test/test_move_function.cpp
Normal 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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -19,6 +19,7 @@ void initialize_variable()
|
||||
++var_to_init;
|
||||
}
|
||||
|
||||
|
||||
void call_once_thread()
|
||||
{
|
||||
unsigned const loop_count=100;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
271
test/test_shared_mutex_part_2.cpp
Normal file
271
test/test_shared_mutex_part_2.cpp
Normal 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
37
test/test_thread_move.cpp
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user