2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 21:52:07 +00:00

Compare commits

...

40 Commits

Author SHA1 Message Date
Daniel James
44768abcac Branch for adding initializer list support (only in the unreleased gcc 4.4 at the moment).
[SVN r48931]
2008-09-23 19:45:43 +00:00
Anthony Williams
8fd0dd0cc0 Define a raw DLL main which is called by the C runtime if we're statically linked into a DLL --- fix for issue #2199
[SVN r48537]
2008-09-02 16:56:57 +00:00
Anthony Williams
8eea5811ba Don't allocate TLS Key unless we need it; deallocate it on process exit --- partial fix for bug #2199
[SVN r48536]
2008-09-02 16:54:56 +00:00
Anthony Williams
a154c2adab Removed locked and get_active_count
[SVN r48531]
2008-09-02 10:38:17 +00:00
Anthony Williams
10bf4ed576 Removed locked and get_active_count
[SVN r48530]
2008-09-02 10:38:04 +00:00
Anthony Williams
60d12dd395 Added recursive_mutex/condition::wait() change to list of breaking changes
[SVN r48528]
2008-09-02 10:22:06 +00:00
Anthony Williams
b4e9be3c52 Added missing relative time constructor to unique_lock
[SVN r48213]
2008-08-19 10:26:53 +00:00
Anthony Williams
dcebae6d4a Renamed internal bind stuff to invoker, as more expressive
[SVN r48209]
2008-08-19 07:03:22 +00:00
Anthony Williams
0d776bcd26 Updated changes list
[SVN r48037]
2008-08-08 20:37:30 +00:00
Anthony Williams
2d6ed47cf2 Updated signature of create_thread
[SVN r48036]
2008-08-08 20:21:29 +00:00
Anthony Williams
ea06434425 Doc updates missed by previous checkin
[SVN r47826]
2008-07-26 08:37:55 +00:00
Anthony Williams
6508eff95e Added note about max number of arguments
[SVN r47818]
2008-07-25 22:22:58 +00:00
Anthony Williams
69930684a9 Added a description for the new thread constructors that allow functions with arguments.
[SVN r47817]
2008-07-25 22:21:05 +00:00
Anthony Williams
b1931a3eda Fix for trac issue #2118
[SVN r47816]
2008-07-25 22:01:04 +00:00
Anthony Williams
63b44d4e32 Added documentation for the lock and try_lock free functions
[SVN r47815]
2008-07-25 21:57:33 +00:00
Anthony Williams
f7cb8d8141 Added a description for the scoped_try_lock typedefs
[SVN r47814]
2008-07-25 21:30:37 +00:00
Anthony Williams
48c857e02c Fix for issue #2105: specify which header to include for each class or function
[SVN r47810]
2008-07-25 21:12:29 +00:00
Anthony Williams
442dc58e0f Use sysconf(_SC_NPROCESSORS_ONLN) where it is available, as a fallback
[SVN r47654]
2008-07-21 10:39:50 +00:00
Anthony Williams
25460c652c Use sysconf to detect number of processors on AIX too
[SVN r47653]
2008-07-21 10:25:08 +00:00
Anthony Williams
31a98f0a1e BOOST_NO_SFINAE isn't enough to identify compilers that can't auto-detect mutexes, so create a new macro for that, and add IBM and Sun compilers to list
[SVN r47652]
2008-07-21 10:04:26 +00:00
Anthony Williams
36c44b6f45 Borland-specific fixes should apply to all compilers for which enable_if is broken: check for BOOST_NO_SFINAE instead
[SVN r47554]
2008-07-18 13:42:10 +00:00
Anthony Williams
27426b18d1 Split lock and try_lock into mutex and range overloads without using enable_if, so it works on Borland compilers
[SVN r47472]
2008-07-16 14:41:09 +00:00
Anthony Williams
3ea9ce1c8c Fixes to make basic thread functionality work with Borland compilers again
[SVN r47471]
2008-07-16 13:19:43 +00:00
Anthony Williams
4dfc636c84 test and fix for issue #2080
[SVN r47199]
2008-07-07 22:19:28 +00:00
Anthony Williams
5fe4312c6c test and fix for issue #2081
[SVN r47197]
2008-07-07 22:04:10 +00:00
Anthony Williams
63e675a6bb Corrected description to avoid reference to arguments
[SVN r47172]
2008-07-07 07:30:27 +00:00
Anthony Williams
e92aeac7d7 Added notify functions to class synopsis
[SVN r47171]
2008-07-07 07:28:32 +00:00
Anthony Williams
f1f7eac1f2 Backwards compatibility with xtime --- test and fix for issue #2052
[SVN r47149]
2008-07-06 21:58:11 +00:00
Anthony Williams
eff0c84553 Test and fix for issue #2076
[SVN r47120]
2008-07-05 21:55:36 +00:00
Anthony Williams
58c8ce61c7 Fix for issue #2065
[SVN r47077]
2008-07-04 15:45:52 +00:00
Anthony Williams
6ac5e6953a Qualify everything with boost:: to try and avoid name clashes on AIX
[SVN r47070]
2008-07-04 07:30:35 +00:00
Anthony Williams
5d9ad59af2 Use rvalue refs for move semantics of unique_lock where available
[SVN r47033]
2008-07-03 09:16:49 +00:00
Anthony Williams
3c48a05437 Added try_lock_upgrade to shared_mutex: second half of #1867 fix
[SVN r46961]
2008-07-01 16:28:06 +00:00
Anthony Williams
4462124ff2 Added try_lock_upgrade to shared_mutex: second half of #1867 fix
[SVN r46960]
2008-07-01 16:27:59 +00:00
Anthony Williams
373f557ef7 Reduced thread counts to make tests run faster
[SVN r46958]
2008-07-01 16:22:47 +00:00
Anthony Williams
495e561398 Partial fix for issue #1867 - ensure boost::shared_mutex supports try_lock
[SVN r46956]
2008-07-01 16:04:51 +00:00
Anthony Williams
d24a579033 Partial fix for issue #1867 - ensure boost::shared_mutex supports try_lock
[SVN r46955]
2008-07-01 16:04:43 +00:00
Anthony Williams
77130424b4 Removed tabs from source files
[SVN r46706]
2008-06-26 06:43:30 +00:00
Anthony Williams
eb30688937 Added license and copyright to docs
[SVN r46705]
2008-06-26 06:41:00 +00:00
Anthony Williams
880bac0633 Added missing include of detail/config.hpp
[SVN r46624]
2008-06-23 12:14:58 +00:00
38 changed files with 1789 additions and 469 deletions

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
@@ -54,4 +77,7 @@ been moved to __thread_id__.
* __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,6 +378,8 @@ object passed to the constructor.]]
[section:unique_lock Class template `unique_lock`]
#include <boost/thread/locks.hpp>
template<typename Lockable>
class unique_lock
{
@@ -610,6 +621,8 @@ __owns_lock_ref__ returns `false`.]]
[section:shared_lock Class template `shared_lock`]
#include <boost/thread/locks.hpp>
template<typename Lockable>
class shared_lock
{
@@ -843,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
{
@@ -890,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
{
@@ -914,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
{
@@ -17,7 +26,7 @@
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
@@ -44,6 +53,8 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
[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.
@@ -52,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
{
@@ -71,7 +84,7 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
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;
};
@@ -99,6 +112,8 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
[section:recursive_mutex Class `recursive_mutex`]
#include <boost/thread/recursive_mutex.hpp>
class recursive_mutex:
boost::noncopyable
{
@@ -114,7 +129,7 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
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
@@ -143,6 +158,8 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
[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.
@@ -151,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
{
@@ -171,7 +190,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
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;
};

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`]]

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]
@@ -158,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:
@@ -167,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);
@@ -243,6 +255,30 @@ not of type __thread_interrupted__, then `std::terminate()` will be called.]]
[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();
@@ -473,6 +509,8 @@ value as `this->get_id()` prior to the call.]]
[section:non_member_swap Non-member function `swap()`]
#include <boost/thread/thread.hpp>
void swap(thread& lhs,thread& rhs);
[variablelist
@@ -486,6 +524,8 @@ value as `this->get_id()` prior to the call.]]
[section:id Class `boost::thread::id`]
#include <boost/thread/thread.hpp>
class thread::id
{
public:
@@ -634,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();
@@ -651,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();
@@ -668,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();
@@ -685,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();
@@ -702,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>
@@ -722,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();
@@ -739,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
@@ -790,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
@@ -844,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.]]
@@ -864,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
{
@@ -871,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();
@@ -908,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

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: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
@@ -40,6 +47,8 @@ date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] c
[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.
@@ -48,6 +57,8 @@ See the documentation for [link date_time.posix_time.ptime_class `boost::posix_t
[section:get_system_time Non-member function `get_system_time()`]
#include <boost/thread/thread_time.hpp>
system_time get_system_time();
[variablelist

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

@@ -6,8 +6,10 @@
#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>
@@ -37,11 +39,13 @@ namespace boost
};
}
#ifndef BOOST_NO_SFINAE
template<typename T>
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, detail::thread_move_t<T> >::type move(T& t)
{
return t;
}
#endif
template<typename T>
detail::thread_move_t<T> move(detail::thread_move_t<T> t)

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

@@ -172,6 +172,14 @@ namespace boost
return static_cast<thread&&>(*this);
}
#else
#ifdef BOOST_NO_SFINAE
template <class F>
explicit thread(F f):
thread_info(make_thread_info(f))
{
start_thread();
}
#else
template <class F>
explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
@@ -179,9 +187,10 @@ namespace boost
{
start_thread();
}
#endif
template <class F>
thread(detail::thread_move_t<F> f):
explicit thread(detail::thread_move_t<F> f):
thread_info(make_thread_info(f))
{
start_thread();

View File

@@ -10,12 +10,21 @@
#include <algorithm>
#include <iterator>
#include <boost/thread/thread_time.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
struct xtime;
#if defined(BOOST_NO_SFINAE) || \
BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \
BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
#endif
#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
namespace detail
{
template<typename T>
@@ -77,7 +86,13 @@ namespace boost
detail::has_member_try_lock<T>::value);
};
#else
template<typename T>
struct is_mutex_type
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
#endif
struct defer_lock_t
{};
@@ -96,6 +111,74 @@ namespace boost
template<typename Mutex>
class upgrade_lock;
template<typename Mutex>
class unique_lock;
namespace detail
{
template<typename Mutex>
class try_lock_wrapper;
}
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
template<typename T>
struct is_mutex_type<unique_lock<T> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<typename T>
struct is_mutex_type<shared_lock<T> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<typename T>
struct is_mutex_type<upgrade_lock<T> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<typename T>
struct is_mutex_type<detail::try_lock_wrapper<T> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
class mutex;
class timed_mutex;
class recursive_mutex;
class recursive_timed_mutex;
class shared_mutex;
template<>
struct is_mutex_type<mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_mutex_type<timed_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_mutex_type<recursive_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_mutex_type<recursive_timed_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_mutex_type<shared_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
#endif
template<typename Mutex>
class lock_guard
{
@@ -126,8 +209,10 @@ namespace boost
private:
Mutex* m;
bool is_locked;
explicit unique_lock(unique_lock&);
unique_lock(unique_lock&);
explicit unique_lock(upgrade_lock<Mutex>&);
unique_lock& operator=(unique_lock&);
unique_lock& operator=(upgrade_lock<Mutex>& other);
public:
unique_lock():
m(0),is_locked(false)
@@ -149,11 +234,51 @@ namespace boost
{
try_lock();
}
template<typename TimeDuration>
unique_lock(Mutex& m_,TimeDuration const& target_time):
m(&m_),is_locked(false)
{
timed_lock(target_time);
}
unique_lock(Mutex& m_,system_time const& target_time):
m(&m_),is_locked(false)
{
timed_lock(target_time);
}
#ifdef BOOST_HAS_RVALUE_REFS
unique_lock(unique_lock&& other):
m(other.m),is_locked(other.is_locked)
{
other.is_locked=false;
other.m=0;
}
explicit unique_lock(upgrade_lock<Mutex>&& other);
unique_lock<Mutex>&& move()
{
return static_cast<unique_lock<Mutex>&&>(*this);
}
unique_lock& operator=(unique_lock<Mutex>&& other)
{
unique_lock temp(other);
swap(temp);
return *this;
}
unique_lock& operator=(upgrade_lock<Mutex>&& other)
{
unique_lock temp(other);
swap(temp);
return *this;
}
void swap(unique_lock&& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
#else
unique_lock(detail::thread_move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
@@ -185,7 +310,6 @@ namespace boost
swap(temp);
return *this;
}
void swap(unique_lock& other)
{
std::swap(m,other.m);
@@ -196,6 +320,7 @@ namespace boost
std::swap(m,other->m);
std::swap(is_locked,other->is_locked);
}
#endif
~unique_lock()
{
@@ -234,6 +359,11 @@ namespace boost
is_locked=m->timed_lock(absolute_time);
return is_locked;
}
bool timed_lock(::boost::xtime const& absolute_time)
{
is_locked=m->timed_lock(absolute_time);
return is_locked;
}
void unlock()
{
if(!owns_lock())
@@ -275,11 +405,27 @@ namespace boost
friend class upgrade_lock<Mutex>;
};
#ifdef BOOST_HAS_RVALUE_REFS
template<typename Mutex>
void swap(unique_lock<Mutex>&& lhs,unique_lock<Mutex>&& rhs)
{
lhs.swap(rhs);
}
#else
template<typename Mutex>
void swap(unique_lock<Mutex>& lhs,unique_lock<Mutex>& rhs)
{
lhs.swap(rhs);
}
#endif
#ifdef BOOST_HAS_RVALUE_REFS
template<typename Mutex>
inline unique_lock<Mutex>&& move(unique_lock<Mutex>&& ul)
{
return ul;
}
#endif
template<typename Mutex>
class shared_lock
@@ -378,11 +524,29 @@ namespace boost
return *this;
}
#ifdef BOOST_HAS_RVALUE_REFS
void swap(shared_lock&& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
#else
void swap(shared_lock& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
void swap(boost::detail::thread_move_t<shared_lock<Mutex> > other)
{
std::swap(m,other->m);
std::swap(is_locked,other->is_locked);
}
#endif
Mutex* mutex() const
{
return m;
}
~shared_lock()
{
@@ -418,6 +582,16 @@ namespace boost
is_locked=m->timed_lock_shared(target_time);
return is_locked;
}
template<typename Duration>
bool timed_lock(Duration const& target_time)
{
if(owns_lock())
{
throw boost::lock_error();
}
is_locked=m->timed_lock_shared(target_time);
return is_locked;
}
void unlock()
{
if(!owns_lock())
@@ -428,7 +602,7 @@ namespace boost
is_locked=false;
}
typedef void (shared_lock::*bool_type)();
typedef void (shared_lock<Mutex>::*bool_type)();
operator bool_type() const
{
return is_locked?&shared_lock::lock:0;
@@ -444,6 +618,20 @@ namespace boost
};
#ifdef BOOST_HAS_RVALUE_REFS
template<typename Mutex>
void swap(shared_lock<Mutex>&& lhs,shared_lock<Mutex>&& rhs)
{
lhs.swap(rhs);
}
#else
template<typename Mutex>
void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs)
{
lhs.swap(rhs);
}
#endif
template<typename Mutex>
class upgrade_lock
{
@@ -576,6 +764,18 @@ namespace boost
};
#ifdef BOOST_HAS_RVALUE_REFS
template<typename Mutex>
unique_lock<Mutex>::unique_lock(upgrade_lock<Mutex>&& other):
m(other.m),is_locked(other.is_locked)
{
other.is_locked=false;
if(is_locked)
{
m.unlock_upgrade_and_lock();
}
}
#else
template<typename Mutex>
unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
@@ -586,7 +786,7 @@ namespace boost
m->unlock_upgrade_and_lock();
}
}
#endif
template <class Mutex>
class upgrade_to_unique_lock
{
@@ -685,6 +885,12 @@ namespace boost
return *this;
}
#ifdef BOOST_HAS_RVALUE_REFS
void swap(try_lock_wrapper&& other)
{
base::swap(other);
}
#else
void swap(try_lock_wrapper& other)
{
base::swap(other);
@@ -693,6 +899,7 @@ namespace boost
{
base::swap(*other);
}
#endif
void lock()
{
@@ -726,15 +933,23 @@ namespace boost
typedef typename base::bool_type bool_type;
operator bool_type() const
{
return static_cast<base const&>(*this);
return base::operator bool_type();
}
};
#ifdef BOOST_HAS_RVALUE_REFS
template<typename Mutex>
void swap(try_lock_wrapper<Mutex>&& lhs,try_lock_wrapper<Mutex>&& rhs)
{
lhs.swap(rhs);
}
#else
template<typename Mutex>
void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs)
{
lhs.swap(rhs);
}
#endif
template<typename MutexType1,typename MutexType2>
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2)
@@ -859,28 +1074,63 @@ namespace boost
}
}
template<typename MutexType1,typename MutexType2>
typename enable_if<is_mutex_type<MutexType1>, void>::type lock(MutexType1& m1,MutexType2& m2)
namespace detail
{
unsigned const lock_count=2;
unsigned lock_first=0;
while(true)
template<bool x>
struct is_mutex_type_wrapper
{};
template<typename MutexType1,typename MutexType2>
void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>)
{
switch(lock_first)
unsigned const lock_count=2;
unsigned lock_first=0;
while(true)
{
case 0:
lock_first=detail::lock_helper(m1,m2);
if(!lock_first)
return;
break;
case 1:
lock_first=detail::lock_helper(m2,m1);
if(!lock_first)
return;
lock_first=(lock_first+1)%lock_count;
break;
switch(lock_first)
{
case 0:
lock_first=detail::lock_helper(m1,m2);
if(!lock_first)
return;
break;
case 1:
lock_first=detail::lock_helper(m2,m1);
if(!lock_first)
return;
lock_first=(lock_first+1)%lock_count;
break;
}
}
}
template<typename Iterator>
void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>);
}
template<typename MutexType1,typename MutexType2>
void lock(MutexType1& m1,MutexType2& m2)
{
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2>
void lock(const MutexType1& m1,MutexType2& m2)
{
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2>
void lock(MutexType1& m1,const MutexType2& m2)
{
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2>
void lock(const MutexType1& m1,const MutexType2& m2)
{
detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2,typename MutexType3>
@@ -995,10 +1245,52 @@ namespace boost
}
}
template<typename MutexType1,typename MutexType2>
typename enable_if<is_mutex_type<MutexType1>, int>::type try_lock(MutexType1& m1,MutexType2& m2)
namespace detail
{
return ((int)detail::try_lock_internal(m1,m2))-1;
template<typename Mutex,bool x=is_mutex_type<Mutex>::value>
struct try_lock_impl_return
{
typedef int type;
};
template<typename Iterator>
struct try_lock_impl_return<Iterator,false>
{
typedef Iterator type;
};
template<typename MutexType1,typename MutexType2>
int try_lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>)
{
return ((int)detail::try_lock_internal(m1,m2))-1;
}
template<typename Iterator>
Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>);
}
template<typename MutexType1,typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,MutexType2& m2)
{
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,MutexType2& m2)
{
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,const MutexType2& m2)
{
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,const MutexType2& m2)
{
return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template<typename MutexType1,typename MutexType2,typename MutexType3>
@@ -1020,9 +1312,6 @@ namespace boost
}
template<typename Iterator>
typename disable_if<is_mutex_type<Iterator>, void>::type lock(Iterator begin,Iterator end);
namespace detail
{
template<typename Iterator>
@@ -1050,70 +1339,59 @@ namespace boost
}
}
};
}
template<typename Iterator>
typename disable_if<is_mutex_type<Iterator>, Iterator>::type try_lock(Iterator begin,Iterator end)
{
if(begin==end)
{
return end;
}
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
unique_lock<lock_type> guard(*begin,try_to_lock);
if(!guard.owns_lock())
{
return begin;
}
Iterator const failed=try_lock(++begin,end);
if(failed==end)
{
guard.release();
}
return failed;
}
template<typename Iterator>
Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>)
template<typename Iterator>
typename disable_if<is_mutex_type<Iterator>, void>::type lock(Iterator begin,Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
if(begin==end)
{
return;
}
bool start_with_begin=true;
Iterator second=begin;
++second;
Iterator next=second;
for(;;)
{
unique_lock<lock_type> begin_lock(*begin,defer_lock);
if(start_with_begin)
if(begin==end)
{
begin_lock.lock();
Iterator const failed_lock=try_lock(next,end);
if(failed_lock==end)
{
begin_lock.release();
return;
}
start_with_begin=false;
next=failed_lock;
return end;
}
else
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
unique_lock<lock_type> guard(*begin,try_to_lock);
if(!guard.owns_lock())
{
detail::range_lock_guard<Iterator> guard(next,end);
if(begin_lock.try_lock())
return begin;
}
Iterator const failed=try_lock(++begin,end);
if(failed==end)
{
guard.release();
}
return failed;
}
}
namespace detail
{
template<typename Iterator>
void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>)
{
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
if(begin==end)
{
return;
}
bool start_with_begin=true;
Iterator second=begin;
++second;
Iterator next=second;
for(;;)
{
unique_lock<lock_type> begin_lock(*begin,defer_lock);
if(start_with_begin)
{
Iterator const failed_lock=try_lock(second,next);
if(failed_lock==next)
begin_lock.lock();
Iterator const failed_lock=try_lock(next,end);
if(failed_lock==end)
{
begin_lock.release();
guard.release();
return;
}
start_with_begin=false;
@@ -1121,11 +1399,28 @@ namespace boost
}
else
{
start_with_begin=true;
next=second;
detail::range_lock_guard<Iterator> guard(next,end);
if(begin_lock.try_lock())
{
Iterator const failed_lock=try_lock(second,next);
if(failed_lock==next)
{
begin_lock.release();
guard.release();
return;
}
start_with_begin=false;
next=failed_lock;
}
else
{
start_with_begin=true;
next=second;
}
}
}
}
}
}

