|
Boost-Commit : |
From: troy_at_[hidden]
Date: 2008-06-29 11:50:45
Author: troy
Date: 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
New Revision: 46864
URL: http://svn.boost.org/trac/boost/changeset/46864
Log:
merge from release branch
Added:
branches/CMake/release/libs/thread/doc/time.qbk
- copied unchanged from r46809, /branches/release/libs/thread/doc/time.qbk
branches/CMake/release/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp
- copied unchanged from r46809, /branches/release/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp
branches/CMake/release/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp
- copied unchanged from r46809, /branches/release/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp
branches/CMake/release/libs/thread/test/test_generic_locks.cpp
- copied unchanged from r46809, /branches/release/libs/thread/test/test_generic_locks.cpp
branches/CMake/release/libs/thread/test/test_shared_mutex_timed_locks.cpp
- copied unchanged from r46809, /branches/release/libs/thread/test/test_shared_mutex_timed_locks.cpp
branches/CMake/release/libs/thread/test/test_thread_launching.cpp
- copied unchanged from r46809, /branches/release/libs/thread/test/test_thread_launching.cpp
branches/CMake/release/libs/thread/test/test_thread_mf.cpp
- copied unchanged from r46809, /branches/release/libs/thread/test/test_thread_mf.cpp
Text files modified:
branches/CMake/release/libs/thread/doc/changes.qbk | 7
branches/CMake/release/libs/thread/doc/mutex_concepts.qbk | 30 ++++
branches/CMake/release/libs/thread/doc/mutexes.qbk | 77 ++++++++++
branches/CMake/release/libs/thread/doc/thread.qbk | 2
branches/CMake/release/libs/thread/doc/thread_ref.qbk | 77 +++++++++
branches/CMake/release/libs/thread/example/condition.cpp | 12 +
branches/CMake/release/libs/thread/src/pthread/thread.cpp | 299 ++++++++++++++++++---------------------
branches/CMake/release/libs/thread/src/tss_null.cpp | 2
branches/CMake/release/libs/thread/src/win32/thread.cpp | 86 ++--------
branches/CMake/release/libs/thread/test/CMakeLists.txt | 37 +++-
branches/CMake/release/libs/thread/test/Jamfile.v2 | 20 +
branches/CMake/release/libs/thread/test/shared_mutex_locking_thread.hpp | 62 ++++++++
branches/CMake/release/libs/thread/test/test_condition_notify_all.cpp | 42 +++++
branches/CMake/release/libs/thread/test/test_condition_notify_one.cpp | 42 +++++
branches/CMake/release/libs/thread/test/test_lock_concept.cpp | 106 ++++++++++++++
branches/CMake/release/libs/thread/test/test_move_function.cpp | 74 +++++++++
branches/CMake/release/libs/thread/test/test_shared_mutex_part_2.cpp | 96 ------------
branches/CMake/release/libs/thread/test/test_thread.cpp | 18 ++
branches/CMake/release/libs/thread/test/test_tss.cpp | 48 ++++++
19 files changed, 791 insertions(+), 346 deletions(-)
Modified: branches/CMake/release/libs/thread/doc/changes.qbk
==============================================================================
--- branches/CMake/release/libs/thread/doc/changes.qbk (original)
+++ branches/CMake/release/libs/thread/doc/changes.qbk 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -44,7 +44,14 @@
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__.
+
+* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not
+associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has
+been moved to __thread_id__.
+
* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__.
+* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
[endsect]
Modified: branches/CMake/release/libs/thread/doc/mutex_concepts.qbk
==============================================================================
--- branches/CMake/release/libs/thread/doc/mutex_concepts.qbk (original)
+++ branches/CMake/release/libs/thread/doc/mutex_concepts.qbk 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -373,6 +373,7 @@
class unique_lock
{
public:
+ unique_lock();
explicit unique_lock(Lockable& m_);
unique_lock(Lockable& m_,adopt_lock_t);
unique_lock(Lockable& m_,defer_lock_t);
@@ -426,6 +427,20 @@
__lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock state
(including the destructor) must be called by the same thread that acquired ownership of the lock state.
+[section:defaultconstructor `unique_lock()`]
+
+[variablelist
+
+[[Effects:] [Creates a lock object with no associated mutex.]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
[section:constructor `unique_lock(Lockable & m)`]
[variablelist
@@ -599,6 +614,7 @@
class shared_lock
{
public:
+ shared_lock();
explicit shared_lock(Lockable& m_);
shared_lock(Lockable& m_,adopt_lock_t);
shared_lock(Lockable& m_,defer_lock_t);
@@ -644,6 +660,20 @@
ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock
state (including the destructor) must be called by the same thread that acquired ownership of the lock state.
+[section:defaultconstructor `shared_lock()`]
+
+[variablelist
+
+[[Effects:] [Creates a lock object with no associated mutex.]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
[section:constructor `shared_lock(Lockable & m)`]
[variablelist
Modified: branches/CMake/release/libs/thread/doc/mutexes.qbk
==============================================================================
--- branches/CMake/release/libs/thread/doc/mutexes.qbk (original)
+++ branches/CMake/release/libs/thread/doc/mutexes.qbk 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -12,6 +12,9 @@
void lock();
bool try_lock();
void unlock();
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
typedef unique_lock<mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
@@ -20,6 +23,23 @@
__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given
instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted.
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+
[endsect]
[section:try_mutex Typedef `try_mutex`]
@@ -47,6 +67,9 @@
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef scoped_timed_lock scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
@@ -56,6 +79,22 @@
lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__,
__timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted.
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
[endsect]
[section:recursive_mutex Class `recursive_mutex`]
@@ -70,6 +109,9 @@
void lock();
bool try_lock();
void unlock();
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
typedef unique_lock<recursive_mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
@@ -81,6 +123,22 @@
__lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for
each level of ownership acquired by a single thread before ownership can be acquired by another thread.
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
[endsect]
[section:recursive_try_mutex Typedef `recursive_try_mutex`]
@@ -108,6 +166,9 @@
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
typedef unique_lock<recursive_timed_mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
@@ -121,6 +182,22 @@
__timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be
called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
[endsect]
[include shared_mutex_ref.qbk]
Modified: branches/CMake/release/libs/thread/doc/thread.qbk
==============================================================================
--- branches/CMake/release/libs/thread/doc/thread.qbk (original)
+++ branches/CMake/release/libs/thread/doc/thread.qbk 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -147,4 +147,6 @@
[include tss.qbk]
+[include time.qbk]
+
[include acknowledgements.qbk]
Modified: branches/CMake/release/libs/thread/doc/thread_ref.qbk
==============================================================================
--- branches/CMake/release/libs/thread/doc/thread_ref.qbk (original)
+++ branches/CMake/release/libs/thread/doc/thread_ref.qbk 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -17,6 +17,13 @@
some_thread.join();
}
+[Note: On compilers that support rvalue references, __thread__ provides a proper move constructor and move-assignment operator, and
+therefore meets the C++0x ['MoveConstructible] and ['MoveAssignable] concepts. With such compilers, __thread__ can therefore be used
+with containers that support those concepts.
+
+For other compilers, move support is provided with a move emulation layer, so containers must explicitly detect that move emulation
+layer. See <boost/thread/detail/move.hpp> for details.]
+
[heading Launching threads]
A new thread is launched by passing an object of a callable type that can be invoked with no parameters to the constructor. The
@@ -43,11 +50,21 @@
// this leads to undefined behaviour
If you wish to construct an instance of __thread__ with a function or callable object that requires arguments to be supplied,
-this can be done using `boost::bind`:
+this can be done by passing additional arguments to the __thread__ constructor:
void find_the_question(int the_answer);
- boost::thread deep_thought_2(boost::bind(find_the_question,42));
+ boost::thread deep_thought_2(find_the_question,42);
+
+The arguments are ['copied] into the internal thread structure: if a reference is required, use `boost::ref`, just as for references
+to callable functions.
+
+There is an unspecified limit on the number of additional arguments that can be passed.
+
+[heading Exceptions in thread functions]
+
+If the function or callable object passed to the __thread__ constructor propagates an exception when invoked that is not of type
+__thread_interrupted__, `std::terminate()` is called.
[heading Joining and detaching]
@@ -189,6 +206,8 @@
static void sleep(const system_time& xt);
};
+ void swap(thread& lhs,thread& rhs);
+
[section:default_constructor Default Constructor]
thread();
@@ -212,7 +231,9 @@
[[Preconditions:] [`Callable` must by copyable.]]
-[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created thread of execution.]]
+[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
+thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
+not of type __thread_interrupted__, then `std::terminate()` will be called.]]
[[Postconditions:] [`*this` refers to the newly created thread of execution.]]
@@ -306,7 +327,7 @@
[variablelist
-[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and longer has an associated __thread__ object.]]
+[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and no longer has an associated __thread__ object.]]
[[Postconditions:] [`*this` no longer refers to any thread of execution.]]
@@ -364,6 +385,22 @@
[endsect]
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
[section:equals `operator==`]
bool operator==(const thread& other) const;
@@ -416,6 +453,36 @@
[endsect]
+[section:swap Member function `swap()`]
+
+ void swap(thread& other);
+
+[variablelist
+
+[[Effects:] [Exchanges the threads of execution associated with `*this` and `other`, so `*this` is associated with the thread of
+execution associated with `other` prior to the call, and vice-versa.]]
+
+[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()` prior to the call. `other.get_id()` returns the same
+value as `this->get_id()` prior to the call.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:non_member_swap Non-member function `swap()`]
+
+ void swap(thread& lhs,thread& rhs);
+
+[variablelist
+
+[[Effects:] [[link thread.thread_management.thread.swap `lhs.swap(rhs)`].]]
+
+]
+
+[endsect]
+
[section:id Class `boost::thread::id`]
@@ -471,7 +538,7 @@
[variablelist
-[[Returns:] [`true` if `*this` and `y` represent the different threads of execution, or one represents a thread of execution, and
+[[Returns:] [`true` if `*this` and `y` represent different threads of execution, or one represents a thread of execution, and
the other represent __not_a_thread__, `false` otherwise.]]
[[Throws:] [Nothing]]
Modified: branches/CMake/release/libs/thread/example/condition.cpp
==============================================================================
--- branches/CMake/release/libs/thread/example/condition.cpp (original)
+++ branches/CMake/release/libs/thread/example/condition.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -46,11 +46,16 @@
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 @@
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
}
Modified: branches/CMake/release/libs/thread/src/pthread/thread.cpp
==============================================================================
--- branches/CMake/release/libs/thread/src/pthread/thread.cpp (original)
+++ branches/CMake/release/libs/thread/src/pthread/thread.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -1,6 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
-// Copyright (C) 2007 Anthony Williams
+// Copyright (C) 2007-8 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)
@@ -18,7 +18,7 @@
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/sysctl.h>
-#elif defined(__sun)
+#elif defined(__sun) || defined(__CYGWIN__)
#include <unistd.h>
#endif
@@ -28,6 +28,9 @@
{
namespace detail
{
+ thread_data_base::~thread_data_base()
+ {}
+
struct thread_exit_callback_node
{
boost::detail::thread_exit_function_base* func;
@@ -119,7 +122,7 @@
{
void* thread_proxy(void* param)
{
- boost::shared_ptr<boost::detail::thread_data_base> thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
+ boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
thread_info->self.reset();
detail::set_current_thread_data(thread_info.get());
try
@@ -153,6 +156,10 @@
void run()
{}
+
+ private:
+ externally_launched_thread(externally_launched_thread&);
+ void operator=(externally_launched_thread&);
};
detail::thread_data_base* make_external_thread_data()
@@ -196,47 +203,6 @@
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();
- }
-
- bool thread::operator!=(const thread& other) const
- {
- return !operator==(other);
- }
-
detail::thread_data_ptr thread::get_thread_info() const
{
lock_guard<mutex> l(thread_info_mutex);
@@ -361,57 +327,61 @@
}
}
- void thread::sleep(const system_time& st)
+ namespace this_thread
{
- detail::thread_data_base* const thread_info=detail::get_current_thread_data();
- if(thread_info)
- {
- unique_lock<mutex> lk(thread_info->sleep_mutex);
- while(thread_info->sleep_condition.timed_wait(lk,st));
- }
- else
+ void sleep(const system_time& st)
{
- xtime const xt=get_xtime(st);
-
- for (int foo=0; foo < 5; ++foo)
+ detail::thread_data_base* const thread_info=detail::get_current_thread_data();
+
+ if(thread_info)
+ {
+ unique_lock<mutex> lk(thread_info->sleep_mutex);
+ while(thread_info->sleep_condition.timed_wait(lk,st));
+ }
+ else
{
+ xtime const xt=get_xtime(st);
+
+ for (int foo=0; foo < 5; ++foo)
+ {
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
- timespec ts;
- to_timespec_duration(xt, ts);
- BOOST_VERIFY(!pthread_delay_np(&ts));
+ timespec ts;
+ to_timespec_duration(xt, ts);
+ BOOST_VERIFY(!pthread_delay_np(&ts));
# elif defined(BOOST_HAS_NANOSLEEP)
- timespec ts;
- to_timespec_duration(xt, ts);
+ timespec ts;
+ to_timespec_duration(xt, ts);
- // nanosleep takes a timespec that is an offset, not
- // an absolute time.
- nanosleep(&ts, 0);
+ // nanosleep takes a timespec that is an offset, not
+ // an absolute time.
+ nanosleep(&ts, 0);
# else
- mutex mx;
- mutex::scoped_lock lock(mx);
- condition cond;
- cond.timed_wait(lock, xt);
+ mutex mx;
+ mutex::scoped_lock lock(mx);
+ condition cond;
+ cond.timed_wait(lock, xt);
# endif
- xtime cur;
- xtime_get(&cur, TIME_UTC);
- if (xtime_cmp(xt, cur) <= 0)
- return;
+ xtime cur;
+ xtime_get(&cur, TIME_UTC);
+ if (xtime_cmp(xt, cur) <= 0)
+ return;
+ }
}
}
- }
- void thread::yield()
- {
+ void yield()
+ {
# if defined(BOOST_HAS_SCHED_YIELD)
- BOOST_VERIFY(!sched_yield());
+ BOOST_VERIFY(!sched_yield());
# elif defined(BOOST_HAS_PTHREAD_YIELD)
- BOOST_VERIFY(!pthread_yield());
+ BOOST_VERIFY(!pthread_yield());
# else
- xtime xt;
- xtime_get(&xt, TIME_UTC);
- sleep(xt);
+ xtime xt;
+ xtime_get(&xt, TIME_UTC);
+ sleep(xt);
# endif
+ }
}
unsigned thread::hardware_concurrency()
@@ -424,7 +394,7 @@
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
-#elif defined(__sun)
+#elif defined(__sun) || defined(__CYGWIN__)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#else
@@ -472,6 +442,21 @@
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
@@ -607,85 +592,85 @@
}
}
- thread_group::thread_group()
- {
- }
-
- thread_group::~thread_group()
- {
- // We shouldn't have to scoped_lock here, since referencing this object
- // from another thread while we're deleting it in the current thread is
- // going to lead to undefined behavior any way.
- for (std::list<thread*>::iterator it = m_threads.begin();
- it != m_threads.end(); ++it)
- {
- delete (*it);
- }
- }
-
- thread* thread_group::create_thread(const function0<void>& threadfunc)
- {
- // No scoped_lock required here since the only "shared data" that's
- // modified here occurs inside add_thread which does scoped_lock.
- std::auto_ptr<thread> thrd(new thread(threadfunc));
- add_thread(thrd.get());
- return thrd.release();
- }
-
- void thread_group::add_thread(thread* thrd)
- {
- mutex::scoped_lock scoped_lock(m_mutex);
-
- // For now we'll simply ignore requests to add a thread object multiple
- // times. Should we consider this an error and either throw or return an
- // error value?
- std::list<thread*>::iterator it = std::find(m_threads.begin(),
- m_threads.end(), thrd);
- BOOST_ASSERT(it == m_threads.end());
- if (it == m_threads.end())
- m_threads.push_back(thrd);
- }
-
- void thread_group::remove_thread(thread* thrd)
- {
- mutex::scoped_lock scoped_lock(m_mutex);
-
- // For now we'll simply ignore requests to remove a thread object that's
- // not in the group. Should we consider this an error and either throw or
- // return an error value?
- std::list<thread*>::iterator it = std::find(m_threads.begin(),
- m_threads.end(), thrd);
- BOOST_ASSERT(it != m_threads.end());
- if (it != m_threads.end())
- m_threads.erase(it);
- }
-
- void thread_group::join_all()
- {
- mutex::scoped_lock scoped_lock(m_mutex);
- for (std::list<thread*>::iterator it = m_threads.begin();
- it != m_threads.end(); ++it)
- {
- (*it)->join();
- }
- }
-
- void thread_group::interrupt_all()
- {
- boost::lock_guard<mutex> guard(m_mutex);
+// thread_group::thread_group()
+// {
+// }
+
+// thread_group::~thread_group()
+// {
+// // We shouldn't have to scoped_lock here, since referencing this object
+// // from another thread while we're deleting it in the current thread is
+// // going to lead to undefined behavior any way.
+// for (std::list<thread*>::iterator it = m_threads.begin();
+// it != m_threads.end(); ++it)
+// {
+// delete (*it);
+// }
+// }
+
+// thread* thread_group::create_thread(const function0<void>& threadfunc)
+// {
+// // No scoped_lock required here since the only "shared data" that's
+// // modified here occurs inside add_thread which does scoped_lock.
+// std::auto_ptr<thread> thrd(new thread(threadfunc));
+// add_thread(thrd.get());
+// return thrd.release();
+// }
+
+// void thread_group::add_thread(thread* thrd)
+// {
+// mutex::scoped_lock scoped_lock(m_mutex);
+
+// // For now we'll simply ignore requests to add a thread object multiple
+// // times. Should we consider this an error and either throw or return an
+// // error value?
+// std::list<thread*>::iterator it = std::find(m_threads.begin(),
+// m_threads.end(), thrd);
+// BOOST_ASSERT(it == m_threads.end());
+// if (it == m_threads.end())
+// m_threads.push_back(thrd);
+// }
+
+// void thread_group::remove_thread(thread* thrd)
+// {
+// mutex::scoped_lock scoped_lock(m_mutex);
+
+// // For now we'll simply ignore requests to remove a thread object that's
+// // not in the group. Should we consider this an error and either throw or
+// // return an error value?
+// std::list<thread*>::iterator it = std::find(m_threads.begin(),
+// m_threads.end(), thrd);
+// BOOST_ASSERT(it != m_threads.end());
+// if (it != m_threads.end())
+// m_threads.erase(it);
+// }
+
+// void thread_group::join_all()
+// {
+// mutex::scoped_lock scoped_lock(m_mutex);
+// for (std::list<thread*>::iterator it = m_threads.begin();
+// it != m_threads.end(); ++it)
+// {
+// (*it)->join();
+// }
+// }
+
+// void thread_group::interrupt_all()
+// {
+// boost::lock_guard<mutex> guard(m_mutex);
- for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
- it!=end;
- ++it)
- {
- (*it)->interrupt();
- }
- }
+// for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
+// it!=end;
+// ++it)
+// {
+// (*it)->interrupt();
+// }
+// }
- size_t thread_group::size() const
- {
- return m_threads.size();
- }
+// size_t thread_group::size() const
+// {
+// return m_threads.size();
+// }
}
Modified: branches/CMake/release/libs/thread/src/tss_null.cpp
==============================================================================
--- branches/CMake/release/libs/thread/src/tss_null.cpp (original)
+++ branches/CMake/release/libs/thread/src/tss_null.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -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
Modified: branches/CMake/release/libs/thread/src/win32/thread.cpp
==============================================================================
--- branches/CMake/release/libs/thread/src/win32/thread.cpp (original)
+++ branches/CMake/release/libs/thread/src/win32/thread.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -81,25 +81,6 @@
}
- void thread::yield()
- {
- this_thread::yield();
- }
-
- void thread::sleep(const system_time& target)
- {
- system_time const now(get_system_time());
-
- if(target<=now)
- {
- this_thread::yield();
- }
- else
- {
- this_thread::sleep(target-now);
- }
- }
-
namespace detail
{
struct thread_exit_callback_node
@@ -164,26 +145,24 @@
set_current_thread_data(0);
}
- }
-
-
- unsigned __stdcall thread::thread_start_function(void* param)
- {
- detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
- set_current_thread_data(thread_info);
- try
+ unsigned __stdcall thread_start_function(void* param)
{
- thread_info->run();
- }
- catch(thread_interrupted const&)
- {
- }
- catch(...)
- {
- std::terminate();
+ detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
+ set_current_thread_data(thread_info);
+ try
+ {
+ thread_info->run();
+ }
+ catch(thread_interrupted const&)
+ {
+ }
+ catch(...)
+ {
+ std::terminate();
+ }
+ run_thread_exit_callbacks();
+ return 0;
}
- run_thread_exit_callbacks();
- return 0;
}
thread::thread()
@@ -218,6 +197,9 @@
void run()
{}
+ private:
+ externally_launched_thread(externally_launched_thread&);
+ void operator=(externally_launched_thread&);
};
void make_external_thread_data()
@@ -244,36 +226,6 @@
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=0;
- }
-
- 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);
- }
-
thread::id thread::get_id() const
{
return thread::id(get_thread_info());
Modified: branches/CMake/release/libs/thread/test/CMakeLists.txt
==============================================================================
--- branches/CMake/release/libs/thread/test/CMakeLists.txt (original)
+++ branches/CMake/release/libs/thread/test/CMakeLists.txt 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -1,8 +1,29 @@
-boost_test_run(test_thread MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-boost_test_run(test_mutex MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-boost_test_run(test_condition MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-boost_test_run(test_tss MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-boost_test_run(test_once MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-boost_test_run(test_xtime MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-boost_test_run(test_barrier MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
-#boost_test_run(test_read_write_mutex DEPENDS boost_thread-static boost_unit_test_framework)
+set(TESTS
+test_thread
+test_thread_id
+test_hardware_concurrency
+test_thread_move
+test_thread_launching
+test_thread_mf
+test_move_function
+test_mutex
+test_condition_notify_one
+test_condition_timed_wait_times_out
+test_condition_notify_all
+test_condition
+test_tss
+test_once
+test_xtime
+test_barrier
+test_shared_mutex
+test_shared_mutex_part_2
+test_shared_mutex_timed_locks
+test_lock_concept
+test_generic_locks)
+
+foreach (TEST ${TESTS})
+ boost_test_run(${TEST} MULTI_THREADED DEPENDS boost_thread boost_unit_test_framework)
+endforeach (TEST ${TESTS})
+
+boost_test_compile_fail(no_implicit_move_from_lvalue_thread)
+boost_test_compile_fail(no_implicit_assign_from_lvalue_thread)
Modified: branches/CMake/release/libs/thread/test/Jamfile.v2
==============================================================================
--- branches/CMake/release/libs/thread/test/Jamfile.v2 (original)
+++ branches/CMake/release/libs/thread/test/Jamfile.v2 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -22,22 +22,24 @@
: requirements <library>/boost/test//boost_unit_test_framework/<link>static
<threading>multi
;
-
+
rule thread-run ( sources )
{
return
- [ run $(sources) ../build//boost_thread ]
- [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
- : : : : $(sources[1]:B)_lib ]
- ;
+ [ run $(sources) ../build//boost_thread ]
+ [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
+ : : : : $(sources[1]:B)_lib ]
+ ;
}
-
+
{
test-suite "threads"
: [ thread-run test_thread.cpp ]
[ 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_thread_mf.cpp ]
[ thread-run test_move_function.cpp ]
[ thread-run test_mutex.cpp ]
[ thread-run test_condition_notify_one.cpp ]
@@ -47,9 +49,13 @@
[ thread-run test_tss.cpp ]
[ thread-run test_once.cpp ]
[ thread-run test_xtime.cpp ]
- [ thread-run test_barrier.cpp ]
+ [ 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 ]
+ [ thread-run test_generic_locks.cpp ]
+ [ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
+ [ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
;
}
Modified: branches/CMake/release/libs/thread/test/shared_mutex_locking_thread.hpp
==============================================================================
--- branches/CMake/release/libs/thread/test/shared_mutex_locking_thread.hpp (original)
+++ branches/CMake/release/libs/thread/test/shared_mutex_locking_thread.hpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -66,5 +66,67 @@
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
Modified: branches/CMake/release/libs/thread/test/test_condition_notify_all.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_condition_notify_all.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_condition_notify_all.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -159,6 +159,47 @@
}
}
+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 @@
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);
}
Modified: branches/CMake/release/libs/thread/test/test_condition_notify_one.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_condition_notify_one.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_condition_notify_one.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -92,6 +92,47 @@
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 @@
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);
}
Modified: branches/CMake/release/libs/thread/test/test_lock_concept.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_lock_concept.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_lock_concept.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -1,4 +1,4 @@
-// (C) Copyright 2006-7 Anthony Williams
+// (C) Copyright 2006-8 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)
@@ -7,7 +7,9 @@
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
template<typename Mutex,typename Lock>
struct test_initially_locked
@@ -23,6 +25,64 @@
};
template<typename Mutex,typename Lock>
+struct test_initially_unlocked_if_other_thread_has_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_unlocked_if_other_thread_has_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m);
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ bool is_done() const
+ {
+ return done;
+ }
+
+
+ void operator()()
+ {
+ Lock lock(m);
+
+ typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
struct test_initially_unlocked_with_defer_lock_parameter
{
void operator()() const
@@ -125,11 +185,51 @@
BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
}
};
+template<typename Lock>
+struct test_default_constructed_has_no_mutex_and_unlocked
+{
+ void operator()() const
+ {
+ Lock l;
+ BOOST_CHECK(!l.mutex());
+ BOOST_CHECK(!l.owns_lock());
+ };
+};
+
+
+template<typename Mutex,typename Lock>
+struct test_locks_can_be_swapped
+{
+ void operator()() const
+ {
+ Mutex m1;
+ Mutex m2;
+ Lock l1(m1);
+ Lock l2(m2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m1);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m2);
+
+ l1.swap(l2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m2);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m1);
+
+ swap(l1,l2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m1);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m2);
+
+ }
+};
+
+
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
{
typedef typename Mutex::scoped_lock Lock;
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
@@ -137,13 +237,16 @@
test_locked_after_lock_called<Mutex,Lock>()();
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
{
typedef typename Mutex::scoped_try_lock Lock;
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
test_unlocked_after_unlock_called<Mutex,Lock>()();
@@ -152,6 +255,7 @@
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
Modified: branches/CMake/release/libs/thread/test/test_move_function.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_move_function.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_move_function.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -1,10 +1,11 @@
-// Copyright (C) 2007 Anthony Williams
+// Copyright (C) 2007-8 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>
+#include <boost/shared_ptr.hpp>
void do_nothing()
{}
@@ -20,13 +21,36 @@
dest.join();
}
+void test_thread_move_from_lvalue_on_assignment()
+{
+ boost::thread src(do_nothing);
+ boost::thread::id src_id=src.get_id();
+ boost::thread dest;
+ 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();
+}
+
+boost::thread start_thread()
+{
+ return boost::thread(do_nothing);
+}
+
void test_thread_move_from_rvalue_on_construction()
{
- boost::thread x(boost::move(boost::thread(do_nothing)));
+ boost::thread x(start_thread());
BOOST_CHECK(x.get_id()!=boost::thread::id());
x.join();
}
+void test_thread_move_from_rvalue_using_explicit_move()
+{
+ boost::thread x(boost::move(start_thread()));
+ BOOST_CHECK(x.get_id()!=boost::thread::id());
+ x.join();
+}
void test_unique_lock_move_from_lvalue_on_construction()
{
@@ -42,6 +66,48 @@
BOOST_CHECK(l2.mutex()==&m);
}
+boost::unique_lock<boost::mutex> get_lock(boost::mutex& m)
+{
+ return boost::unique_lock<boost::mutex>(m);
+}
+
+
+void test_unique_lock_move_from_rvalue_on_construction()
+{
+ boost::mutex m;
+ boost::unique_lock<boost::mutex> l(get_lock(m));
+ BOOST_CHECK(l.owns_lock());
+ BOOST_CHECK(l.mutex()==&m);
+}
+
+namespace user_test_ns
+{
+ template<typename T>
+ T move(T& t)
+ {
+ return t.move();
+ }
+
+ bool move_called=false;
+
+ struct nc:
+ public boost::shared_ptr<int>
+ {
+ nc move()
+ {
+ move_called=true;
+ return nc();
+ }
+ };
+}
+
+void test_move_for_user_defined_type_unaffected()
+{
+ user_test_ns::nc src;
+ user_test_ns::nc dest=move(src);
+ BOOST_CHECK(user_test_ns::move_called);
+}
+
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
@@ -49,6 +115,10 @@
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_thread_move_from_rvalue_using_explicit_move));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment));
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected));
return test;
}
Modified: branches/CMake/release/libs/thread/test/test_shared_mutex_part_2.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_shared_mutex_part_2.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_shared_mutex_part_2.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -107,40 +107,6 @@
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 @@
}
}
-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 @@
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 @@
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;
}
Modified: branches/CMake/release/libs/thread/test/test_thread.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_thread.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_thread.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
+// Copyright (C) 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)
@@ -198,6 +199,22 @@
timed_test(&do_test_timed_join, 10);
}
+void test_swap()
+{
+ boost::thread t(simple_thread);
+ boost::thread t2(simple_thread);
+ boost::thread::id id1=t.get_id();
+ boost::thread::id id2=t2.get_id();
+
+ t.swap(t2);
+ BOOST_CHECK(t.get_id()==id2);
+ BOOST_CHECK(t2.get_id()==id1);
+
+ swap(t,t2);
+ BOOST_CHECK(t.get_id()==id1);
+ BOOST_CHECK(t2.get_id()==id2);
+}
+
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
@@ -211,6 +228,7 @@
test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point));
test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper));
test->add(BOOST_TEST_CASE(test_timed_join));
+ test->add(BOOST_TEST_CASE(test_swap));
return test;
}
Modified: branches/CMake/release/libs/thread/test/test_tss.cpp
==============================================================================
--- branches/CMake/release/libs/thread/test/test_tss.cpp (original)
+++ branches/CMake/release/libs/thread/test/test_tss.cpp 2008-06-29 11:50:43 EDT (Sun, 29 Jun 2008)
@@ -258,11 +258,58 @@
}
}
+struct dummy_class_tracks_deletions
+{
+ static unsigned deletions;
+
+ ~dummy_class_tracks_deletions()
+ {
+ ++deletions;
+ }
+
+};
+
+unsigned dummy_class_tracks_deletions::deletions=0;
+
+boost::thread_specific_ptr<dummy_class_tracks_deletions> tss_with_null_cleanup(NULL);
+
+void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker)
+{
+ tss_with_null_cleanup.reset(delete_tracker);
+}
+
+void do_test_tss_does_no_cleanup_with_null_cleanup_function()
+{
+ dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions;
+ boost::thread t(tss_thread_with_null_cleanup,delete_tracker);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(!dummy_class_tracks_deletions::deletions);
+ if(!dummy_class_tracks_deletions::deletions)
+ {
+ delete delete_tracker;
+ }
+}
+
void test_tss_does_no_cleanup_after_release()
{
timed_test(&do_test_tss_does_no_cleanup_after_release, 2);
}
+void test_tss_does_no_cleanup_with_null_cleanup_function()
+{
+ timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
+}
+
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
@@ -271,6 +318,7 @@
test->add(BOOST_TEST_CASE(test_tss));
test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup));
test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release));
+ test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function));
return test;
}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk