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

Compare commits

...

12 Commits

Author SHA1 Message Date
Beman Dawes
af4eb0ebbf Release 1.39.0
[SVN r52732]
2009-05-02 13:01:04 +00:00
John Maddock
9255a035f4 Merge PDF build changes from Trunk.
[SVN r51417]
2009-02-23 18:39:32 +00:00
Troy D. Straszheim
fbdc23f482 merge of cmake build files from trunk per beman
[SVN r50756]
2009-01-24 18:57:20 +00:00
Anthony Williams
8ab0d5acdd Merged change from trunk removing catch(...) clauses
[SVN r50524]
2009-01-09 11:06:53 +00:00
Daniel James
5af323102a Merge [46445] - add line ending properties. Ref #2441.
[SVN r49577]
2008-11-03 22:29:39 +00:00
Anthony Williams
0997fad8ec Merged Boost.Thread changes from trunk
[SVN r49324]
2008-10-13 20:30:13 +00:00
Anthony Williams
8749696538 Merged Thread doc changes from trunk
[SVN r48038]
2008-08-08 20:38:50 +00:00
Anthony Williams
9beea23f63 Merged thread doc changes from trunk
[SVN r47827]
2008-07-26 08:39:51 +00:00
Anthony Williams
2978d43a5d Merged thread doc changes from trunk
[SVN r47701]
2008-07-23 09:37:02 +00:00
Anthony Williams
a264766584 Merged changes over from trunk
[SVN r47700]
2008-07-23 09:35:40 +00:00
Anthony Williams
f03a9bfcf3 Merged thread changes from trunk
[SVN r47211]
2008-07-08 07:44:55 +00:00
Anthony Williams
60fdcddcb5 Merge of new boost.thread code along with required changes from boost.bind
[SVN r46474]
2008-06-18 13:01:08 +00:00
82 changed files with 5880 additions and 1725 deletions

22
CMakeLists.txt Normal file
View File

@@ -0,0 +1,22 @@
#----------------------------------------------------------------------------
# This file was automatically generated from the original CMakeLists.txt file
# Add a variable to hold the headers for the library
set (lib_headers
thread.hpp
thread
)
# Add a library target to the build system
boost_library_project(
thread
SRCDIRS src
TESTDIRS test
HEADERS ${lib_headers}
# DOCDIRS
# DESCRIPTION
MODULARIZED
# AUTHORS
# MAINTAINERS
)

View File

@@ -31,25 +31,6 @@ boostbook standalone
# Use the main Boost stylesheet:
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
# PDF Options:
# TOC Generation: this is needed for FOP-0.9 and later:
#<xsl:param>fop1.extensions=1
# Or enable this if you're using XEP:
<xsl:param>xep.extensions=1
# TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9!
<xsl:param>fop.extensions=0
# No indent on body text:
<xsl:param>body.start.indent=0pt
# Margin size:
<xsl:param>page.margin.inner=0.5in
# Margin size:
<xsl:param>page.margin.outer=0.5in
# Yes, we want graphics for admonishments:
<xsl:param>admon.graphics=1
# Set this one for PDF generation *only*:
# default pnd graphics are awful in PDF form,
# better use SVG's instead:
<format>pdf:<xsl:param>admon.graphics.extension=".svg"
<format>pdf:<xsl:param>admon.graphics.path=$(boost-images)/
;

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section:acknowledgements Acknowledgments]
The original implementation of __boost_thread__ was written by William Kempf, with contributions from numerous others. This new

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section:barriers Barriers]
A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is

View File

@@ -1,4 +1,27 @@
[section:changes Changes since boost 1.34]
[/
(C) Copyright 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).
]
[section:changes Changes since boost 1.35]
The 1.36.0 release of Boost includes a few new features in the thread library:
* New generic __lock_multiple_ref__ and __try_lock_multiple_ref__ functions for locking multiple mutexes at once.
* Rvalue reference support for move semantics where the compilers supports it.
* A few bugs fixed and missing functions added (including the serious win32 condition variable bug).
* `scoped_try_lock` types are now backwards-compatible with Boost 1.34.0 and previous releases.
* Support for passing function arguments to the thread function by supplying additional arguments to the __thread__ constructor.
* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts.
[heading Changes since boost 1.34]
Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface
changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking
@@ -44,7 +67,17 @@ 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__.
* 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.
* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
[endsect]

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section:condvar_ref Condition Variables]
[heading Synopsis]
@@ -67,6 +74,8 @@ optimizations in some cases, based on the knowledge of the mutex type;
[section:condition_variable Class `condition_variable`]
#include <boost/thread/condition_variable.hpp>
namespace boost
{
class condition_variable
@@ -75,6 +84,9 @@ optimizations in some cases, based on the knowledge of the mutex type;
condition_variable();
~condition_variable();
void notify_one();
void notify_all();
void wait(boost::unique_lock<boost::mutex>& lock);
template<typename predicate_type>
@@ -284,6 +296,8 @@ return true;
[section:condition_variable_any Class `condition_variable_any`]
#include <boost/thread/condition_variable.hpp>
namespace boost
{
class condition_variable_any
@@ -292,6 +306,9 @@ return true;
condition_variable_any();
~condition_variable_any();
void notify_one();
void notify_all();
template<typename lock_type>
void wait(lock_type& lock);
@@ -485,6 +502,8 @@ return true;
[section:condition Typedef `condition`]
#include <boost/thread/condition.hpp>
typedef condition_variable_any condition;
The typedef `condition` is provided for backwards compatibility with previous boost releases.

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section:mutex_concepts Mutex Concepts]
A mutex object facilitates protection against data races and allows thread-safe synchronization of data between threads. A thread
@@ -305,6 +312,8 @@ without blocking.]]
[section:lock_guard Class template `lock_guard`]
#include <boost/thread/locks.hpp>
template<typename Lockable>
class lock_guard
{
@@ -369,10 +378,13 @@ object passed to the constructor.]]
[section:unique_lock Class template `unique_lock`]
#include <boost/thread/locks.hpp>
template<typename Lockable>
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 +438,20 @@ The member functions of __unique_lock__ are not thread-safe. In particular, __un
__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
@@ -595,10 +621,13 @@ __owns_lock_ref__ returns `false`.]]
[section:shared_lock Class template `shared_lock`]
#include <boost/thread/locks.hpp>
template<typename Lockable>
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 +673,20 @@ The member functions of __shared_lock__ are not thread-safe. In particular, __sh
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
@@ -813,6 +856,8 @@ __owns_lock_shared_ref__ returns `false`.]]
[section:upgrade_lock Class template `upgrade_lock`]
#include <boost/thread/locks.hpp>
template<typename Lockable>
class upgrade_lock
{
@@ -860,6 +905,8 @@ state (including the destructor) must be called by the same thread that acquired
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`]
#include <boost/thread/locks.hpp>
template <class Lockable>
class upgrade_to_unique_lock
{
@@ -884,4 +931,189 @@ __lockable_concept_type__ is downgraded back to ['upgrade ownership].
[endsect]
[section:scoped_try_lock Mutex-specific class `scoped_try_lock`]
class MutexType::scoped_try_lock
{
private:
MutexType::scoped_try_lock(MutexType::scoped_try_lock<MutexType>& other);
MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock<MutexType>& other);
public:
MutexType::scoped_try_lock();
explicit MutexType::scoped_try_lock(MutexType& m);
MutexType::scoped_try_lock(MutexType& m_,adopt_lock_t);
MutexType::scoped_try_lock(MutexType& m_,defer_lock_t);
MutexType::scoped_try_lock(MutexType& m_,try_to_lock_t);
MutexType::scoped_try_lock(MutexType::scoped_try_lock<MutexType>&& other);
MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock<MutexType>&& other);
void swap(MutexType::scoped_try_lock&& other);
void lock();
bool try_lock();
void unlock();
bool owns_lock() const;
MutexType* mutex() const;
MutexType* release();
bool operator!() const;
typedef ``['unspecified-bool-type]`` bool_type;
operator bool_type() const;
};
The member typedef `scoped_try_lock` is provided for each distinct
`MutexType` as a typedef to a class with the preceding definition. The
semantics of each constructor and member function are identical to
those of [unique_lock_link `boost::unique_lock<MutexType>`] for the same `MutexType`, except
that the constructor that takes a single reference to a mutex will
call [try_lock_ref_link `m.try_lock()`] rather than `m.lock()`.
[endsect]
[endsect]
[section:lock_functions Lock functions]
[section:lock_multiple Non-member function `lock(Lockable1,Lockable2,...)`]
template<typename Lockable1,typename Lockable2>
void lock(Lockable1& l1,Lockable2& l2);
template<typename Lockable1,typename Lockable2,typename Lockable3>
void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3);
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4>
void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4);
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4,typename Lockable5>
void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5);
[variablelist
[[Effects:] [Locks the __lockable_concept_type__ objects supplied as
arguments in an unspecified and indeterminate order in a way that
avoids deadlock. It is safe to call this function concurrently from
multiple threads with the same mutexes (or other lockable objects) in
different orders without risk of deadlock. If any of the __lock_ref__
or __try_lock_ref__ operations on the supplied
__lockable_concept_type__ objects throws an exception any locks
acquired by the function will be released before the function exits.]]
[[Throws:] [Any exceptions thrown by calling __lock_ref__ or
__try_lock_ref__ on the supplied __lockable_concept_type__ objects.]]
[[Postcondition:] [All the supplied __lockable_concept_type__ objects
are locked by the calling thread.]]
]
[endsect]
[section:lock_range Non-member function `lock(begin,end)`]
template<typename ForwardIterator>
void lock(ForwardIterator begin,ForwardIterator end);
[variablelist
[[Preconditions:] [The `value_type` of `ForwardIterator` must implement the __lockable_concept__]]
[[Effects:] [Locks all the __lockable_concept_type__ objects in the
supplied range in an unspecified and indeterminate order in a way that
avoids deadlock. It is safe to call this function concurrently from
multiple threads with the same mutexes (or other lockable objects) in
different orders without risk of deadlock. If any of the __lock_ref__
or __try_lock_ref__ operations on the __lockable_concept_type__
objects in the supplied range throws an exception any locks acquired
by the function will be released before the function exits.]]
[[Throws:] [Any exceptions thrown by calling __lock_ref__ or
__try_lock_ref__ on the supplied __lockable_concept_type__ objects.]]
[[Postcondition:] [All the __lockable_concept_type__ objects in the
supplied range are locked by the calling thread.]]
]
[endsect]
[section:try_lock_multiple Non-member function `try_lock(Lockable1,Lockable2,...)`]
template<typename Lockable1,typename Lockable2>
int try_lock(Lockable1& l1,Lockable2& l2);
template<typename Lockable1,typename Lockable2,typename Lockable3>
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3);
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4>
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4);
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4,typename Lockable5>
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5);
[variablelist
[[Effects:] [Calls __try_lock_ref__ on each of the
__lockable_concept_type__ objects supplied as arguments. If any of the
calls to __try_lock_ref__ returns `false` then all locks acquired are
released and the zero-based index of the failed lock is returned.
If any of the __try_lock_ref__ operations on the supplied
__lockable_concept_type__ objects throws an exception any locks
acquired by the function will be released before the function exits.]]
[[Returns:] [`-1` if all the supplied __lockable_concept_type__ objects
are now locked by the calling thread, the zero-based index of the
object which could not be locked otherwise.]]
[[Throws:] [Any exceptions thrown by calling __try_lock_ref__ on the
supplied __lockable_concept_type__ objects.]]
[[Postcondition:] [If the function returns `-1`, all the supplied
__lockable_concept_type__ objects are locked by the calling
thread. Otherwise any locks acquired by this function will have been
released.]]
]
[endsect]
[section:try_lock_range Non-member function `try_lock(begin,end)`]
template<typename ForwardIterator>
ForwardIterator try_lock(ForwardIterator begin,ForwardIterator end);
[variablelist
[[Preconditions:] [The `value_type` of `ForwardIterator` must implement the __lockable_concept__]]
[[Effects:] [Calls __try_lock_ref__ on each of the
__lockable_concept_type__ objects in the supplied range. If any of the
calls to __try_lock_ref__ returns `false` then all locks acquired are
released and an iterator referencing the failed lock is returned.
If any of the __try_lock_ref__ operations on the supplied
__lockable_concept_type__ objects throws an exception any locks
acquired by the function will be released before the function exits.]]
[[Returns:] [`end` if all the supplied __lockable_concept_type__
objects are now locked by the calling thread, an iterator referencing
the object which could not be locked otherwise.]]
[[Throws:] [Any exceptions thrown by calling __try_lock_ref__ on the
supplied __lockable_concept_type__ objects.]]
[[Postcondition:] [If the function returns `end` then all the
__lockable_concept_type__ objects in the supplied range are locked by
the calling thread, otherwise all locks acquired by the function have
been released.]]
]
[endsect]
[endsect]

View File

@@ -1,7 +1,16 @@
[/
(C) Copyright 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).
]
[section:mutex_types Mutex Types]
[section:mutex Class `mutex`]
#include <boost/thread/mutex.hpp>
class mutex:
boost::noncopyable
{
@@ -12,18 +21,40 @@
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;
typedef unspecified-type scoped_try_lock;
};
__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`]
#include <boost/thread/mutex.hpp>
typedef mutex try_mutex;
__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost.
@@ -32,6 +63,8 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
[section:timed_mutex Class `timed_mutex`]
#include <boost/thread/mutex.hpp>
class timed_mutex:
boost::noncopyable
{
@@ -47,8 +80,11 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
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 unspecified-type scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
@@ -56,10 +92,28 @@ __timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusiv
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`]
#include <boost/thread/recursive_mutex.hpp>
class recursive_mutex:
boost::noncopyable
{
@@ -70,9 +124,12 @@ __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be perm
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;
typedef unspecified-type scoped_try_lock;
};
__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can
@@ -81,10 +138,28 @@ __unlock_ref__ shall be permitted. A thread that already has exclusive ownership
__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`]
#include <boost/thread/recursive_mutex.hpp>
typedef recursive_mutex recursive_try_mutex;
__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost.
@@ -93,6 +168,8 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
[section:recursive_timed_mutex Class `recursive_timed_mutex`]
#include <boost/thread/recursive_mutex.hpp>
class recursive_timed_mutex:
boost::noncopyable
{
@@ -108,9 +185,12 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
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;
typedef unspecified-type scoped_try_lock;
typedef scoped_lock scoped_timed_lock;
};
@@ -121,6 +201,22 @@ exclusive ownership of a given __recursive_timed_mutex__ instance can call __loc
__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]

View File

@@ -1,9 +1,18 @@
[/
(C) Copyright 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).
]
[section:once One-time Initialization]
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
[section:once_flag Typedef `once_flag`]
#include <boost/thread/once.hpp>
typedef platform-specific-type once_flag;
#define BOOST_ONCE_INIT platform-specific-initializer
@@ -15,6 +24,8 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
[section:call_once Non-member function `call_once`]
#include <boost/thread/once.hpp>
template<typename Callable>
void call_once(once_flag& flag,Callable func);
@@ -24,8 +35,8 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
be equivalent to calling the original. ]]
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func(args)`, and the invocation of
`call_once` is effective if and only if `func(args)` returns without exception. If an exception is thrown, the exception is
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
without invoking `func`. ]]

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section:overview Overview]
__boost_thread__ enables the use of multiple threads of execution with shared data in portable C++ code. It provides classes and
@@ -12,4 +19,12 @@ closely follow the proposals presented to the C++ Standards Committee, in partic
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
In order to use the classes and functions described here, you can
either include the specific headers specified by the descriptions of
each class or function, or include the master thread library header:
#include <boost/thread.hpp>
which includes all the other headers in turn.
[endsect]

View File

@@ -1,5 +1,14 @@
[/
(C) Copyright 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).
]
[section:shared_mutex Class `shared_mutex`]
#include <boost/thread/shared_mutex.hpp>
class shared_mutex
{
public:

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[article Thread
[quickbook 1.4]
[authors [Williams, Anthony]]
@@ -31,6 +38,12 @@
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.lock [link_text]]]
[def __lock_ref__ [lock_ref_link `lock()`]]
[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]]
[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]]
[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]]
[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]]
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.unlock [link_text]]]
[def __unlock_ref__ [unlock_ref_link `unlock()`]]
@@ -94,8 +107,10 @@
[def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]]
[def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]]
[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]]
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
[def __unique_lock__ [link thread.synchronization.locks.unique_lock `boost::unique_lock`]]
[def __unique_lock__ [unique_lock_link `boost::unique_lock`]]
[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]]
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
@@ -147,4 +162,6 @@
[include tss.qbk]
[include time.qbk]
[include acknowledgements.qbk]

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section:thread_management Thread Management]
[heading Synopsis]
@@ -17,6 +24,13 @@ allows the details of thread creation to be wrapped in a function.
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 +57,21 @@ __boost_thread__ must ensure that the referred-to object outlives the newly-crea
// 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]
@@ -141,6 +165,8 @@ __thread_id__ yield a total order for every non-equal thread ID.
[section:thread Class `thread`]
#include <boost/thread/thread.hpp>
class thread
{
public:
@@ -150,6 +176,9 @@ __thread_id__ yield a total order for every non-equal thread ID.
template <class F>
explicit thread(F f);
template <class F,class A1,class A2,...>
thread(F f,A1 a1,A2 a2,...);
template <class F>
thread(detail::thread_move_t<F> f);
@@ -189,6 +218,8 @@ __thread_id__ yield a total order for every non-equal thread ID.
static void sleep(const system_time& xt);
};
void swap(thread& lhs,thread& rhs);
[section:default_constructor Default Constructor]
thread();
@@ -212,7 +243,9 @@ __thread_id__ yield a total order for every non-equal thread ID.
[[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.]]
@@ -222,6 +255,30 @@ __thread_id__ yield a total order for every non-equal thread ID.
[endsect]
[section:multiple_argument_constructor Thread Constructor with arguments]
template <class F,class A1,class A2,...>
thread(F f,A1 a1,A2 a2,...);
[variablelist
[[Preconditions:] [`F` and each `A`n must by copyable or movable.]]
[[Effects:] [As if [link
thread.thread_management.thread.callable_constructor
`thread(boost::bind(f,a1,a2,...))`. Consequently, `f` and each `a`n
are copied into internal storage for access by the new thread.]]]
[[Postconditions:] [`*this` refers to the newly created thread of execution.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
[[Note:] [Currently up to nine additional arguments `a1` to `a9` can be specified in addition to the function `f`.]]
]
[endsect]
[section:destructor Thread Destructor]
~thread();
@@ -306,7 +363,7 @@ unchanged.]]
[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 +421,22 @@ or 0 if this information is not available.]]
[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,9 +489,43 @@ or 0 if this information is not available.]]
[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()`]
#include <boost/thread/thread.hpp>
void swap(thread& lhs,thread& rhs);
[variablelist
[[Effects:] [[link thread.thread_management.thread.swap `lhs.swap(rhs)`].]]
]
[endsect]
[section:id Class `boost::thread::id`]
#include <boost/thread/thread.hpp>
class thread::id
{
public:
@@ -471,7 +578,7 @@ otherwise.]]
[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]]
@@ -567,6 +674,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:get_id Non-member function `get_id()`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
thread::id get_id();
@@ -584,6 +693,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:interruption_point Non-member function `interruption_point()`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
void interruption_point();
@@ -601,6 +712,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:interruption_requested Non-member function `interruption_requested()`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
bool interruption_requested();
@@ -618,6 +731,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:interruption_enabled Non-member function `interruption_enabled()`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
bool interruption_enabled();
@@ -635,6 +750,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:sleep Non-member function `sleep()`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
template<typename TimeDuration>
@@ -655,6 +772,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:yield Non-member function `yield()`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
void yield();
@@ -672,6 +791,8 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[section:disable_interruption Class `disable_interruption`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
class disable_interruption
@@ -723,6 +844,8 @@ interruption state on destruction. Instances of `disable_interruption` cannot be
[section:restore_interruption Class `restore_interruption`]
#include <boost/thread/thread.hpp>
namespace this_thread
{
class restore_interruption
@@ -777,12 +900,16 @@ is destroyed, interruption is again disabled. Instances of `restore_interruption
[section:atthreadexit Non-member function template `at_thread_exit()`]
#include <boost/thread/thread.hpp>
template<typename Callable>
void at_thread_exit(Callable func);
[variablelist
[[Effects:] [A copy of `func` is taken and stored to in thread-specific storage. This copy is invoked when the current thread exits.]]
[[Effects:] [A copy of `func` is placed in
thread-specific storage. This copy is invoked when the current thread
exits (even if the thread has been interrupted).]]
[[Postconditions:] [A copy of `func` has been saved for invocation on thread exit.]]
@@ -797,6 +924,8 @@ error occurs within the thread library. Any exception thrown whilst copying `fun
[section:threadgroup Class `thread_group`]
#include <boost/thread/thread.hpp>
class thread_group:
private noncopyable
{
@@ -804,7 +933,8 @@ error occurs within the thread library. Any exception thrown whilst copying `fun
thread_group();
~thread_group();
thread* create_thread(const function0<void>& threadfunc);
template<typename F>
thread* create_thread(F threadfunc);
void add_thread(thread* thrd);
void remove_thread(thread* thrd);
void join_all();
@@ -841,7 +971,8 @@ error occurs within the thread library. Any exception thrown whilst copying `fun
[section:create_thread Member function `create_thread()`]
thread* create_thread(const function0<void>& threadfunc);
template<typename F>
thread* create_thread(F threadfunc);
[variablelist

75
doc/time.qbk Normal file
View File

@@ -0,0 +1,75 @@
[/
(C) Copyright 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).
]
[section:time Date and Time Requirements]
As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a
time out. These include (but are not limited to):
* __sleep__
* __timed_join__
* __cond_timed_wait__
* __timed_lock_ref__
For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is
required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link
thread.time.get_system_time `boost::get_system_time()`]. e.g.
boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500);
extern bool done;
extern boost::mutex m;
extern boost::condition_variable cond;
boost::unique_lock<boost::mutex> lk(m);
while(!done)
{
if(!cond.timed_wait(lk,timeout))
{
throw "timed out";
}
}
For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link
date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g.
boost::this_thread::sleep(boost::posix_time::milliseconds(25));
boost::mutex m;
if(m.timed_lock(boost::posix_time::nanoseconds(100)))
{
// ...
}
[section:system_time Typedef `system_time`]
#include <boost/thread/thread_time.hpp>
typedef boost::posix_time::ptime system_time;
See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library.
[endsect]
[section:get_system_time Non-member function `get_system_time()`]
#include <boost/thread/thread_time.hpp>
system_time get_system_time();
[variablelist
[[Returns:] [The current time.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]

View File

@@ -1,3 +1,10 @@
[/
(C) Copyright 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).
]
[section Thread Local Storage]
[heading Synopsis]
@@ -37,6 +44,8 @@ cleaned up, that value is added to the cleanup list. Cleanup finishes when there
[section:thread_specific_ptr Class `thread_specific_ptr`]
#include <boost/thread/tss.hpp>
template <typename T>
class thread_specific_ptr
{

View File

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

View File

@@ -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

View File

@@ -1,6 +1,6 @@
// Copyright (C) 2002-2003
// David Moore, 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)
@@ -15,6 +15,8 @@
#include <string>
#include <stdexcept>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
@@ -56,4 +58,6 @@ namespace boost
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,11 +1,18 @@
// 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)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
#ifndef BOOST_THREAD_MOVE_HPP
#define BOOST_THREAD_MOVE_HPP
#ifndef BOOST_NO_SFINAE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
@@ -14,10 +21,15 @@ namespace boost
struct thread_move_t
{
T& t;
thread_move_t(T& t_):
explicit thread_move_t(T& t_):
t(t_)
{}
T& operator*() const
{
return t;
}
T* operator->() const
{
return &t;
@@ -26,8 +38,23 @@ namespace boost
void operator=(thread_move_t&);
};
}
#ifndef BOOST_NO_SFINAE
template<typename T>
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, T >::type move(T& t)
{
return T(detail::thread_move_t<T>(t));
}
#endif
template<typename T>
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
{
return t;
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -42,9 +42,9 @@
#elif defined(__QNXNTO__)
# define BOOST_THREAD_QNXNTO
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_POSIX
# endif
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_POSIX
# endif
#endif
// For every supported platform add a new entry into the dispatch table below.

View File

@@ -1,27 +1,29 @@
#ifndef BOOST_THREAD_THREAD_WIN32_HPP
#define BOOST_THREAD_THREAD_WIN32_HPP
#ifndef BOOST_THREAD_THREAD_COMMON_HPP
#define BOOST_THREAD_THREAD_COMMON_HPP
// 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)
// (C) Copyright 2007 Anthony Williams
#include <exception>
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/exceptions.hpp>
#include <ostream>
#include <boost/thread/detail/move.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread_time.hpp>
#include "thread_primitives.hpp"
#include "thread_heap_alloc.hpp"
#include <boost/thread/xtime.hpp>
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/utility.hpp>
#include <boost/assert.hpp>
#include <list>
#include <algorithm>
#include <boost/ref.hpp>
#include <boost/cstdint.hpp>
#include <boost/bind.hpp>
#include <stdlib.h>
#include <memory>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
@@ -30,195 +32,262 @@
namespace boost
{
class thread_interrupted
{};
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base
{
long count;
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
thread_exit_callbacks(0),tss_data(0),
interruption_enabled(true),
id(0)
{}
virtual ~thread_data_base()
{}
friend void intrusive_ptr_add_ref(thread_data_base * p)
{
BOOST_INTERLOCKED_INCREMENT(&p->count);
}
friend void intrusive_ptr_release(thread_data_base * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
{
detail::heap_delete(p);
}
}
void interrupt()
{
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
}
virtual void run()=0;
};
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
{
unsigned long start;
uintmax_t milliseconds;
bool relative;
boost::system_time abs_time;
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct remaining_time
{
bool more;
unsigned long milliseconds;
remaining_time(uintmax_t remaining):
more(remaining>max_non_infinite_wait),
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
{}
};
remaining_time remaining_milliseconds() const
{
if(is_sentinel())
{
return remaining_time(win32::infinite);
}
else if(relative)
{
unsigned long const now=win32::GetTickCount();
unsigned long const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}
else
{
system_time const now=get_system_time();
if(abs_time<=now)
{
return remaining_time(0);
}
return remaining_time((abs_time-now).total_milliseconds()+1);
}
}
bool is_sentinel() const
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
return timeout(sentinel_type());
}
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
}
class BOOST_THREAD_DECL thread
{
private:
thread(thread&);
thread& operator=(thread&);
void release_handle();
template<typename F>
struct thread_data:
detail::thread_data_base
class thread_data:
public detail::thread_data_base
{
F f;
public:
#ifdef BOOST_HAS_RVALUE_REFS
thread_data(F&& f_):
f(static_cast<F&&>(f_))
{}
#else
thread_data(F f_):
f(f_)
{}
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
#endif
void run()
{
f();
}
private:
F f;
void operator=(thread_data&);
thread_data(thread_data&);
};
template<typename F>
class thread_data<boost::reference_wrapper<F> >:
public detail::thread_data_base
{
private:
F& f;
void operator=(thread_data&);
thread_data(thread_data&);
public:
thread_data(boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
template<typename F>
class thread_data<const boost::reference_wrapper<F> >:
public detail::thread_data_base
{
private:
F& f;
void operator=(thread_data&);
thread_data(thread_data&);
public:
thread_data(const boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
}
class BOOST_THREAD_DECL thread
{
private:
thread(thread&);
thread& operator=(thread&);
void release_handle();
mutable boost::mutex thread_info_mutex;
detail::thread_data_ptr thread_info;
static unsigned __stdcall thread_start_function(void* param);
void start_thread();
explicit thread(detail::thread_data_ptr data);
detail::thread_data_ptr get_thread_info() const;
#ifdef BOOST_HAS_RVALUE_REFS
template<typename F>
static inline detail::thread_data_ptr make_thread_info(F&& f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(static_cast<F&&>(f)));
}
static inline detail::thread_data_ptr make_thread_info(void (*f)())
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(f));
}
#else
template<typename F>
static inline detail::thread_data_ptr make_thread_info(F f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
}
template<typename F>
static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t<F> f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
}
struct dummy;
#endif
public:
thread();
~thread();
#ifdef BOOST_HAS_RVALUE_REFS
template <class F>
thread(F&& f):
thread_info(make_thread_info(static_cast<F&&>(f)))
{
start_thread();
}
thread(thread&& other)
{
thread_info.swap(other.thread_info);
}
thread& operator=(thread&& other)
{
thread_info=other.thread_info;
other.thread_info.reset();
return *this;
}
thread&& move()
{
return static_cast<thread&&>(*this);
}
#else
#ifdef BOOST_NO_SFINAE
template <class F>
explicit thread(F f):
thread_info(detail::heap_new<thread_data<F> >(f))
thread_info(make_thread_info(f))
{
start_thread();
}
#else
template <class F>
thread(detail::thread_move_t<F> f):
thread_info(detail::heap_new<thread_data<F> >(f))
explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
thread_info(make_thread_info(f))
{
start_thread();
}
#endif
template <class F>
explicit thread(detail::thread_move_t<F> f):
thread_info(make_thread_info(f))
{
start_thread();
}
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
thread(detail::thread_move_t<thread> x)
{
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> move()
{
detail::thread_move_t<thread> x(*this);
return x;
}
void swap(thread& x);
#endif
template <class F,class A1>
thread(F f,A1 a1):
thread_info(make_thread_info(boost::bind(boost::type<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(boost::type<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(boost::type<void>(),f,a1,a2,a3)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
{
start_thread();
}
void swap(thread& x)
{
thread_info.swap(x.thread_info);
}
class id;
id get_id() const;
@@ -237,47 +306,44 @@ namespace boost
static unsigned hardware_concurrency();
typedef detail::win32::handle native_handle_type;
typedef detail::thread_data_base::native_handle_type native_handle_type;
native_handle_type native_handle();
// backwards compatibility
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
static void yield();
static void sleep(const system_time& xt);
static inline void yield()
{
this_thread::yield();
}
static inline void sleep(const system_time& xt)
{
this_thread::sleep(xt);
}
// extensions
void interrupt();
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
inline void swap(thread& lhs,thread& rhs)
{
return x.move();
return lhs.swap(rhs);
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
#ifdef BOOST_HAS_RVALUE_REFS
inline thread&& move(thread&& t)
{
return x;
return t;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
#else
inline thread move(detail::thread_move_t<thread> t)
{
F& f;
thread_data(boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
return thread(t);
}
#endif
namespace this_thread
{
@@ -304,21 +370,13 @@ namespace boost
thread::id BOOST_THREAD_DECL get_id();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline bool interruptible_wait(unsigned long milliseconds)
{
return interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
}
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled();
bool BOOST_THREAD_DECL interruption_requested();
void BOOST_THREAD_DECL yield();
template<typename TimeDuration>
void sleep(TimeDuration const& rel_time)
inline void sleep(xtime const& abs_time)
{
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
sleep(system_time(abs_time));
}
}
@@ -334,7 +392,7 @@ namespace boost
friend id this_thread::get_id();
public:
id():
thread_data(0)
thread_data()
{}
bool operator==(const id& y) const
@@ -380,15 +438,6 @@ namespace boost
return os<<"{Not-any-thread}";
}
}
void interrupt()
{
if(thread_data)
{
thread_data->interrupt();
}
}
};
inline bool thread::operator==(const thread& other) const
@@ -521,4 +570,6 @@ namespace boost
#pragma warning(pop)
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,23 @@
#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
// thread_heap_alloc.hpp
//
// (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)
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/thread_heap_alloc.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/thread_heap_alloc.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -8,6 +8,8 @@
#include <boost/thread/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
#if defined(BOOST_HAS_WINTHREADS)
typedef void (__cdecl *thread_exit_handler)(void);
@@ -59,7 +61,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
@@ -75,4 +77,6 @@
#endif //defined(BOOST_HAS_WINTHREADS)
#include <boost/config/abi_suffix.hpp>
#endif //!defined(BOOST_TLS_HOOKS_HPP)

View File

@@ -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)
@@ -19,7 +19,13 @@
#include <string>
#include <stdexcept>
namespace boost {
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class BOOST_THREAD_DECL thread_interrupted
{};
class BOOST_THREAD_DECL thread_exception : public std::exception
{
@@ -99,6 +105,8 @@ public:
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_THREAD_CONFIG_PDM070801_H
// Change log:

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,8 @@
#error "Boost threads unavailable on this platform"
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
inline void call_once(void (*func)(),once_flag& flag)
@@ -26,4 +28,6 @@ namespace boost
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,32 +3,17 @@
// 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)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
#include <limits.h>
#include <boost/assert.hpp>
#include <algorithm>
#include <pthread.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
#include "thread_data.hpp"
#include "condition_variable_fwd.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
inline condition_variable::condition_variable()
{
int const res=pthread_cond_init(&cond,NULL);
if(res)
{
throw thread_resource_error();
}
}
inline condition_variable::~condition_variable()
{
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
inline void condition_variable::wait(unique_lock<mutex>& m)
{
detail::interruption_checker check_for_interruption(&cond);
@@ -136,6 +121,17 @@ namespace boost
}
return true;
}
template<typename lock_type>
bool timed_wait(lock_type& m,xtime const& wait_until)
{
return timed_wait(m,system_time(wait_until));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return timed_wait(m,get_system_time()+wait_duration);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
@@ -175,4 +171,6 @@ namespace boost
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,14 +3,17 @@
// 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)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
#include <boost/assert.hpp>
#include <pthread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class condition_variable
@@ -22,8 +25,18 @@ namespace boost
condition_variable& operator=(condition_variable&);
public:
condition_variable();
~condition_variable();
condition_variable()
{
int const res=pthread_cond_init(&cond,NULL);
if(res)
{
throw thread_resource_error();
}
}
~condition_variable()
{
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
void wait(unique_lock<mutex>& m);
@@ -34,6 +47,16 @@ namespace boost
}
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until);
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until)
{
return timed_wait(m,system_time(wait_until));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return timed_wait(m,get_system_time()+wait_duration);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
@@ -58,9 +81,17 @@ 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();
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,6 +1,6 @@
#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 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)
@@ -10,10 +10,8 @@
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/assert.hpp>
#ifndef WIN32
#include <unistd.h>
#endif
#include <errno.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
@@ -24,6 +22,8 @@
#endif
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class mutex:
@@ -69,7 +69,7 @@ namespace boost
}
typedef unique_lock<mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
};
typedef mutex try_mutex;
@@ -114,6 +114,10 @@ namespace boost
{
return timed_lock(get_system_time()+relative_time);
}
bool timed_lock(boost::xtime const & absolute_time)
{
return timed_lock(system_time(absolute_time));
}
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
void lock()
@@ -136,9 +140,16 @@ 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;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
#else
void lock()
{
@@ -187,11 +198,13 @@ namespace boost
#endif
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef scoped_timed_lock scoped_try_lock;
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,7 +3,7 @@
// once.hpp
//
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -17,7 +17,10 @@
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
namespace boost {
#include <boost/config/abi_prefix.hpp>
namespace boost
{
struct once_flag
{
@@ -82,4 +85,6 @@ namespace boost {
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,6 +1,6 @@
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -9,6 +9,8 @@
#include <pthread.h>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace pthread
@@ -47,4 +49,6 @@ namespace boost
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,6 +1,6 @@
#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 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)
@@ -11,7 +11,7 @@
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/assert.hpp>
#ifndef WIN32
#ifndef _WIN32
#include <unistd.h>
#endif
#include <boost/date_time/posix_time/conversion.hpp>
@@ -25,6 +25,8 @@
#endif
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class recursive_mutex:
@@ -76,8 +78,15 @@ namespace boost
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
typedef unique_lock<recursive_mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
};
typedef recursive_mutex recursive_try_mutex;
@@ -168,9 +177,16 @@ 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;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
#else
void lock()
{
@@ -239,11 +255,12 @@ namespace boost
#endif
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
typedef scoped_timed_lock scoped_try_lock;
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
// (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
@@ -13,6 +13,8 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex
@@ -44,7 +46,7 @@ namespace boost
public:
shared_mutex()
{
state_data state_={0};
state_data state_={0,0,0,0};
state=state_;
}
@@ -55,30 +57,18 @@ namespace boost
void lock_shared()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
while(state.exclusive || state.exclusive_waiting_blocked)
{
if(!state.exclusive && !state.exclusive_waiting_blocked)
{
++state.shared_count;
return;
}
shared_cond.wait(lock);
shared_cond.wait(lk);
}
++state.shared_count;
}
bool try_lock_shared()
{
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked)
{
@@ -94,33 +84,28 @@ namespace boost
bool timed_lock_shared(system_time const& timeout)
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
while(state.exclusive || state.exclusive_waiting_blocked)
{
if(!state.exclusive && !state.exclusive_waiting_blocked)
{
++state.shared_count;
return true;
}
if(!shared_cond.timed_wait(lock,timeout))
if(!shared_cond.timed_wait(lk,timeout))
{
return false;
}
}
++state.shared_count;
return true;
}
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);
boost::mutex::scoped_lock lk(state_change);
bool const last_reader=!--state.shared_count;
if(last_reader)
@@ -142,63 +127,48 @@ namespace boost
void lock()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
while(state.shared_count || state.exclusive)
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
}
else
{
state.exclusive=true;
return;
}
exclusive_cond.wait(lock);
state.exclusive_waiting_blocked=true;
exclusive_cond.wait(lk);
}
state.exclusive=true;
}
bool timed_lock(system_time const& timeout)
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
boost::mutex::scoped_lock lk(state_change);
while(state.shared_count || state.exclusive)
{
if(state.shared_count || state.exclusive)
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.timed_wait(lk,timeout))
{
state.exclusive_waiting_blocked=true;
}
else
{
state.exclusive=true;
return true;
}
if(!exclusive_cond.timed_wait(lock,timeout))
{
return false;
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
exclusive_cond.notify_one();
return false;
}
break;
}
}
state.exclusive=true;
return true;
}
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);
boost::mutex::scoped_lock lk(state_change);
if(state.shared_count || state.exclusive)
{
@@ -214,7 +184,7 @@ namespace boost
void unlock()
{
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
state.exclusive=false;
state.exclusive_waiting_blocked=false;
release_waiters();
@@ -223,57 +193,44 @@ namespace boost
void lock_upgrade()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade)
{
++state.shared_count;
state.upgrade=true;
return;
}
shared_cond.wait(lock);
shared_cond.wait(lk);
}
++state.shared_count;
state.upgrade=true;
}
bool timed_lock_upgrade(system_time const& timeout)
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade)
if(!shared_cond.timed_wait(lk,timeout))
{
++state.shared_count;
state.upgrade=true;
return true;
}
if(!shared_cond.timed_wait(lock,timeout))
{
return false;
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
break;
}
}
++state.shared_count;
state.upgrade=true;
return true;
}
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);
boost::mutex::scoped_lock lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
@@ -288,7 +245,7 @@ namespace boost
void unlock_upgrade()
{
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
state.upgrade=false;
bool const last_reader=!--state.shared_count;
@@ -302,30 +259,19 @@ namespace boost
void unlock_upgrade_and_lock()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
--state.shared_count;
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
while(state.shared_count)
{
if(!state.shared_count)
{
state.upgrade=false;
state.exclusive=true;
break;
}
upgrade_cond.wait(lock);
upgrade_cond.wait(lk);
}
state.upgrade=false;
state.exclusive=true;
}
void unlock_and_lock_upgrade()
{
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
state.exclusive=false;
state.upgrade=true;
++state.shared_count;
@@ -335,7 +281,7 @@ namespace boost
void unlock_and_lock_shared()
{
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
state.exclusive=false;
++state.shared_count;
state.exclusive_waiting_blocked=false;
@@ -344,7 +290,7 @@ namespace boost
void unlock_upgrade_and_lock_shared()
{
boost::mutex::scoped_lock lock(state_change);
boost::mutex::scoped_lock lk(state_change);
state.upgrade=false;
state.exclusive_waiting_blocked=false;
release_waiters();
@@ -352,5 +298,6 @@ namespace boost
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,329 +0,0 @@
#ifndef BOOST_THREAD_THREAD_PTHREAD_HPP
#define BOOST_THREAD_THREAD_PTHREAD_HPP
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <list>
#include <memory>
#include <pthread.h>
#include <boost/optional.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/shared_ptr.hpp>
#include "thread_data.hpp"
#include <stdlib.h>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4251)
#endif
namespace boost
{
class thread;
namespace detail
{
class thread_id;
}
namespace this_thread
{
BOOST_THREAD_DECL detail::thread_id get_id();
}
namespace detail
{
class thread_id
{
private:
detail::thread_data_ptr thread_data;
thread_id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
{}
friend class boost::thread;
friend thread_id this_thread::get_id();
public:
thread_id():
thread_data()
{}
bool operator==(const thread_id& y) const
{
return thread_data==y.thread_data;
}
bool operator!=(const thread_id& y) const
{
return thread_data!=y.thread_data;
}
bool operator<(const thread_id& y) const
{
return thread_data<y.thread_data;
}
bool operator>(const thread_id& y) const
{
return y.thread_data<thread_data;
}
bool operator<=(const thread_id& y) const
{
return !(y.thread_data<thread_data);
}
bool operator>=(const thread_id& y) const
{
return !(thread_data<y.thread_data);
}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const thread_id& x)
{
if(x.thread_data)
{
return os<<x.thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
}
};
}
struct xtime;
class BOOST_THREAD_DECL thread
{
private:
thread(thread&);
thread& operator=(thread&);
template<typename F>
struct thread_data:
detail::thread_data_base
{
F f;
thread_data(F f_):
f(f_)
{}
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
void run()
{
f();
}
};
mutable boost::mutex thread_info_mutex;
detail::thread_data_ptr thread_info;
void start_thread();
explicit thread(detail::thread_data_ptr data);
detail::thread_data_ptr get_thread_info() const;
public:
thread();
~thread();
template <class F>
explicit thread(F f):
thread_info(new thread_data<F>(f))
{
start_thread();
}
template <class F>
thread(detail::thread_move_t<F> f):
thread_info(new thread_data<F>(f))
{
start_thread();
}
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
void swap(thread& x);
typedef detail::thread_id id;
id get_id() const;
bool joinable() const;
void join();
bool timed_join(const system_time& wait_until);
template<typename TimeDuration>
inline bool timed_join(TimeDuration const& rel_time)
{
return timed_join(get_system_time()+rel_time);
}
void detach();
static unsigned hardware_concurrency();
// backwards compatibility
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
static void sleep(const system_time& xt);
static void yield();
// extensions
void interrupt();
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
{
F& f;
thread_data(boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
namespace this_thread
{
class BOOST_THREAD_DECL disable_interruption
{
disable_interruption(const disable_interruption&);
disable_interruption& operator=(const disable_interruption&);
bool interruption_was_enabled;
friend class restore_interruption;
public:
disable_interruption();
~disable_interruption();
};
class BOOST_THREAD_DECL restore_interruption
{
restore_interruption(const restore_interruption&);
restore_interruption& operator=(const restore_interruption&);
public:
explicit restore_interruption(disable_interruption& d);
~restore_interruption();
};
BOOST_THREAD_DECL thread::id get_id();
BOOST_THREAD_DECL void interruption_point();
BOOST_THREAD_DECL bool interruption_enabled();
BOOST_THREAD_DECL bool interruption_requested();
inline void yield()
{
thread::yield();
}
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
{
thread::sleep(get_system_time()+rel_time);
}
}
namespace detail
{
struct thread_exit_function_base
{
virtual ~thread_exit_function_base()
{}
virtual void operator()() const=0;
};
template<typename F>
struct thread_exit_function:
thread_exit_function_base
{
F f;
thread_exit_function(F f_):
f(f_)
{}
void operator()() const
{
f();
}
};
BOOST_THREAD_DECL void add_thread_exit_function(thread_exit_function_base*);
}
namespace this_thread
{
template<typename F>
inline void at_thread_exit(F f)
{
detail::thread_exit_function_base* const thread_exit_func=new detail::thread_exit_function<F>(f);
detail::add_thread_exit_function(thread_exit_func);
}
}
class BOOST_THREAD_DECL thread_group
{
public:
thread_group();
~thread_group();
thread* create_thread(const function0<void>& threadfunc);
void add_thread(thread* thrd);
void remove_thread(thread* thrd);
void join_all();
void interrupt_all();
size_t size() const;
private:
thread_group(thread_group&);
void operator=(thread_group&);
std::list<thread*> m_threads;
mutex m_mutex;
};
} // namespace boost
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#endif

View File

@@ -6,6 +6,7 @@
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/mutex.hpp>
@@ -13,11 +14,12 @@
#include <pthread.h>
#include "condition_variable_fwd.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class thread_interrupted
{};
class thread;
namespace detail
{
struct thread_exit_callback_node;
@@ -26,7 +28,7 @@ namespace boost
struct thread_data_base;
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
struct thread_data_base:
struct BOOST_THREAD_DECL thread_data_base:
enable_shared_from_this<thread_data_base>
{
thread_data_ptr self;
@@ -51,8 +53,9 @@ namespace boost
interrupt_requested(false),
current_cond(0)
{}
virtual ~thread_data_base()
{}
virtual ~thread_data_base();
typedef pthread_t native_handle_type;
virtual void run()=0;
};
@@ -95,7 +98,21 @@ namespace boost
}
};
}
namespace this_thread
{
void BOOST_THREAD_DECL yield();
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
{
this_thread::sleep(get_system_time()+rel_time);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,242 @@
// 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)
// (C) Copyright 2008 Anthony Williams
#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP
#define THREAD_HEAP_ALLOC_PTHREAD_HPP
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
template<typename T>
inline T* heap_new()
{
return new T();
}
#ifdef BOOST_HAS_RVALUE_REFS
template<typename T,typename A1>
inline T* heap_new(A1&& a1)
{
return new T(static_cast<A1&&>(a1));
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1&& a1,A2&& a2)
{
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
{
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3));
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
{
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
}
#else
template<typename T,typename A1>
inline T* heap_new_impl(A1 a1)
{
return new T(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new_impl(A1 a1,A2 a2)
{
return new T(a1,a2);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
{
return new T(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
{
return new T(a1,a2,a3,a4);
}
template<typename T,typename A1>
inline T* heap_new(A1 const& a1)
{
return heap_new_impl<T,A1 const&>(a1);
}
template<typename T,typename A1>
inline T* heap_new(A1& a1)
{
return heap_new_impl<T,A1&>(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2 const& a2)
{
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2 const& a2)
{
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2& a2)
{
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2& a2)
{
return heap_new_impl<T,A1&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
#endif
template<typename T>
inline void heap_delete(T* data)
{
delete data;
}
template<typename T>
struct do_heap_delete
{
void operator()(T* data) const
{
detail::heap_delete(data);
}
};
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,6 +1,6 @@
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -8,6 +8,12 @@
#include <boost/thread/thread_time.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <pthread.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
@@ -15,14 +21,16 @@ namespace boost
{
inline struct timespec get_timespec(boost::system_time const& abs_time)
{
struct timespec timeout={0};
struct timespec timeout={0,0};
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
timeout.tv_sec=time_since_epoch.total_seconds();
timeout.tv_nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second());
timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
return timeout;
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,103 +0,0 @@
#ifndef BOOST_THREAD_PTHREAD_TSS_HPP
#define BOOST_THREAD_PTHREAD_TSS_HPP
// 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)
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(new delete_data)
{}
explicit thread_specific_ptr(void (*func_)(T*)):
cleanup(new run_custom_cleanup_function(func_))
{}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#endif

View File

@@ -3,7 +3,7 @@
// thread.hpp
//
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -12,11 +12,14 @@
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/thread.hpp>
#include <boost/thread/win32/thread_data.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/thread.hpp>
#include <boost/thread/pthread/thread_data.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#include <boost/thread/detail/thread.hpp>
#endif

View File

@@ -9,6 +9,8 @@
#include <boost/date_time/microsec_time_clock.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
typedef boost::posix_time::ptime system_time;
@@ -43,4 +45,6 @@ namespace boost
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,18 +1,111 @@
// 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)
#ifndef BOOST_THREAD_TSS_HPP
#define BOOST_THREAD_TSS_HPP
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/tss.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/tss.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif
#ifndef BOOST_THREAD_TSS_HPP
#define BOOST_THREAD_TSS_HPP
// 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)
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}
explicit thread_specific_ptr(void (*func_)(T*))
{
if(func_)
{
cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
}
}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,7 +3,7 @@
// basic_recursive_mutex.hpp
//
// (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
@@ -12,6 +12,8 @@
#include "thread_primitives.hpp"
#include "basic_timed_mutex.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
@@ -62,11 +64,6 @@ namespace boost
return timed_lock(get_system_time()+timeout);
}
long get_active_count()
{
return mutex.get_active_count();
}
void unlock()
{
if(!--recursion_count)
@@ -76,11 +73,6 @@ namespace boost
}
}
bool locked()
{
return mutex.locked();
}
private:
bool try_recursive_lock(long current_thread_id)
{
@@ -123,4 +115,6 @@ namespace boost
#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,7 +3,7 @@
// basic_timed_mutex_win32.hpp
//
// (C) Copyright 2006 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
@@ -13,15 +13,21 @@
#include "thread_primitives.hpp"
#include "interlocked_read.hpp"
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
struct basic_timed_mutex
{
BOOST_STATIC_CONSTANT(long,lock_flag_value=0x80000000);
BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31);
BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30);
BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit);
BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit);
long active_count;
void* event;
@@ -50,18 +56,7 @@ namespace boost
bool try_lock()
{
long old_count=active_count&~lock_flag_value;
do
{
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
if(current_count==old_count)
{
return true;
}
old_count=current_count;
}
while(!(old_count&lock_flag_value));
return false;
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
}
void lock()
@@ -70,47 +65,46 @@ namespace boost
}
bool timed_lock(::boost::system_time const& wait_until)
{
long old_count=active_count;
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(!win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit))
{
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
if(current_count==old_count)
return true;
}
long old_count=active_count;
for(;;)
{
long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
break;
}
old_count=current_count;
old_count=current;
}
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
++old_count; // we're waiting, too
do
{
old_count-=(lock_flag_value+1); // there will be one less active thread on this mutex when it gets unlocked
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
do
old_count&=~lock_flag_value;
old_count|=event_set_flag_value;
for(;;)
{
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,old_count|lock_flag_value,old_count);
if(current_count==old_count)
long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
break;
}
old_count=current_count;
old_count=current;
}
while(!(old_count&lock_flag_value));
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
@@ -124,27 +118,24 @@ namespace boost
return timed_lock(get_system_time()+timeout);
}
long get_active_count()
bool timed_lock(boost::xtime const& timeout)
{
return ::boost::detail::interlocked_read_acquire(&active_count);
return timed_lock(system_time(timeout));
}
void unlock()
{
long const offset=lock_flag_value+1;
long old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,(~offset)+1);
if(old_count>offset)
long const offset=lock_flag_value;
long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
if(!(old_count&event_set_flag_value) && (old_count>offset))
{
win32::SetEvent(get_event());
if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
{
win32::SetEvent(get_event());
}
}
}
bool locked()
{
return get_active_count()>=lock_flag_value;
}
private:
void* get_event()
{
@@ -182,4 +173,6 @@ namespace boost
#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,7 +3,7 @@
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/mutex.hpp>
#include "thread_primitives.hpp"
@@ -14,85 +14,118 @@
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
#include <boost/thread/xtime.hpp>
#include <vector>
#include <boost/intrusive_ptr.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
class basic_cv_list_entry;
void intrusive_ptr_add_ref(basic_cv_list_entry * p);
void intrusive_ptr_release(basic_cv_list_entry * p);
class basic_cv_list_entry
{
private:
detail::win32::handle_manager semaphore;
detail::win32::handle_manager wake_sem;
long waiters;
bool notified;
long references;
basic_cv_list_entry(basic_cv_list_entry&);
void operator=(basic_cv_list_entry&);
public:
explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
wake_sem(wake_sem_.duplicate()),
waiters(1),notified(false),references(0)
{}
static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
{
return !detail::interlocked_read_acquire(&entry->waiters);
}
void add_waiter()
{
BOOST_INTERLOCKED_INCREMENT(&waiters);
}
void remove_waiter()
{
BOOST_INTERLOCKED_DECREMENT(&waiters);
}
void release(unsigned count_to_release)
{
notified=true;
detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
}
void release_waiters()
{
release(detail::interlocked_read_acquire(&waiters));
}
bool is_notified() const
{
return notified;
}
bool wait(timeout wait_until)
{
return this_thread::interruptible_wait(semaphore,wait_until);
}
bool woken()
{
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0);
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
return woken_result==0;
}
friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
friend void intrusive_ptr_release(basic_cv_list_entry * p);
};
inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
{
BOOST_INTERLOCKED_INCREMENT(&p->references);
}
inline void intrusive_ptr_release(basic_cv_list_entry * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
{
delete p;
}
}
class basic_condition_variable
{
boost::mutex internal_mutex;
long total_count;
unsigned active_generation_count;
struct list_entry
typedef basic_cv_list_entry list_entry;
typedef boost::intrusive_ptr<list_entry> entry_ptr;
typedef std::vector<entry_ptr> generation_list;
generation_list generations;
detail::win32::handle_manager wake_sem;
void wake_waiters(long count_to_wake)
{
detail::win32::handle semaphore;
long count;
bool notified;
list_entry():
semaphore(0),count(0),notified(0)
{}
};
BOOST_STATIC_CONSTANT(unsigned,generation_count=3);
list_entry generations[generation_count];
detail::win32::handle wake_sem;
static bool no_waiters(list_entry const& entry)
{
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,75 +149,78 @@ 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()->is_notified())
{
shift_generations_down();
entry_ptr new_entry(new list_entry(wake_sem));
generations.push_back(new_entry);
return new_entry;
}
else if(!active_generation_count)
else
{
active_generation_count=1;
generations.back()->add_waiter();
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);
entry->remove_waiter();
}
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(!entry->wait(wait_until))
{
return false;
}
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0);
woken=(woken_result==0);
woken=entry->woken();
}
return woken;
}
@@ -202,45 +238,33 @@ namespace boost
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
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)
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
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(),&basic_cv_list_entry::no_waiters),generations.end());
}
}
@@ -248,16 +272,20 @@ 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)
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
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_waiters();
}
generations.clear();
wake_sem=detail::win32::handle(0);
}
}
@@ -265,9 +293,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 +350,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)
{
@@ -367,4 +413,6 @@ namespace boost
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -3,12 +3,16 @@
// interlocked_read_win32.hpp
//
// (C) Copyright 2005-7 Anthony Williams
// (C) Copyright 2005-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/detail/interlocked.hpp>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
extern "C" void _ReadWriteBarrier(void);
@@ -46,8 +50,6 @@ namespace boost
#else
#include <boost/detail/interlocked.hpp>
namespace boost
{
namespace detail
@@ -73,5 +75,6 @@ namespace boost
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -10,6 +10,8 @@
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
@@ -18,7 +20,7 @@ namespace boost
}
class mutex:
boost::noncopyable,
boost::noncopyable,
public ::boost::detail::underlying_mutex
{
public:
@@ -32,7 +34,7 @@ namespace boost
}
typedef unique_lock<mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
};
typedef mutex try_mutex;
@@ -53,9 +55,11 @@ namespace boost
}
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef scoped_timed_lock scoped_try_lock;
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -18,6 +18,8 @@
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std
{
@@ -129,4 +131,6 @@ namespace boost
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -15,6 +15,8 @@
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class recursive_mutex:
@@ -32,7 +34,7 @@ namespace boost
}
typedef unique_lock<recursive_mutex> scoped_lock;
typedef scoped_lock scoped_try_lock;
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
};
typedef recursive_mutex recursive_try_mutex;
@@ -52,10 +54,11 @@ namespace boost
}
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
typedef scoped_timed_lock scoped_try_lock;
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -15,6 +15,8 @@
#include <boost/utility.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex:
@@ -23,12 +25,12 @@ namespace boost
private:
struct state_data
{
unsigned shared_count:11;
unsigned shared_waiting:11;
unsigned exclusive:1;
unsigned upgrade:1;
unsigned exclusive_waiting:7;
unsigned exclusive_waiting_blocked:1;
unsigned shared_count:11,
shared_waiting:11,
exclusive:1,
upgrade:1,
exclusive_waiting:7,
exclusive_waiting_blocked:1;
friend bool operator==(state_data const& lhs,state_data const& rhs)
{
@@ -89,7 +91,7 @@ namespace boost
bool try_lock_shared()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
@@ -104,14 +106,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
}
@@ -120,19 +114,18 @@ 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
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
for(;;)
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
@@ -151,14 +144,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
@@ -168,7 +153,7 @@ namespace boost
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
if(res==detail::win32::timeout)
{
do
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
@@ -190,14 +175,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
@@ -213,7 +190,7 @@ namespace boost
void unlock_shared()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
@@ -254,14 +231,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
void lock()
@@ -269,20 +238,45 @@ 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 try_lock()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
return false;
}
else
{
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
return true;
}
bool timed_lock(boost::system_time const& wait_until)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
for(;;)
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
@@ -302,14 +296,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(!old_state.shared_count && !old_state.exclusive)
{
@@ -318,14 +304,17 @@ namespace boost
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
if(wait_res==detail::win32::timeout)
{
do
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
if(!--new_state.exclusive_waiting)
{
new_state.exclusive_waiting_blocked=false;
}
}
}
else
@@ -340,14 +329,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
@@ -361,7 +342,7 @@ namespace boost
void unlock()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
new_state.exclusive=false;
@@ -379,30 +360,15 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
release_waiters(old_state);
}
void lock_upgrade()
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true)
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
for(;;)
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
@@ -422,14 +388,6 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
{
@@ -440,10 +398,36 @@ namespace boost
}
}
bool try_lock_upgrade()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
{
return false;
}
else
{
++new_state.shared_count;
new_state.upgrade=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
return true;
}
void unlock_upgrade()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
new_state.upgrade=false;
@@ -470,20 +454,12 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
void unlock_upgrade_and_lock()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
@@ -505,20 +481,12 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
void unlock_and_lock_upgrade()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
new_state.exclusive=false;
@@ -538,21 +506,13 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
release_waiters(old_state);
}
void unlock_and_lock_shared()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
new_state.exclusive=false;
@@ -571,21 +531,13 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
release_waiters(old_state);
}
void unlock_upgrade_and_lock_shared()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
new_state.upgrade=false;
@@ -603,19 +555,12 @@ namespace boost
}
old_state=current_state;
}
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4127)
#endif
while(true);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
release_waiters(old_state);
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,178 @@
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
// 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)
// (C) Copyright 2008 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/thread/thread_time.hpp>
#include "thread_primitives.hpp"
#include "thread_heap_alloc.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base;
void intrusive_ptr_add_ref(thread_data_base * p);
void intrusive_ptr_release(thread_data_base * p);
struct thread_data_base
{
long count;
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
thread_exit_callbacks(0),tss_data(0),
interruption_enabled(true),
id(0)
{}
virtual ~thread_data_base()
{}
friend void intrusive_ptr_add_ref(thread_data_base * p)
{
BOOST_INTERLOCKED_INCREMENT(&p->count);
}
friend void intrusive_ptr_release(thread_data_base * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
{
detail::heap_delete(p);
}
}
void interrupt()
{
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
}
typedef detail::win32::handle native_handle_type;
virtual void run()=0;
};
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
{
unsigned long start;
uintmax_t milliseconds;
bool relative;
boost::system_time abs_time;
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct remaining_time
{
bool more;
unsigned long milliseconds;
remaining_time(uintmax_t remaining):
more(remaining>max_non_infinite_wait),
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
{}
};
remaining_time remaining_milliseconds() const
{
if(is_sentinel())
{
return remaining_time(win32::infinite);
}
else if(relative)
{
unsigned long const now=win32::GetTickCount();
unsigned long const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}
else
{
system_time const now=get_system_time();
if(abs_time<=now)
{
return remaining_time(0);
}
return remaining_time((abs_time-now).total_milliseconds()+1);
}
}
bool is_sentinel() const
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
return timeout(sentinel_type());
}
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
}
namespace this_thread
{
void BOOST_THREAD_DECL yield();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline void interruptible_wait(unsigned long milliseconds)
{
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
}
inline void interruptible_wait(system_time const& abs_time)
{
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
}
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
{
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
}
inline void sleep(system_time const& abs_time)
{
interruptible_wait(abs_time);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -49,6 +49,8 @@ namespace boost
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
@@ -69,7 +71,7 @@ namespace boost
}
template<typename T>
T* heap_new()
inline T* heap_new()
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
@@ -84,8 +86,72 @@ namespace boost
}
}
#ifdef BOOST_HAS_RVALUE_REFS
template<typename T,typename A1>
T* heap_new(A1 a1)
inline T* heap_new(A1&& a1)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1&& a1,A2&& a2)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
#else
template<typename T,typename A1>
inline T* heap_new_impl(A1 a1)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
@@ -99,9 +165,9 @@ namespace boost
throw;
}
}
template<typename T,typename A1,typename A2>
T* heap_new(A1 a1,A2 a2)
inline T* heap_new_impl(A1 a1,A2 a2)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
@@ -117,7 +183,7 @@ namespace boost
}
template<typename T,typename A1,typename A2,typename A3>
T* heap_new(A1 a1,A2 a2,A3 a3)
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
@@ -131,9 +197,9 @@ namespace boost
throw;
}
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4)
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
@@ -147,9 +213,168 @@ namespace boost
throw;
}
}
template<typename T,typename A1>
inline T* heap_new(A1 const& a1)
{
return heap_new_impl<T,A1 const&>(a1);
}
template<typename T,typename A1>
inline T* heap_new(A1& a1)
{
return heap_new_impl<T,A1&>(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2 const& a2)
{
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2 const& a2)
{
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2& a2)
{
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2& a2)
{
return heap_new_impl<T,A1&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
#endif
template<typename T>
void heap_delete(T* data)
inline void heap_delete(T* data)
{
data->~T();
free_raw_heap_memory(data);
@@ -166,5 +391,7 @@ namespace boost
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -13,10 +13,12 @@
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/detail/interlocked.hpp>
#include <algorithm>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
namespace boost
{
namespace detail
@@ -62,7 +64,7 @@ namespace boost
# ifdef UNDER_CE
# ifndef WINAPI
# ifndef _WIN32_WCE_EMULATION
# define WINAPI __cdecl // Note this doesn't match the desktop definition
# define WINAPI __cdecl // Note this doesn't match the desktop definition
# else
# define WINAPI __stdcall
# endif
@@ -146,6 +148,8 @@ namespace boost
# error "Win32 functions not available"
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
@@ -277,5 +281,118 @@ namespace boost
}
}
#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
namespace boost
{
namespace detail
{
namespace win32
{
#if _MSC_VER==1400
extern "C" unsigned char _interlockedbittestandset(long *a,long b);
extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
#else
extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
#endif
#pragma intrinsic(_interlockedbittestandset)
#pragma intrinsic(_interlockedbittestandreset)
inline bool interlocked_bit_test_and_set(long* x,long bit)
{
return _interlockedbittestandset(x,bit)!=0;
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
{
return _interlockedbittestandreset(x,bit)!=0;
}
}
}
}
#define BOOST_THREAD_BTS_DEFINED
#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
namespace boost
{
namespace detail
{
namespace win32
{
inline bool interlocked_bit_test_and_set(long* x,long bit)
{
__asm {
mov eax,bit;
mov edx,x;
lock bts [edx],eax;
setc al;
};
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
{
__asm {
mov eax,bit;
mov edx,x;
lock btr [edx],eax;
setc al;
};
}
}
}
}
#define BOOST_THREAD_BTS_DEFINED
#endif
#ifndef BOOST_THREAD_BTS_DEFINED
namespace boost
{
namespace detail
{
namespace win32
{
inline bool interlocked_bit_test_and_set(long* x,long bit)
{
long const value=1<<bit;
long old=*x;
do
{
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old);
if(current==old)
{
break;
}
old=current;
}
while(true);
return (old&value)!=0;
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
{
long const value=1<<bit;
long old=*x;
do
{
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old);
if(current==old)
{
break;
}
old=current;
}
while(true);
return (old&value)!=0;
}
}
}
}
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,103 +0,0 @@
#ifndef BOOST_THREAD_WIN32_TSS_HPP
#define BOOST_THREAD_WIN32_TSS_HPP
// 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)
// (C) Copyright 2007 Anthony Williams
#include <boost/shared_ptr.hpp>
#include "thread_heap_alloc.hpp"
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}
explicit thread_specific_ptr(void (*func_)(T*)):
cleanup(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>())
{}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#endif

View File

@@ -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)
@@ -14,6 +14,8 @@
#include <boost/thread/thread_time.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
enum xtime_clock_types
@@ -56,7 +58,7 @@ struct xtime
inline xtime get_xtime(boost::system_time const& abs_time)
{
xtime res={0};
xtime res;
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds());
@@ -85,4 +87,6 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif //BOOST_XTIME_WEK070601_HPP

1
module.cmake Normal file
View File

@@ -0,0 +1 @@
boost_module(thread DEPENDS date_time bind optional range)

15
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,15 @@
if (WIN32)
set(THREAD_SOURCES win32/thread.cpp win32/exceptions.cpp win32/tss_dll.cpp
win32/tss_pe.cpp)
else (WIN32)
set(THREAD_SOURCES pthread/thread.cpp pthread/exceptions.cpp pthread/once.cpp)
endif (WIN32)
boost_add_library(
boost_thread
${THREAD_SOURCES}
SHARED_COMPILE_FLAGS "-DBOOST_THREAD_BUILD_DLL=1"
STATIC_COMPILE_FLAGS "-DBOOST_THREAD_BUILD_LIB=1"
NO_SINGLE_THREADED
)

0
src/pthread/once.cpp Executable file → Normal file
View File

View File

@@ -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 BOOST_HAS_UNISTD_H
#include <unistd.h>
#endif
@@ -28,6 +28,9 @@ namespace boost
{
namespace detail
{
thread_data_base::~thread_data_base()
{}
struct thread_exit_callback_node
{
boost::detail::thread_exit_function_base* func;
@@ -119,7 +122,7 @@ namespace boost
{
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
@@ -129,10 +132,12 @@ namespace boost
catch(thread_interrupted const&)
{
}
catch(...)
{
std::terminate();
}
// Removed as it stops the debugger identifying the cause of the exception
// Unhandled exceptions still cause the application to terminate
// catch(...)
// {
// std::terminate();
// }
detail::tls_destructor(thread_info.get());
detail::set_current_thread_data(0);
@@ -153,6 +158,10 @@ namespace boost
void run()
{}
private:
externally_launched_thread(externally_launched_thread&);
void operator=(externally_launched_thread&);
};
detail::thread_data_base* make_external_thread_data()
@@ -196,47 +205,6 @@ namespace boost
detach();
}
thread::thread(detail::thread_move_t<thread> x)
{
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& thread::operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> thread::move()
{
detail::thread_move_t<thread> x(*this);
return x;
}
void thread::swap(thread& x)
{
thread_info.swap(x.thread_info);
}
bool thread::operator==(const thread& other) const
{
return get_id()==other.get_id();
}
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 +329,61 @@ namespace boost
}
}
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)
void sleep(const system_time& st)
{
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)
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 +396,7 @@ namespace boost
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
#elif defined(__sun)
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#else
@@ -472,6 +444,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
@@ -607,85 +594,85 @@ namespace boost
}
}
thread_group::thread_group()
{
}
// 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_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();
}
// 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);
// 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);
}
// // 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);
// 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);
}
// // 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::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);
// 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();
// }
}

View File

@@ -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

View File

@@ -29,13 +29,26 @@ namespace boost
void create_current_thread_tls_key()
{
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
current_thread_tls_key=TlsAlloc();
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
}
void cleanup_tls_key()
{
if(current_thread_tls_key)
{
TlsFree(current_thread_tls_key);
current_thread_tls_key=0;
}
}
detail::thread_data_base* get_current_thread_data()
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
if(!current_thread_tls_key)
{
return 0;
}
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
}
@@ -81,25 +94,6 @@ namespace boost
}
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
@@ -160,30 +154,30 @@ namespace boost
}
}
set_current_thread_data(0);
}
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();
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&)
{
}
// Removed as it stops the debugger identifying the cause of the exception
// Unhandled exceptions still cause the application to terminate
// catch(...)
// {
// std::terminate();
// }
run_thread_exit_callbacks();
return 0;
}
catch(thread_interrupted const&)
{
}
catch(...)
{
std::terminate();
}
run_thread_exit_callbacks();
return 0;
}
thread::thread()
@@ -218,6 +212,9 @@ namespace boost
void run()
{}
private:
externally_launched_thread(externally_launched_thread&);
void operator=(externally_launched_thread&);
};
void make_external_thread_data()
@@ -244,36 +241,6 @@ namespace boost
detach();
}
thread::thread(detail::thread_move_t<thread> x)
{
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info=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());
@@ -592,7 +559,6 @@ namespace boost
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func.get())
@@ -620,7 +586,9 @@ extern "C" BOOST_THREAD_DECL void on_thread_enter()
{}
extern "C" BOOST_THREAD_DECL void on_process_exit()
{}
{
boost::cleanup_tls_key();
}
extern "C" BOOST_THREAD_DECL void on_thread_exit()
{

View File

@@ -26,11 +26,11 @@ namespace {
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
}
}
@@ -125,10 +125,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
#pragma section(".CRT$XCU",long,read)
#pragma section(".CRT$XTU",long,read)
#pragma section(".CRT$XLC",long,read)
static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
__declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
__declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
__declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
__declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
#else
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(push, old_seg)
@@ -168,6 +168,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
#pragma warning(push)
#pragma warning(disable:4189)
#endif
PVAPI on_tls_prepare(void)
{
//The following line has an important side effect:
@@ -239,15 +240,32 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
case DLL_THREAD_DETACH:
on_thread_exit();
break;
}
}
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
on_thread_exit();
break;
case DLL_PROCESS_DETACH:
on_process_exit();
break;
}
return true;
}
} //namespace
extern "C"
{
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
}
extern "C" void tss_cleanup_implemented(void)
{
/*

33
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,33 @@
boost_additional_test_dependencies(thread BOOST_DEPENDS test )
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)

View File

@@ -22,22 +22,24 @@ project
: 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 @@ rule thread-run ( sources )
[ 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 ]
;
}

View File

@@ -0,0 +1,15 @@
// 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)
#include <boost/thread/thread.hpp>
void do_nothing()
{}
void test()
{
boost::thread t1(do_nothing);
boost::thread t2;
t2=t1;
}

View File

@@ -0,0 +1,14 @@
// 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)
#include <boost/thread/thread.hpp>
void do_nothing()
{}
void test()
{
boost::thread t1(do_nothing);
boost::thread t2(t1);
}

View File

@@ -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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
// 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)
@@ -16,7 +16,7 @@ bool fake_predicate()
return false;
}
unsigned const timeout_seconds=5;
unsigned const timeout_seconds=2;
unsigned const timeout_grace=1;
boost::posix_time::milliseconds const timeout_resolution(100);
@@ -70,12 +70,96 @@ void do_test_relative_timed_wait_with_predicate_times_out()
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_timed_wait_relative_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
while(cond.timed_wait(lock,delay));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_timed_wait_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
while(cond.timed_wait(lock,timeout));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_timed_wait_with_predicate_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_relative_timed_wait_with_predicate_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
bool const res=cond.timed_wait(lock,delay,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_timed_wait_relative_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
while(cond.timed_wait(lock,delay));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void test_timed_wait_times_out()
{
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

523
test/test_generic_locks.cpp Normal file
View File

@@ -0,0 +1,523 @@
// (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)
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
void test_lock_two_uncontended()
{
boost::mutex m1,m2;
boost::mutex::scoped_lock l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
boost::lock(l1,l2);
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
}
struct wait_data
{
boost::mutex m;
bool flag;
boost::condition_variable cond;
wait_data():
flag(false)
{}
void wait()
{
boost::mutex::scoped_lock l(m);
while(!flag)
{
cond.wait(l);
}
}
template<typename Duration>
bool timed_wait(Duration d)
{
boost::system_time const target=boost::get_system_time()+d;
boost::mutex::scoped_lock l(m);
while(!flag)
{
if(!cond.timed_wait(l,target))
{
return flag;
}
}
return true;
}
void signal()
{
boost::mutex::scoped_lock l(m);
flag=true;
cond.notify_all();
}
};
void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
{
boost::lock_guard<boost::mutex> l1(*m1);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l2(*m2);
locked->signal();
quit->wait();
}
void lock_pair(boost::mutex* m1,boost::mutex* m2)
{
boost::lock(*m1,*m2);
boost::mutex::scoped_lock l1(*m1,boost::adopt_lock),
l2(*m2,boost::adopt_lock);
}
void test_lock_two_other_thread_locks_in_order()
{
boost::mutex m1,m2;
wait_data locked;
wait_data release;
boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_pair,&m1,&m2);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
t.join();
}
void test_lock_two_other_thread_locks_in_opposite_order()
{
boost::mutex m1,m2;
wait_data locked;
wait_data release;
boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_pair,&m2,&m1);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
t.join();
}
void test_lock_five_uncontended()
{
boost::mutex m1,m2,m3,m4,m5;
boost::mutex::scoped_lock l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock),
l3(m3,boost::defer_lock),
l4(m4,boost::defer_lock),
l5(m5,boost::defer_lock);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
BOOST_CHECK(!l4.owns_lock());
BOOST_CHECK(!l5.owns_lock());
boost::lock(l1,l2,l3,l4,l5);
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
BOOST_CHECK(l4.owns_lock());
BOOST_CHECK(l5.owns_lock());
}
void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
wait_data* locked,wait_data* quit)
{
boost::lock_guard<boost::mutex> l1(*m1);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l2(*m2);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l3(*m3);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l4(*m4);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l5(*m5);
locked->signal();
quit->wait();
}
void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
{
boost::lock(*m1,*m2,*m3,*m4,*m5);
m1->unlock();
m2->unlock();
m3->unlock();
m4->unlock();
m5->unlock();
}
void test_lock_five_other_thread_locks_in_order()
{
boost::mutex m1,m2,m3,m4,m5;
wait_data locked;
wait_data release;
boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
t.join();
}
void test_lock_five_other_thread_locks_in_different_order()
{
boost::mutex m1,m2,m3,m4,m5;
wait_data locked;
wait_data release;
boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
t.join();
}
void lock_n(boost::mutex* mutexes,unsigned count)
{
boost::lock(mutexes,mutexes+count);
for(unsigned i=0;i<count;++i)
{
mutexes[i].unlock();
}
}
void test_lock_ten_other_thread_locks_in_different_order()
{
unsigned const num_mutexes=10;
boost::mutex mutexes[num_mutexes];
wait_data locked;
wait_data release;
boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_n,mutexes,num_mutexes);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
t.join();
}
struct dummy_mutex
{
bool is_locked;
dummy_mutex():
is_locked(false)
{}
void lock()
{
is_locked=true;
}
bool try_lock()
{
if(is_locked)
{
return false;
}
is_locked=true;
return true;
}
void unlock()
{
is_locked=false;
}
};
namespace boost
{
template<>
struct is_mutex_type<dummy_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}
void test_lock_five_in_range()
{
unsigned const num_mutexes=5;
dummy_mutex mutexes[num_mutexes];
boost::lock(mutexes,mutexes+num_mutexes);
for(unsigned i=0;i<num_mutexes;++i)
{
BOOST_CHECK(mutexes[i].is_locked);
}
}
void test_lock_ten_in_range()
{
unsigned const num_mutexes=10;
dummy_mutex mutexes[num_mutexes];
boost::lock(mutexes,mutexes+num_mutexes);
for(unsigned i=0;i<num_mutexes;++i)
{
BOOST_CHECK(mutexes[i].is_locked);
}
}
void test_try_lock_two_uncontended()
{
dummy_mutex m1,m2;
int const res=boost::try_lock(m1,m2);
BOOST_CHECK(res==-1);
BOOST_CHECK(m1.is_locked);
BOOST_CHECK(m2.is_locked);
}
void test_try_lock_two_first_locked()
{
dummy_mutex m1,m2;
m1.lock();
boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock);
int const res=boost::try_lock(l1,l2);
BOOST_CHECK(res==0);
BOOST_CHECK(m1.is_locked);
BOOST_CHECK(!m2.is_locked);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
}
void test_try_lock_two_second_locked()
{
dummy_mutex m1,m2;
m2.lock();
boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock);
int const res=boost::try_lock(l1,l2);
BOOST_CHECK(res==1);
BOOST_CHECK(!m1.is_locked);
BOOST_CHECK(m2.is_locked);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
}
void test_try_lock_three()
{
int const num_mutexes=3;
for(int i=-1;i<num_mutexes;++i)
{
dummy_mutex mutexes[num_mutexes];
if(i>=0)
{
mutexes[i].lock();
}
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
l2(mutexes[1],boost::defer_lock),
l3(mutexes[2],boost::defer_lock);
int const res=boost::try_lock(l1,l2,l3);
BOOST_CHECK(res==i);
for(int j=0;j<num_mutexes;++j)
{
if((i==j) || (i==-1))
{
BOOST_CHECK(mutexes[j].is_locked);
}
else
{
BOOST_CHECK(!mutexes[j].is_locked);
}
}
if(i==-1)
{
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
}
else
{
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
}
}
}
void test_try_lock_four()
{
int const num_mutexes=4;
for(int i=-1;i<num_mutexes;++i)
{
dummy_mutex mutexes[num_mutexes];
if(i>=0)
{
mutexes[i].lock();
}
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
l2(mutexes[1],boost::defer_lock),
l3(mutexes[2],boost::defer_lock),
l4(mutexes[3],boost::defer_lock);
int const res=boost::try_lock(l1,l2,l3,l4);
BOOST_CHECK(res==i);
for(int j=0;j<num_mutexes;++j)
{
if((i==j) || (i==-1))
{
BOOST_CHECK(mutexes[j].is_locked);
}
else
{
BOOST_CHECK(!mutexes[j].is_locked);
}
}
if(i==-1)
{
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
BOOST_CHECK(l4.owns_lock());
}
else
{
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
BOOST_CHECK(!l4.owns_lock());
}
}
}
void test_try_lock_five()
{
int const num_mutexes=5;
for(int i=-1;i<num_mutexes;++i)
{
dummy_mutex mutexes[num_mutexes];
if(i>=0)
{
mutexes[i].lock();
}
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
l2(mutexes[1],boost::defer_lock),
l3(mutexes[2],boost::defer_lock),
l4(mutexes[3],boost::defer_lock),
l5(mutexes[4],boost::defer_lock);
int const res=boost::try_lock(l1,l2,l3,l4,l5);
BOOST_CHECK(res==i);
for(int j=0;j<num_mutexes;++j)
{
if((i==j) || (i==-1))
{
BOOST_CHECK(mutexes[j].is_locked);
}
else
{
BOOST_CHECK(!mutexes[j].is_locked);
}
}
if(i==-1)
{
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
BOOST_CHECK(l4.owns_lock());
BOOST_CHECK(l5.owns_lock());
}
else
{
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
BOOST_CHECK(!l4.owns_lock());
BOOST_CHECK(!l5.owns_lock());
}
}
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order));
test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order));
test->add(BOOST_TEST_CASE(&test_lock_five_uncontended));
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
test->add(BOOST_TEST_CASE(&test_lock_ten_in_range));
test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked));
test->add(BOOST_TEST_CASE(&test_try_lock_three));
test->add(BOOST_TEST_CASE(&test_try_lock_four));
test->add(BOOST_TEST_CASE(&test_try_lock_five));
return test;
}

View File

@@ -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,10 @@
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_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
@@ -22,6 +25,180 @@ struct test_initially_locked
}
};
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_try_lock_if_other_thread_has_unique_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m,boost::try_to_lock);
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()()
{
boost::unique_lock<Mutex> lock(m);
typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_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_locked_if_other_thread_has_shared_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_initially_locked_if_other_thread_has_shared_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()()
{
boost::shared_lock<Mutex> lock(m);
typedef test_initially_locked_if_other_thread_has_shared_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
{
@@ -89,6 +266,64 @@ struct test_locked_after_try_lock_called
}
};
template<typename Mutex,typename Lock>
struct test_unlocked_after_try_lock_if_other_thread_has_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_unlocked_after_try_lock_if_other_thread_has_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m,boost::defer_lock);
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_unlocked_after_try_lock_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_throws_if_lock_called_when_already_locked
{
@@ -125,11 +360,53 @@ struct test_throws_if_unlock_called_when_already_unlocked
BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
}
};
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
template<typename Lock>
struct test_default_constructed_has_no_mutex_and_unlocked
{
typedef typename Mutex::scoped_lock Lock;
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;
Mutex m3;
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);
l1.swap(Lock(m3));
BOOST_CHECK_EQUAL(l1.mutex(),&m3);
}
};
template<typename Mutex,typename Lock>
void test_lock_is_scoped_lock_concept_for_mutex()
{
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 +414,117 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
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>()();
test_locked_after_try_lock_called<Mutex,Lock>()();
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
{
typedef typename Mutex::scoped_lock Lock;
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex)
{
typedef boost::unique_lock<Mutex> Lock;
test_lock_is_scoped_lock_concept_for_mutex<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>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_locked_after_try_lock_called<Mutex,Lock>()();
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
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>()();
}
struct dummy_shared_mutex
{
bool locked;
bool shared_locked;
bool shared_unlocked;
bool shared_timed_locked_relative;
bool shared_timed_locked_absolute;
bool timed_locked_relative;
bool timed_locked_absolute;
dummy_shared_mutex():
locked(false),shared_locked(false),shared_unlocked(false),
shared_timed_locked_relative(false),
shared_timed_locked_absolute(false),
timed_locked_relative(false),
timed_locked_absolute(false)
{}
void lock()
{
locked=true;
}
void lock_shared()
{
shared_locked=true;
}
void unlock()
{}
void unlock_shared()
{
shared_unlocked=true;
}
bool timed_lock_shared(boost::system_time)
{
shared_timed_locked_absolute=true;
return false;
}
template<typename Duration>
bool timed_lock_shared(Duration)
{
shared_timed_locked_relative=true;
return false;
}
bool timed_lock(boost::system_time)
{
timed_locked_absolute=true;
return false;
}
template<typename Duration>
bool timed_lock(Duration)
{
timed_locked_relative=true;
return false;
}
};
void test_shared_lock()
{
typedef boost::shared_mutex Mutex;
typedef boost::shared_lock<Mutex> Lock;
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
test_initially_locked_if_other_thread_has_shared_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 +533,17 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
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>()();
dummy_shared_mutex dummy;
boost::shared_lock<dummy_shared_mutex> lk(dummy);
BOOST_CHECK(dummy.shared_locked);
lk.unlock();
BOOST_CHECK(dummy.shared_unlocked);
lk.timed_lock(boost::posix_time::milliseconds(5));
BOOST_CHECK(dummy.shared_timed_locked_relative);
lk.timed_lock(boost::get_system_time());
BOOST_CHECK(dummy.shared_timed_locked_absolute);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
@@ -160,14 +552,20 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types;
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types));
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
boost::recursive_try_mutex,boost::recursive_timed_mutex> try_mutex_types;
boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,try_mutex_types));
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
test->add(BOOST_TEST_CASE(&test_shared_lock));
return test;
}

View File

@@ -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 @@ void test_thread_move_from_lvalue_on_construction()
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 @@ void test_unique_lock_move_from_lvalue_on_construction()
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 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
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;
}

View File

@@ -7,6 +7,7 @@
#include <boost/thread/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/condition.hpp>
@@ -96,6 +97,86 @@ struct test_trylock
}
};
template<typename Mutex>
struct test_lock_times_out_if_other_thread_has_lock
{
typedef boost::unique_lock<Mutex> Lock;
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_lock_times_out_if_other_thread_has_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m,boost::defer_lock);
lock.timed_lock(boost::posix_time::milliseconds(50));
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
void locking_thread_through_constructor()
{
Lock lock(m,boost::posix_time::milliseconds(50));
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
bool is_done() const
{
return done;
}
typedef test_lock_times_out_if_other_thread_has_lock<Mutex> this_type;
void do_test(void (this_type::*test_func)())
{
Lock lock(m);
locked=false;
done=false;
boost::thread t(test_func,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;
}
}
void operator()()
{
do_test(&this_type::locking_thread);
do_test(&this_type::locking_thread_through_constructor);
}
};
template <typename M>
struct test_timedlock
{
@@ -109,6 +190,8 @@ struct test_timedlock
void operator()()
{
test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
mutex_type mutex;
boost::condition condition;
@@ -178,6 +261,7 @@ struct test_recursive_lock
}
};
void do_test_mutex()
{
test_lock<boost::mutex>()();

View File

@@ -17,7 +17,7 @@
void test_multiple_readers()
{
unsigned const number_of_threads=100;
unsigned const number_of_threads=10;
boost::thread_group pool;
@@ -64,7 +64,7 @@ void test_multiple_readers()
void test_only_one_writer_permitted()
{
unsigned const number_of_threads=100;
unsigned const number_of_threads=10;
boost::thread_group pool;
@@ -164,7 +164,7 @@ void test_unlocking_writer_unblocks_all_readers()
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
unsigned const reader_count=10;
try
{
@@ -218,8 +218,8 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
boost::mutex finish_writing_mutex;
boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
unsigned const reader_count=100;
unsigned const writer_count=100;
unsigned const reader_count=10;
unsigned const writer_count=10;
try
{

View File

@@ -15,10 +15,41 @@
BOOST_CHECK_EQUAL(value,expected_value); \
}
class simple_upgrade_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
void operator=(simple_upgrade_thread&);
public:
simple_upgrade_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::upgrade_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
void test_only_one_upgrade_lock_permitted()
{
unsigned const number_of_threads=100;
unsigned const number_of_threads=10;
boost::thread_group pool;
@@ -71,7 +102,7 @@ void test_can_lock_upgrade_if_currently_locked_shared()
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
unsigned const reader_count=10;
try
{
@@ -107,40 +138,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()
{
@@ -164,6 +161,29 @@ void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
writer.join();
}
void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
finish_lock.unlock();
writer.join();
}
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
@@ -175,38 +195,15 @@ void test_if_no_thread_has_lock_try_lock_shared_returns_true()
}
}
namespace
void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
{
class simple_reading_thread
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
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);
}
};
rw_mutex.unlock_upgrade();
}
}
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
@@ -232,32 +229,51 @@ 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()
void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
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)
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
rw_mutex.unlock_upgrade();
}
finish_lock.unlock();
writer.join();
}
void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
finish_lock.unlock();
writer.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
@@ -269,7 +285,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;
}

View File

@@ -0,0 +1,268 @@
// (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();
}
void test_timed_lock_times_out_but_read_lock_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::this_thread::sleep(boost::posix_time::seconds(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);
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
boost::posix_time::milliseconds const wait_duration(500);
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
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));
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held));
return test;
}

View File

@@ -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 @@ void test_timed_join()
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 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
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;
}

View File

@@ -0,0 +1,226 @@
// 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/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);
}
int nfoa_res=0;
void normal_function_one_arg(int i)
{
nfoa_res=i;
}
void test_thread_function_one_argument()
{
boost::thread function(normal_function_one_arg,42);
function.join();
BOOST_CHECK_EQUAL(42,nfoa_res);
}
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()
{
callable_one_arg func;
boost::thread callable(func,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);
}
callable_multiple_arg func;
boost::thread callable3(func,"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(func,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);
}
struct X
{
bool function_called;
int arg_value;
X():
function_called(false),
arg_value(0)
{}
void f0()
{
function_called=true;
}
void f1(int i)
{
arg_value=i;
}
};
void test_thread_member_function_no_arguments()
{
X x;
boost::thread function(&X::f0,&x);
function.join();
BOOST_CHECK(x.function_called);
}
void test_thread_member_function_one_argument()
{
X x;
boost::thread function(&X::f1,&x,42);
function.join();
BOOST_CHECK_EQUAL(42,x.arg_value);
}
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_function_one_argument));
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));
test->add(BOOST_TEST_CASE(test_thread_member_function_no_arguments));
test->add(BOOST_TEST_CASE(test_thread_member_function_one_argument));
return test;
}

134
test/test_thread_mf.cpp Normal file
View File

@@ -0,0 +1,134 @@
//
// Copyright (C) 2008 Peter Dimov
//
// 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/detail/lightweight_test.hpp>
struct X
{
mutable unsigned int hash;
X(): hash(0) {}
int f0() { f1(17); return 0; }
int g0() const { g1(17); return 0; }
int f1(int a1) { hash = (hash * 17041 + a1) % 32768; return 0; }
int g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; return 0; }
int f2(int a1, int a2) { f1(a1); f1(a2); return 0; }
int g2(int a1, int a2) const { g1(a1); g1(a2); return 0; }
int f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); return 0; }
int g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); return 0; }
int f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); return 0; }
int g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); return 0; }
int f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); return 0; }
int g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); return 0; }
int f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); return 0; }
int g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); return 0; }
int f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); return 0; }
int g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); return 0; }
int f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); return 0; }
int g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); return 0; }
};
int main()
{
X x;
// 0
boost::thread( &X::f0, &x ).join();
boost::thread( &X::f0, boost::ref(x) ).join();
boost::thread( &X::g0, &x ).join();
boost::thread( &X::g0, x ).join();
boost::thread( &X::g0, boost::ref(x) ).join();
// 1
boost::thread( &X::f1, &x, 1 ).join();
boost::thread( &X::f1, boost::ref(x), 1 ).join();
boost::thread( &X::g1, &x, 1 ).join();
boost::thread( &X::g1, x, 1 ).join();
boost::thread( &X::g1, boost::ref(x), 1 ).join();
// 2
boost::thread( &X::f2, &x, 1, 2 ).join();
boost::thread( &X::f2, boost::ref(x), 1, 2 ).join();
boost::thread( &X::g2, &x, 1, 2 ).join();
boost::thread( &X::g2, x, 1, 2 ).join();
boost::thread( &X::g2, boost::ref(x), 1, 2 ).join();
// 3
boost::thread( &X::f3, &x, 1, 2, 3 ).join();
boost::thread( &X::f3, boost::ref(x), 1, 2, 3 ).join();
boost::thread( &X::g3, &x, 1, 2, 3 ).join();
boost::thread( &X::g3, x, 1, 2, 3 ).join();
boost::thread( &X::g3, boost::ref(x), 1, 2, 3 ).join();
// 4
boost::thread( &X::f4, &x, 1, 2, 3, 4 ).join();
boost::thread( &X::f4, boost::ref(x), 1, 2, 3, 4 ).join();
boost::thread( &X::g4, &x, 1, 2, 3, 4 ).join();
boost::thread( &X::g4, x, 1, 2, 3, 4 ).join();
boost::thread( &X::g4, boost::ref(x), 1, 2, 3, 4 ).join();
// 5
boost::thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
boost::thread( &X::f5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
boost::thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join();
boost::thread( &X::g5, x, 1, 2, 3, 4, 5 ).join();
boost::thread( &X::g5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
// 6
boost::thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join();
boost::thread( &X::f6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
boost::thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join();
boost::thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join();
boost::thread( &X::g6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
// 7
boost::thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join();
boost::thread( &X::f7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
boost::thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join();
boost::thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join();
boost::thread( &X::g7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
// 8
boost::thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
boost::thread( &X::f8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
boost::thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
boost::thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
boost::thread( &X::g8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
BOOST_TEST( x.hash == 23558 );
return boost::report_errors();
}

View File

@@ -5,26 +5,59 @@
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
void do_nothing()
{}
void do_nothing(boost::thread::id* my_id)
{
*my_id=boost::this_thread::get_id();
}
void test_move_on_construction()
{
boost::thread x=boost::thread(do_nothing);
boost::thread::id the_id;
boost::thread x=boost::thread(do_nothing,&the_id);
boost::thread::id x_id=x.get_id();
x.join();
BOOST_CHECK_EQUAL(the_id,x_id);
}
boost::thread make_thread()
boost::thread make_thread(boost::thread::id* the_id)
{
return boost::thread(do_nothing);
return boost::thread(do_nothing,the_id);
}
void test_move_from_function_return()
{
boost::thread x=make_thread();
boost::thread::id the_id;
boost::thread x=make_thread(&the_id);
boost::thread::id x_id=x.get_id();
x.join();
BOOST_CHECK_EQUAL(the_id,x_id);
}
boost::thread make_thread_return_lvalue(boost::thread::id* the_id)
{
boost::thread t(do_nothing,the_id);
return boost::move(t);
}
void test_move_from_function_return_lvalue()
{
boost::thread::id the_id;
boost::thread x=make_thread_return_lvalue(&the_id);
boost::thread::id x_id=x.get_id();
x.join();
BOOST_CHECK_EQUAL(the_id,x_id);
}
void test_move_assign()
{
boost::thread::id the_id;
boost::thread x(do_nothing,&the_id);
boost::thread y;
y=boost::move(x);
boost::thread::id y_id=y.get_id();
y.join();
BOOST_CHECK_EQUAL(the_id,y_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
@@ -33,5 +66,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
test->add(BOOST_TEST_CASE(test_move_on_construction));
test->add(BOOST_TEST_CASE(test_move_from_function_return));
test->add(BOOST_TEST_CASE(test_move_from_function_return_lvalue));
test->add(BOOST_TEST_CASE(test_move_assign));
return test;
}

View File

@@ -258,11 +258,58 @@ void do_test_tss_does_no_cleanup_after_release()
}
}
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 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
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;
}

View File

@@ -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)
@@ -9,6 +10,8 @@
#include <boost/thread/xtime.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
void test_xtime_cmp()
{
@@ -53,6 +56,45 @@ void test_xtime_get()
}
}
void test_xtime_mutex_backwards_compatibility()
{
boost::timed_mutex m;
BOOST_CHECK(m.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))));
m.unlock();
boost::timed_mutex::scoped_timed_lock lk(m,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
BOOST_CHECK(lk.owns_lock());
if(lk.owns_lock())
{
lk.unlock();
}
BOOST_CHECK(lk.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))));
if(lk.owns_lock())
{
lk.unlock();
}
}
bool predicate()
{
return false;
}
void test_xtime_condvar_backwards_compatibility()
{
boost::condition_variable cond;
boost::condition_variable_any cond_any;
boost::mutex m;
boost::mutex::scoped_lock lk(m);
cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate);
cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
@@ -60,6 +102,8 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
test->add(BOOST_TEST_CASE(&test_xtime_cmp));
test->add(BOOST_TEST_CASE(&test_xtime_get));
test->add(BOOST_TEST_CASE(&test_xtime_mutex_backwards_compatibility));
test->add(BOOST_TEST_CASE(&test_xtime_condvar_backwards_compatibility));
return test;
}