View File

@@ -121,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)

View File

@@ -47,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)

View File

@@ -10,6 +10,7 @@
#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>
#include <errno.h>
#include "timespec.hpp"
@@ -113,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()

View File

@@ -1,110 +1,111 @@
#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/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
#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

@@ -64,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)
@@ -78,11 +73,6 @@ namespace boost
}
}
bool locked()
{
return mutex.locked();
}
private:
bool try_recursive_lock(long current_thread_id)
{

View File

@@ -13,6 +13,7 @@
#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>
@@ -117,9 +118,9 @@ 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()
@@ -135,11 +136,6 @@ namespace boost
}
}
bool locked()
{
return get_active_count()>=lock_flag_value;
}
private:
void* get_event()
{

View File

@@ -20,7 +20,7 @@ namespace boost
}
class mutex:
boost::noncopyable,
boost::noncopyable,
public ::boost::detail::underlying_mutex
{
public:

View File

@@ -91,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)
@@ -106,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);
}
@@ -130,17 +122,10 @@ namespace boost
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)
@@ -159,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))
{
@@ -176,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)
@@ -198,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))
{
@@ -221,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;
@@ -262,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()
@@ -283,20 +244,39 @@ namespace boost
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)
@@ -316,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)
{
@@ -332,7 +304,7 @@ 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)
@@ -357,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;
@@ -378,7 +342,7 @@ namespace boost
void unlock()
{
state_data old_state=state;
do
for(;;)
{
state_data new_state=old_state;
new_state.exclusive=false;
@@ -396,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)
@@ -439,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))
{
@@ -457,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;
@@ -487,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;
@@ -522,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;
@@ -555,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;
@@ -588,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;
@@ -620,14 +555,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
release_waiters(old_state);
}

