mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 21:52:07 +00:00
Compare commits
52 Commits
boost-1.35
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
127b76747c | ||
|
|
f76037dd12 | ||
|
|
6e1a866b13 | ||
|
|
f91986ad0d | ||
|
|
795cc23f3e | ||
|
|
a3695bd4a0 | ||
|
|
08dc521daf | ||
|
|
8b916d21b1 | ||
|
|
c40f47a78a | ||
|
|
e9fb470b06 | ||
|
|
343d049772 | ||
|
|
86f9480da4 | ||
|
|
8696b610ca | ||
|
|
6f13227eda | ||
|
|
58d5110e61 | ||
|
|
76e53c7bc5 | ||
|
|
cfb08be1a8 | ||
|
|
b5bbb7fb1c | ||
|
|
a76c33f8cc | ||
|
|
810306b8f3 | ||
|
|
6c22bdb3bd | ||
|
|
6a0d3e98bc | ||
|
|
3809321037 | ||
|
|
eef695bdf0 | ||
|
|
ab01ab1e4d | ||
|
|
c8d8a108a7 | ||
|
|
7afd9efcc5 | ||
|
|
56ded87ad2 | ||
|
|
82e503339b | ||
|
|
713d0c7ace | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 |
@@ -44,6 +44,8 @@ functions.
|
||||
but did not lock it on construction. This facility has now been replaced with the constructor that takes a
|
||||
`boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);``
|
||||
|
||||
* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__.
|
||||
|
||||
* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__.
|
||||
|
||||
|
||||
|
||||
@@ -46,11 +46,16 @@ private:
|
||||
|
||||
bounded_buffer buf(2);
|
||||
|
||||
boost::mutex io_mutex;
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
@@ -60,7 +65,10 @@ void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
std::cout << "received: " << n << std::endl;
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// (C) Copyright 2008 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)
|
||||
@@ -10,12 +11,15 @@
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
|
||||
extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
|
||||
//Function to be called just be fore a thread ends
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
|
||||
@@ -400,13 +400,16 @@ namespace boost
|
||||
{
|
||||
lock();
|
||||
}
|
||||
upgrade_lock(Mutex& m_,bool do_lock):
|
||||
upgrade_lock(Mutex& m_,adopt_lock_t):
|
||||
m(&m_),is_locked(true)
|
||||
{}
|
||||
upgrade_lock(Mutex& m_,defer_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{}
|
||||
upgrade_lock(Mutex& m_,try_to_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
if(do_lock)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
try_lock();
|
||||
}
|
||||
upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
|
||||
@@ -58,6 +58,12 @@ namespace boost
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
typedef pthread_cond_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &cond;
|
||||
}
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
};
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace boost
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
return !res;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -118,6 +118,12 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
@@ -196,6 +202,12 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
@@ -271,6 +283,12 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_upgrade(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "thread_data.hpp"
|
||||
#include <boost/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -139,6 +140,12 @@ namespace boost
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info() const;
|
||||
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F f)
|
||||
{
|
||||
return detail::thread_data_ptr(new thread_data<F>(f));
|
||||
}
|
||||
|
||||
public:
|
||||
thread();
|
||||
@@ -146,13 +153,32 @@ namespace boost
|
||||
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(new thread_data<F>(f))
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(detail::thread_move_t<F> f):
|
||||
thread_info(new thread_data<F>(f))
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1>
|
||||
thread(F f,A1 a1):
|
||||
thread_info(make_thread_info(boost::bind<void>(f,a1)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F,class A1,class A2>
|
||||
thread(F f,A1 a1,A2 a2):
|
||||
thread_info(make_thread_info(boost::bind<void>(f,a1,a2)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F,class A1,class A2,class A3>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3):
|
||||
thread_info(make_thread_info(boost::bind<void>(f,a1,a2,a3)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
@@ -188,6 +214,9 @@ namespace boost
|
||||
static void sleep(const system_time& xt);
|
||||
static void yield();
|
||||
|
||||
typedef pthread_t native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
// extensions
|
||||
void interrupt();
|
||||
bool interruption_requested() const;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <vector>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -27,72 +29,50 @@ namespace boost
|
||||
|
||||
struct list_entry
|
||||
{
|
||||
detail::win32::handle semaphore;
|
||||
long count;
|
||||
detail::win32::handle_manager semaphore;
|
||||
detail::win32::handle_manager wake_sem;
|
||||
long waiters;
|
||||
bool notified;
|
||||
long references;
|
||||
|
||||
list_entry():
|
||||
semaphore(0),count(0),notified(0)
|
||||
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
|
||||
wake_sem(0),
|
||||
waiters(1),notified(false),references(0)
|
||||
{}
|
||||
|
||||
void release(unsigned count_to_release)
|
||||
{
|
||||
notified=true;
|
||||
detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_add_ref(list_entry * p)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->references);
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_release(list_entry * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_STATIC_CONSTANT(unsigned,generation_count=3);
|
||||
typedef boost::intrusive_ptr<list_entry> entry_ptr;
|
||||
typedef std::vector<entry_ptr> generation_list;
|
||||
|
||||
list_entry generations[generation_count];
|
||||
detail::win32::handle wake_sem;
|
||||
generation_list generations;
|
||||
detail::win32::handle_manager wake_sem;
|
||||
|
||||
static bool no_waiters(list_entry const& entry)
|
||||
void wake_waiters(long count_to_wake)
|
||||
{
|
||||
return entry.count==0;
|
||||
}
|
||||
|
||||
void shift_generations_down()
|
||||
{
|
||||
list_entry* const last_active_entry=std::remove_if(generations,generations+generation_count,no_waiters);
|
||||
if(last_active_entry==generations+generation_count)
|
||||
{
|
||||
broadcast_entry(generations[generation_count-1],false);
|
||||
}
|
||||
else
|
||||
{
|
||||
active_generation_count=unsigned(last_active_entry-generations)+1;
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
std::copy_backward(generations,generations+active_generation_count-1,generations+active_generation_count);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
generations[0]=list_entry();
|
||||
}
|
||||
|
||||
void broadcast_entry(list_entry& entry,bool wake)
|
||||
{
|
||||
long const count_to_wake=entry.count;
|
||||
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
|
||||
if(wake)
|
||||
{
|
||||
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
|
||||
}
|
||||
detail::win32::ReleaseSemaphore(entry.semaphore,count_to_wake,0);
|
||||
entry.count=0;
|
||||
dispose_entry(entry);
|
||||
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
|
||||
}
|
||||
|
||||
|
||||
void dispose_entry(list_entry& entry)
|
||||
{
|
||||
if(entry.semaphore)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::CloseHandle(entry.semaphore));
|
||||
entry.semaphore=0;
|
||||
}
|
||||
entry.notified=false;
|
||||
}
|
||||
|
||||
|
||||
template<typename lock_type>
|
||||
struct relocker
|
||||
{
|
||||
@@ -116,72 +96,79 @@ namespace boost
|
||||
|
||||
}
|
||||
private:
|
||||
relocker(relocker&);
|
||||
void operator=(relocker&);
|
||||
};
|
||||
|
||||
|
||||
template<typename lock_type>
|
||||
void start_wait_loop_first_time(relocker<lock_type>& locker,
|
||||
detail::win32::handle_manager& local_wake_sem)
|
||||
entry_ptr get_wait_entry()
|
||||
{
|
||||
locker.unlock();
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
|
||||
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)
|
||||
|
||||
detail::interlocked_write_release(&total_count,total_count+1);
|
||||
if(generations.empty() || generations.back()->notified)
|
||||
{
|
||||
shift_generations_down();
|
||||
entry_ptr new_entry(new list_entry);
|
||||
new_entry->wake_sem=wake_sem.duplicate();
|
||||
generations.push_back(new_entry);
|
||||
return new_entry;
|
||||
}
|
||||
else if(!active_generation_count)
|
||||
else
|
||||
{
|
||||
active_generation_count=1;
|
||||
BOOST_INTERLOCKED_INCREMENT(&generations.back()->waiters);
|
||||
return generations.back();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
void start_wait_loop(relocker<lock_type>& locker,
|
||||
detail::win32::handle_manager& local_wake_sem,
|
||||
detail::win32::handle_manager& sem)
|
||||
struct entry_manager
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
detail::interlocked_write_release(&total_count,total_count+1);
|
||||
if(!local_wake_sem)
|
||||
entry_ptr const entry;
|
||||
|
||||
entry_manager(entry_ptr const& entry_):
|
||||
entry(entry_)
|
||||
{}
|
||||
|
||||
~entry_manager()
|
||||
{
|
||||
start_wait_loop_first_time(locker,local_wake_sem);
|
||||
BOOST_INTERLOCKED_DECREMENT(&entry->waiters);
|
||||
}
|
||||
if(!generations[0].semaphore)
|
||||
|
||||
list_entry* operator->()
|
||||
{
|
||||
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(generations[0].semaphore);
|
||||
return entry.get();
|
||||
}
|
||||
++generations[0].count;
|
||||
sem=detail::win32::duplicate_handle(generations[0].semaphore);
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(entry_manager&);
|
||||
entry_manager(entry_manager&);
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
template<typename lock_type>
|
||||
bool do_wait(lock_type& lock,timeout wait_until)
|
||||
{
|
||||
detail::win32::handle_manager local_wake_sem;
|
||||
detail::win32::handle_manager sem;
|
||||
bool woken=false;
|
||||
|
||||
relocker<lock_type> locker(lock);
|
||||
|
||||
|
||||
entry_manager entry(get_wait_entry());
|
||||
|
||||
locker.unlock();
|
||||
|
||||
bool woken=false;
|
||||
while(!woken)
|
||||
{
|
||||
start_wait_loop(locker,local_wake_sem,sem);
|
||||
|
||||
if(!this_thread::interruptible_wait(sem,wait_until))
|
||||
if(!this_thread::interruptible_wait(entry->semaphore,wait_until))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(entry->wake_sem,0);
|
||||
BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0);
|
||||
|
||||
woken=(woken_result==0);
|
||||
@@ -202,45 +189,37 @@ namespace boost
|
||||
|
||||
basic_condition_variable(const basic_condition_variable& other);
|
||||
basic_condition_variable& operator=(const basic_condition_variable& other);
|
||||
|
||||
static bool no_waiters(entry_ptr const& entry)
|
||||
{
|
||||
return !detail::interlocked_read_acquire(&entry->waiters);
|
||||
}
|
||||
public:
|
||||
basic_condition_variable():
|
||||
total_count(0),active_generation_count(0),wake_sem(0)
|
||||
{}
|
||||
|
||||
~basic_condition_variable()
|
||||
{
|
||||
for(unsigned i=0;i<generation_count;++i)
|
||||
{
|
||||
dispose_entry(generations[i]);
|
||||
}
|
||||
detail::win32::CloseHandle(wake_sem);
|
||||
}
|
||||
{}
|
||||
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
detail::win32::ReleaseSemaphore(wake_sem,1,0);
|
||||
for(unsigned generation=active_generation_count;generation!=0;--generation)
|
||||
if(!total_count)
|
||||
{
|
||||
list_entry& entry=generations[generation-1];
|
||||
if(entry.count)
|
||||
{
|
||||
detail::interlocked_write_release(&total_count,total_count-1);
|
||||
entry.notified=true;
|
||||
detail::win32::ReleaseSemaphore(entry.semaphore,1,0);
|
||||
if(!--entry.count)
|
||||
{
|
||||
dispose_entry(entry);
|
||||
if(generation==active_generation_count)
|
||||
{
|
||||
--active_generation_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
wake_waiters(1);
|
||||
|
||||
for(generation_list::iterator it=generations.begin(),
|
||||
end=generations.end();
|
||||
it!=end;++it)
|
||||
{
|
||||
(*it)->release(1);
|
||||
}
|
||||
generations.erase(std::remove_if(generations.begin(),generations.end(),no_waiters),generations.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,15 +228,18 @@ namespace boost
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
for(unsigned generation=active_generation_count;generation!=0;--generation)
|
||||
if(!total_count)
|
||||
{
|
||||
list_entry& entry=generations[generation-1];
|
||||
if(entry.count)
|
||||
{
|
||||
broadcast_entry(entry,true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
active_generation_count=0;
|
||||
wake_waiters(total_count);
|
||||
for(generation_list::iterator it=generations.begin(),
|
||||
end=generations.end();
|
||||
it!=end;++it)
|
||||
{
|
||||
(*it)->release(detail::interlocked_read_acquire(&(*it)->waiters));
|
||||
}
|
||||
wake_sem=detail::win32::handle(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,9 +247,18 @@ namespace boost
|
||||
}
|
||||
|
||||
class condition_variable:
|
||||
public detail::basic_condition_variable
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
private:
|
||||
condition_variable(condition_variable&);
|
||||
void operator=(condition_variable&);
|
||||
public:
|
||||
condition_variable()
|
||||
{}
|
||||
|
||||
using detail::basic_condition_variable::notify_one;
|
||||
using detail::basic_condition_variable::notify_all;
|
||||
|
||||
void wait(unique_lock<mutex>& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
@@ -313,9 +304,18 @@ namespace boost
|
||||
};
|
||||
|
||||
class condition_variable_any:
|
||||
public detail::basic_condition_variable
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
private:
|
||||
condition_variable_any(condition_variable_any&);
|
||||
void operator=(condition_variable_any&);
|
||||
public:
|
||||
condition_variable_any()
|
||||
{}
|
||||
|
||||
using detail::basic_condition_variable::notify_one;
|
||||
using detail::basic_condition_variable::notify_all;
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
|
||||
@@ -120,6 +120,12 @@ namespace boost
|
||||
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time const& wait_until)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -269,6 +275,12 @@ namespace boost
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <algorithm>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
|
||||
@@ -184,6 +185,9 @@ namespace boost
|
||||
{
|
||||
f();
|
||||
}
|
||||
private:
|
||||
void operator=(thread_data&);
|
||||
thread_data(thread_data&);
|
||||
};
|
||||
|
||||
mutable boost::mutex thread_info_mutex;
|
||||
@@ -196,19 +200,44 @@ namespace boost
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info() const;
|
||||
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F f)
|
||||
{
|
||||
return detail::heap_new<thread_data<F> >(f);
|
||||
}
|
||||
public:
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(detail::heap_new<thread_data<F> >(f))
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(detail::thread_move_t<F> f):
|
||||
thread_info(detail::heap_new<thread_data<F> >(f))
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1>
|
||||
thread(F f,A1 a1):
|
||||
thread_info(make_thread_info(boost::bind<void>(f,a1)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F,class A1,class A2>
|
||||
thread(F f,A1 a1,A2 a2):
|
||||
thread_info(make_thread_info(boost::bind<void>(f,a1,a2)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F,class A1,class A2,class A3>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3):
|
||||
thread_info(make_thread_info(boost::bind<void>(f,a1,a2,a3)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
@@ -472,6 +472,21 @@ namespace boost
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->thread_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pthread_t();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace this_thread
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && (!defined(_MSC_VER) || defined(UNDER_CE))
|
||||
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
|
||||
|
||||
/*
|
||||
This file is a "null" implementation of tss cleanup; it's
|
||||
|
||||
@@ -38,6 +38,7 @@ rule thread-run ( sources )
|
||||
[ thread-run test_thread_id.cpp ]
|
||||
[ thread-run test_hardware_concurrency.cpp ]
|
||||
[ thread-run test_thread_move.cpp ]
|
||||
[ thread-run test_thread_launching.cpp ]
|
||||
[ thread-run test_move_function.cpp ]
|
||||
[ thread-run test_mutex.cpp ]
|
||||
[ thread-run test_condition_notify_one.cpp ]
|
||||
@@ -50,6 +51,7 @@ rule thread-run ( sources )
|
||||
[ thread-run test_barrier.cpp ]
|
||||
[ thread-run test_shared_mutex.cpp ]
|
||||
[ thread-run test_shared_mutex_part_2.cpp ]
|
||||
[ thread-run test_shared_mutex_timed_locks.cpp ]
|
||||
[ thread-run test_lock_concept.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
@@ -66,5 +66,67 @@ private:
|
||||
void operator=(locking_thread&);
|
||||
};
|
||||
|
||||
class simple_writing_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_writing_thread&);
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
class simple_reading_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_reading_thread&);
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -159,6 +159,47 @@ void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate(
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex multiple_wake_mutex;
|
||||
boost::condition_variable multiple_wake_cond;
|
||||
unsigned multiple_wake_count=0;
|
||||
|
||||
void wait_for_condvar_and_increase_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
multiple_wake_cond.wait(lk);
|
||||
++multiple_wake_count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void do_test_notify_all_following_notify_one_wakes_all_threads()
|
||||
{
|
||||
boost::thread thread1(wait_for_condvar_and_increase_count);
|
||||
boost::thread thread2(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
|
||||
boost::thread thread3(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
multiple_wake_cond.notify_all();
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
BOOST_CHECK(multiple_wake_count==3);
|
||||
}
|
||||
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
thread3.join();
|
||||
}
|
||||
|
||||
void test_condition_notify_all()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
|
||||
@@ -166,6 +207,7 @@ void test_condition_notify_all()
|
||||
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);
|
||||
timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -92,6 +92,47 @@ void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate(
|
||||
BOOST_CHECK(data.woken);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex multiple_wake_mutex;
|
||||
boost::condition_variable multiple_wake_cond;
|
||||
unsigned multiple_wake_count=0;
|
||||
|
||||
void wait_for_condvar_and_increase_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
multiple_wake_cond.wait(lk);
|
||||
++multiple_wake_count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void do_test_multiple_notify_one_calls_wakes_multiple_threads()
|
||||
{
|
||||
boost::thread thread1(wait_for_condvar_and_increase_count);
|
||||
boost::thread thread2(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
|
||||
boost::thread thread3(wait_for_condvar_and_increase_count);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
multiple_wake_cond.notify_one();
|
||||
multiple_wake_cond.notify_one();
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lk(multiple_wake_mutex);
|
||||
BOOST_CHECK(multiple_wake_count==3);
|
||||
}
|
||||
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
thread3.join();
|
||||
}
|
||||
|
||||
void test_condition_notify_one()
|
||||
{
|
||||
timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
|
||||
@@ -99,6 +140,7 @@ void test_condition_notify_one()
|
||||
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);
|
||||
timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -107,40 +107,6 @@ void test_can_lock_upgrade_if_currently_locked_shared()
|
||||
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;
|
||||
|
||||
void operator=(simple_writing_thread&);
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -175,40 +141,6 @@ void test_if_no_thread_has_lock_try_lock_shared_returns_true()
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class simple_reading_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_reading_thread&);
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -232,33 +164,6 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
|
||||
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 =
|
||||
@@ -269,7 +174,6 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
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;
|
||||
}
|
||||
|
||||
235
test/test_shared_mutex_timed_locks.cpp
Normal file
235
test/test_shared_mutex_timed_locks.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
// (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_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(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool 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();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_shared_succeeds_if_no_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout2);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_timed_lock_shared_succeeds_if_read_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 reader(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);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout2);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
reader.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_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(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
|
||||
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_succeeds_if_no_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
|
||||
BOOST_CHECK(boost::get_system_time()<timeout2);
|
||||
BOOST_CHECK(timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_timed_lock_times_out_if_read_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 reader(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);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
|
||||
boost::posix_time::milliseconds const timeout_resolution(50);
|
||||
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
|
||||
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
boost::posix_time::milliseconds const wait_duration(500);
|
||||
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
|
||||
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
|
||||
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
reader.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_timed_lock_shared_times_out_if_write_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held));
|
||||
|
||||
return test;
|
||||
}
|
||||
165
test/test_thread_launching.cpp
Normal file
165
test/test_thread_launching.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
// 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/ref.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
bool normal_function_called=false;
|
||||
|
||||
void normal_function()
|
||||
{
|
||||
normal_function_called=true;
|
||||
}
|
||||
|
||||
void test_thread_function_no_arguments()
|
||||
{
|
||||
boost::thread function(normal_function);
|
||||
function.join();
|
||||
BOOST_CHECK(normal_function_called);
|
||||
}
|
||||
|
||||
struct callable_no_args
|
||||
{
|
||||
static bool called;
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
called=true;
|
||||
}
|
||||
};
|
||||
|
||||
bool callable_no_args::called=false;
|
||||
|
||||
void test_thread_callable_object_no_arguments()
|
||||
{
|
||||
callable_no_args func;
|
||||
boost::thread callable(func);
|
||||
callable.join();
|
||||
BOOST_CHECK(callable_no_args::called);
|
||||
}
|
||||
|
||||
struct callable_noncopyable_no_args:
|
||||
boost::noncopyable
|
||||
{
|
||||
static bool called;
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
called=true;
|
||||
}
|
||||
};
|
||||
|
||||
bool callable_noncopyable_no_args::called=false;
|
||||
|
||||
void test_thread_callable_object_ref_no_arguments()
|
||||
{
|
||||
callable_noncopyable_no_args func;
|
||||
|
||||
boost::thread callable(boost::ref(func));
|
||||
callable.join();
|
||||
BOOST_CHECK(callable_noncopyable_no_args::called);
|
||||
}
|
||||
|
||||
struct callable_one_arg
|
||||
{
|
||||
static bool called;
|
||||
static int called_arg;
|
||||
|
||||
void operator()(int arg) const
|
||||
{
|
||||
called=true;
|
||||
called_arg=arg;
|
||||
}
|
||||
};
|
||||
|
||||
bool callable_one_arg::called=false;
|
||||
int callable_one_arg::called_arg=0;
|
||||
|
||||
void test_thread_callable_object_one_argument()
|
||||
{
|
||||
boost::thread callable(callable_one_arg(),42);
|
||||
callable.join();
|
||||
BOOST_CHECK(callable_one_arg::called);
|
||||
BOOST_CHECK_EQUAL(callable_one_arg::called_arg,42);
|
||||
}
|
||||
|
||||
struct callable_multiple_arg
|
||||
{
|
||||
static bool called_two;
|
||||
static int called_two_arg1;
|
||||
static double called_two_arg2;
|
||||
static bool called_three;
|
||||
static std::string called_three_arg1;
|
||||
static std::vector<int> called_three_arg2;
|
||||
static int called_three_arg3;
|
||||
|
||||
void operator()(int arg1,double arg2) const
|
||||
{
|
||||
called_two=true;
|
||||
called_two_arg1=arg1;
|
||||
called_two_arg2=arg2;
|
||||
}
|
||||
void operator()(std::string const& arg1,std::vector<int> const& arg2,int arg3) const
|
||||
{
|
||||
called_three=true;
|
||||
called_three_arg1=arg1;
|
||||
called_three_arg2=arg2;
|
||||
called_three_arg3=arg3;
|
||||
}
|
||||
};
|
||||
|
||||
bool callable_multiple_arg::called_two=false;
|
||||
bool callable_multiple_arg::called_three=false;
|
||||
int callable_multiple_arg::called_two_arg1;
|
||||
double callable_multiple_arg::called_two_arg2;
|
||||
std::string callable_multiple_arg::called_three_arg1;
|
||||
std::vector<int> callable_multiple_arg::called_three_arg2;
|
||||
int callable_multiple_arg::called_three_arg3;
|
||||
|
||||
void test_thread_callable_object_multiple_arguments()
|
||||
{
|
||||
std::vector<int> x;
|
||||
for(unsigned i=0;i<7;++i)
|
||||
{
|
||||
x.push_back(i*i);
|
||||
}
|
||||
|
||||
boost::thread callable3(callable_multiple_arg(),"hello",x,1.2);
|
||||
callable3.join();
|
||||
BOOST_CHECK(callable_multiple_arg::called_three);
|
||||
BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg1,"hello");
|
||||
BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.size(),x.size());
|
||||
for(unsigned j=0;j<x.size();++j)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.at(j),x[j]);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg3,1);
|
||||
|
||||
double const dbl=1.234;
|
||||
|
||||
boost::thread callable2(callable_multiple_arg(),19,dbl);
|
||||
callable2.join();
|
||||
BOOST_CHECK(callable_multiple_arg::called_two);
|
||||
BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg1,19);
|
||||
BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg2,dbl);
|
||||
}
|
||||
|
||||
|
||||
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 launching test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_function_no_arguments));
|
||||
test->add(BOOST_TEST_CASE(test_thread_callable_object_no_arguments));
|
||||
test->add(BOOST_TEST_CASE(test_thread_callable_object_ref_no_arguments));
|
||||
test->add(BOOST_TEST_CASE(test_thread_callable_object_one_argument));
|
||||
test->add(BOOST_TEST_CASE(test_thread_callable_object_multiple_arguments));
|
||||
return test;
|
||||
}
|
||||
Reference in New Issue
Block a user