View File

@@ -64,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
@@ -282,16 +282,6 @@ namespace boost
}
#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
#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)
namespace boost
{
@@ -299,6 +289,17 @@ namespace boost
{
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;

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

View File

@@ -18,7 +18,7 @@
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/sysctl.h>
#elif defined(__sun) || defined(__CYGWIN__)
#elif defined BOOST_HAS_UNISTD_H
#include <unistd.h>
#endif
@@ -394,7 +394,7 @@ namespace boost
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
#elif defined(__sun) || defined(__CYGWIN__)
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#else

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);
}
@@ -141,8 +154,8 @@ namespace boost
}
}
set_current_thread_data(0);
}
set_current_thread_data(0);
}
unsigned __stdcall thread_start_function(void* param)
@@ -544,7 +557,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())
@@ -572,7 +584,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)
{
/*

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*[])

View File

@@ -272,6 +272,16 @@ struct dummy_mutex
}
};
namespace boost
{
template<>
struct is_mutex_type<dummy_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}
void test_lock_five_in_range()
{

View File

@@ -7,6 +7,7 @@
#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>
@@ -82,6 +83,122 @@ struct test_initially_unlocked_if_other_thread_has_lock
}
};
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
{
@@ -149,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
{
@@ -204,6 +379,8 @@ struct test_locks_can_be_swapped
{
Mutex m1;
Mutex m2;
Mutex m3;
Lock l1(m1);
Lock l2(m2);
@@ -219,16 +396,16 @@ struct test_locks_can_be_swapped
BOOST_CHECK_EQUAL(l1.mutex(),&m1);
BOOST_CHECK_EQUAL(l2.mutex(),&m2);
l1.swap(Lock(m3));
BOOST_CHECK_EQUAL(l1.mutex(),&m3);
}
};
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
template<typename Mutex,typename Lock>
void test_lock_is_scoped_lock_concept_for_mutex()
{
typedef typename Mutex::scoped_lock Lock;
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
@@ -238,6 +415,24 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
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)
@@ -252,26 +447,125 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
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>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_locked_after_try_lock_called<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>()();
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*[])
{
boost::unit_test_framework::test_suite* test =
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

@@ -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
{
@@ -130,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;
@@ -141,6 +195,17 @@ void test_if_no_thread_has_lock_try_lock_shared_returns_true()
}
}
void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
{
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
}
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
{
@@ -164,6 +229,52 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
writer.join();
}
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_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
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*[])
{
boost::unit_test_framework::test_suite* test =

View File

@@ -45,92 +45,90 @@ struct X
int main()
{
using namespace boost;
X x;
// 0
thread( &X::f0, &x ).join();
thread( &X::f0, ref(x) ).join();
boost::thread( &X::f0, &x ).join();
boost::thread( &X::f0, boost::ref(x) ).join();
thread( &X::g0, &x ).join();
thread( &X::g0, x ).join();
thread( &X::g0, ref(x) ).join();
boost::thread( &X::g0, &x ).join();
boost::thread( &X::g0, x ).join();
boost::thread( &X::g0, boost::ref(x) ).join();
// 1
thread( &X::f1, &x, 1 ).join();
thread( &X::f1, ref(x), 1 ).join();
boost::thread( &X::f1, &x, 1 ).join();
boost::thread( &X::f1, boost::ref(x), 1 ).join();
thread( &X::g1, &x, 1 ).join();
thread( &X::g1, x, 1 ).join();
thread( &X::g1, 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
thread( &X::f2, &x, 1, 2 ).join();
thread( &X::f2, ref(x), 1, 2 ).join();
boost::thread( &X::f2, &x, 1, 2 ).join();
boost::thread( &X::f2, boost::ref(x), 1, 2 ).join();
thread( &X::g2, &x, 1, 2 ).join();
thread( &X::g2, x, 1, 2 ).join();
thread( &X::g2, 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
thread( &X::f3, &x, 1, 2, 3 ).join();
thread( &X::f3, ref(x), 1, 2, 3 ).join();
boost::thread( &X::f3, &x, 1, 2, 3 ).join();
boost::thread( &X::f3, boost::ref(x), 1, 2, 3 ).join();
thread( &X::g3, &x, 1, 2, 3 ).join();
thread( &X::g3, x, 1, 2, 3 ).join();
thread( &X::g3, 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
thread( &X::f4, &x, 1, 2, 3, 4 ).join();
thread( &X::f4, ref(x), 1, 2, 3, 4 ).join();
boost::thread( &X::f4, &x, 1, 2, 3, 4 ).join();
boost::thread( &X::f4, boost::ref(x), 1, 2, 3, 4 ).join();
thread( &X::g4, &x, 1, 2, 3, 4 ).join();
thread( &X::g4, x, 1, 2, 3, 4 ).join();
thread( &X::g4, 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
thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
thread( &X::f5, ref(x), 1, 2, 3, 4, 5 ).join();
boost::thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
boost::thread( &X::f5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join();
thread( &X::g5, x, 1, 2, 3, 4, 5 ).join();
thread( &X::g5, 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
thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join();
thread( &X::f6, ref(x), 1, 2, 3, 4, 5, 6 ).join();
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();
thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join();
thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join();
thread( &X::g6, 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
thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join();
thread( &X::f7, ref(x), 1, 2, 3, 4, 5, 6, 7).join();
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();
thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join();
thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join();
thread( &X::g7, 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
thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
thread( &X::f8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
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();
thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
thread( &X::g8, 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 report_errors();
return boost::report_errors();
}

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