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

Compare commits

..

18 Commits

Author SHA1 Message Date
Beman Dawes
cf4dd909d5 Release 1.49.0
[SVN r77094]
2012-02-22 22:08:43 +00:00
Vicente J. Botet Escriba
09362f0eac Thread: merge from trunk to fix #6141, #5594, #5040 and #5502.
[SVN r76346]
2012-01-07 20:52:57 +00:00
Vicente J. Botet Escriba
32b3f3f569 Thread: Fix typo on auto_ptr
[SVN r76345]
2012-01-07 20:15:14 +00:00
Vicente J. Botet Escriba
8affa33718 Thread fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2309 #2309] Lack of g++ symbol visibility support in Boost.Thread. 
* [@http://svn.boost.org/trac/boost/ticket/2639 #2639] documentation should be extended(defer_lock, try_to_lock, ...).

* [@http://svn.boost.org/trac/boost/ticket/3639 #3639] Boost.Thread doesn't build with Sun-5.9 on Linux.
* [@http://svn.boost.org/trac/boost/ticket/3762 #3762] Thread can't be compiled with winscw (Codewarrior by Nokia).
* [@http://svn.boost.org/trac/boost/ticket/3885 #3885] document about mix usage of boost.thread and native thread api.
* [@http://svn.boost.org/trac/boost/ticket/3975 #3975] Incorrect precondition for promise::set_wait_callback().

* [@http://svn.boost.org/trac/boost/ticket/4048 #4048] thread::id formatting involves locale
* [@http://svn.boost.org/trac/boost/ticket/4315 #4315] gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored. 
* [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds.
* [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints.

* [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x.
* [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor.
* [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6.
* [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure.
* [@http://svn.boost.org/trac/boost/ticket/5839 #5839] thread.cpp: ThreadProxy leaks on exceptions.
* [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions. 

* [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems.
* [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo).
* [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio.
* [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR. 
* [@http://svn.boost.org/trac/boost/ticket/6207 #6207] shared_lock swap compiler error on clang 3.0 c++11. 
* [@http://svn.boost.org/trac/boost/ticket/6208 #6208] try_lock_wrapper swap compiler error on clang 3.0 c++11. 




[SVN r76291]
2012-01-03 17:31:50 +00:00
Anthony Williams
b991c9a8a0 Merged thread changes from trunk
[SVN r72431]
2011-06-06 08:28:31 +00:00
Marshall Clow
ab665c8c56 Merge fixes to release; Fixes #1988
[SVN r71676]
2011-05-02 20:56:53 +00:00
Anthony Williams
7ec9804540 Merged Boost.Thread changes from trunk
[SVN r70382]
2011-03-21 22:59:40 +00:00
Hartmut Kaiser
7c9116af2e Spirit: merge from trunk
[SVN r68078]
2011-01-13 02:11:19 +00:00
Anthony Williams
70584af9c0 Merged fix for issue #4736 from trunk
[SVN r66588]
2010-11-15 10:13:12 +00:00
Anthony Williams
381554f8bc Merged fix for issue #4736 from trunk
[SVN r66482]
2010-11-10 11:24:52 +00:00
Anthony Williams
4dc1cb1ba1 Merged Boost.Thread from trunk
[SVN r66259]
2010-10-29 23:27:00 +00:00
Vladimir Prus
506019dd62 Remove debug print
[SVN r66171]
2010-10-25 07:52:02 +00:00
Vladimir Prus
e30be60bc4 Merge r64010, wherein jam has been moved.
[SVN r65233]
2010-09-04 11:02:21 +00:00
Andrey Semashev
7bfafec128 Fixed compilation with MSVC and, probably, other compilers.
[SVN r64999]
2010-08-25 16:41:08 +00:00
Anthony Williams
e12d2bc486 Marged changes to Boost.Thread from trunk
[SVN r63915]
2010-07-12 07:47:39 +00:00
Anthony Williams
a37d2a1364 Merged boost.thread changes over from trunk
[SVN r63789]
2010-07-09 19:13:09 +00:00
Daniel James
cc662c102c Merge documentation fixes.
* Use `doc/src/*.css` instead of `doc/html/*.css`.
* Remove wiki and people directories.
* Some documentation fixes.
* Left out `minimal.css` changes and boostbook changes because of clashes.


[SVN r63347]
2010-06-26 12:30:09 +00:00
Anthony Williams
65d2898ff0 Merged changes to boost.thread over from trunk
[SVN r60991]
2010-04-01 15:04:15 +00:00
85 changed files with 2608 additions and 908 deletions

View File

@@ -43,6 +43,7 @@ project boost/thread
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
<tag>@$(__name__).tag
<toolset>gcc:<cxxflags>-Wno-long-long
: default-build <threading>multi
;

View File

@@ -26,11 +26,6 @@ boostbook standalone
<xsl:param>generate.section.toc.level=10
# Path for links to Boost:
<xsl:param>boost.root=../../../..
# Path for libraries index:
<xsl:param>boost.libraries=../../../../libs/libraries.htm
# Use the main Boost stylesheet:
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
;

View File

@@ -5,7 +5,45 @@
http://www.boost.org/LICENSE_1_0.txt).
]
[section:changes Changes since boost 1.40]
[section:changes Changes since]
[heading Changes since boost 1.41]
Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2309 #2309] Lack of g++ symbol visibility support in Boost.Thread.
* [@http://svn.boost.org/trac/boost/ticket/2639 #2639] documentation should be extended(defer_lock, try_to_lock, ...).
* [@http://svn.boost.org/trac/boost/ticket/3639 #3639] Boost.Thread doesn't build with Sun-5.9 on Linux.
* [@http://svn.boost.org/trac/boost/ticket/3762 #3762] Thread can't be compiled with winscw (Codewarrior by Nokia).
* [@http://svn.boost.org/trac/boost/ticket/3885 #3885] document about mix usage of boost.thread and native thread api.
* [@http://svn.boost.org/trac/boost/ticket/3975 #3975] Incorrect precondition for promise::set_wait_callback().
* [@http://svn.boost.org/trac/boost/ticket/4048 #4048] thread::id formatting involves locale
* [@http://svn.boost.org/trac/boost/ticket/4315 #4315] gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored.
* [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds.
* [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints.
* [@http://svn.boost.org/trac/boost/ticket/5040 #5040] future.hpp in boost::thread does not compile with /clr.
* [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x.
* [@http://svn.boost.org/trac/boost/ticket/5502 #5502] race condition between shared_mutex timed_lock and lock_shared.
* [@http://svn.boost.org/trac/boost/ticket/5594 #5594] boost::shared_mutex not fully compatible with Windows CE.
* [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor.
* [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6.
* [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure.
* [@http://svn.boost.org/trac/boost/ticket/5839 #5839] thread.cpp: ThreadProxy leaks on exceptions.
* [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions.
* [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems.
* [@http://svn.boost.org/trac/boost/ticket/6141 #6141] Compilation error when boost.thread and boost.move are used together.
* [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo).
* [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio.
* [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR.
* [@http://svn.boost.org/trac/boost/ticket/6207 #6207] shared_lock swap compiler error on clang 3.0 c++11.
* [@http://svn.boost.org/trac/boost/ticket/6208 #6208] try_lock_wrapper swap compiler error on clang 3.0 c++11.
[heading Changes since boost 1.40]
The 1.41.0 release of Boost adds futures to the thread library. There are also a few minor changes.
@@ -85,3 +123,22 @@ been moved to __thread_id__.
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
[endsect]
[section:future Future]
The following features will be included in next releases. By order of priority:
* [@http://svn.boost.org/trac/boost/ticket/6194 #6194] Adapt to Boost.Move.
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] Missing async().
* [@http://svn.boost.org/trac/boost/ticket/6195 #6195] Provide the standard time related interface using Boost.Chrono.
* [@http://svn.boost.org/trac/boost/ticket/2637 #2637] shared mutex lock
* Lock guards
* [@http://svn.boost.org/trac/boost/ticket/1850 #1850] request for unlock_guard (and/or unique_unlock) to compliment lock_guard/unique_lock
* [@http://svn.boost.org/trac/boost/ticket/3567 #3567] Request for shared_lock_guard
* [@http://svn.boost.org/trac/boost/ticket/2741 #2741] Proposal to manage portable and non portable thread attributes.
* #2880 Request for Thread scheduler support for boost ..
* #3696 Boost Thread library lacks any way to set priority of threads
* #5956 Add optional stack_size argument to thread::start_thread()
[endsect]

100
doc/compliance.qbk Normal file
View File

@@ -0,0 +1,100 @@
[/
(C) Copyright 2011 Vicente J. Botet Escriba.
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:compliance Compliance with standard]
[section:cpp11 C++11 standard Thread library]
[table Compliance C++11 standard
[[Section] [Description] [Status] [Comments] [Ticket]]
[[30] [Thread support library] [Partial] [-] [-]]
[[30.1] [General] [-] [-] [-]]
[[30.2] [Requirements] [-] [-] [-]]
[[30.2.1] [Template parameter names] [-] [-] [-]]
[[30.2.2] [Exceptions] [No] [-] [#12]]
[[30.2.3] [Native handles] [Yes] [-] [-]]
[[30.2.4] [Timing specifications] [No] [-] [#6195]]
[[30.2.5] [Requirements for Lockable types] [Partial] [-] [-]]
[[30.2.5.1] [In general] [-] [-] [-]]
[[30.2.5.2] [BasicLockable requirements] [No] [-] [#13]]
[[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
[[30.2.5.4] [TimedLockable requirements] [Partial] [chrono] [#6195]]
[[30.2.6] [decay_copy] [-] [-] [-]]
[[30.3] [Threads] [Partial] [-] [-]]
[[30.3.1] [Class thread] [Partial] [-] [-]]
[[30.3.1.1] [Class thread::id] [Partial] [Missing noexcept, template <> struct hash<thread::id>] [#3,#4]]
[[30.3.1.2] [thread constructors] [Partial] [Missing noexcept and move semantics] [#3,#6194]]
[[30.3.1.3] [thread destructor] [Yes] [-] [-]]
[[30.3.1.4] [thread assignment] [Partial] [move semantics] [-]]
[[30.3.1.5] [thread members] [Partial] [Missing noexcept, chrono] [#3,#6195]]
[[30.3.1.6] [thread static members] [Partial] [Missing noexcept] [#3,#6195]]
[[30.3.1.7] [thread specialized algorithms] [Yes] [-] [-]]
[[30.3.2] [Namespace this_thread] [Partial] [chrono] [#6195]]
[[30.4] [Mutual exclusion] [Partial] [-] [-]]
[[30.4.1] [Mutex requirements] [Partial] [-] [-]]
[[30.4.1.1] [In general] [Partial] [-] [-]]
[[30.4.1.2] [Mutex types] [Partial] [noexcept,delete] [#3,#5]]
[[30.4.1.2.1] [Class mutex] [Partial] [noexcept,delete] [#3,#5]]
[[30.4.1.2.2] [Class recursive_mutex] [Partial] [noexcept,delete] [#3,#5]]
[[30.4.1.3] [Timed mutex types] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
[[30.4.1.3.1] [Class timed_mutex] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
[[30.4.1.3.1] [Class recursive_timed_mutex] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
[[30.4.2] [Locks] [Partial] [noexcept,chrono,move,delete,bool] [#3,#6195,#5,#6]]
[[30.4.2.1] [Class template lock_guard] [Partial] [cons/dest delete] [#5]]
[[30.4.2.2] [Class template unique_lock] [Partial] [noexcept, chrono, move, delete] [#3,#6195,#5,#6]]
[[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Partial] [noexcept, chrono, move, delete] [#3,#6195,#5,#6]]
[[30.4.2.2.2] [unique_lock locking] [Partial] [chrono] [,#6195,]]
[[30.4.2.2.3] [unique_lock modifiers] [Yes] [-] [-]]
[[30.4.2.2.4] [unique_lock observers] [Partial] [explicit operator bool] [#6]]
[[30.4.3] [Generic locking algorithms] [Partial] [Variadic,] [#7]]
[[30.4.4] [Call once] [Partial] [move,variadic] [#6194,#7]]
[[30.4.4.1] [Struct once_flag] [Yes] [-] [-]]
[[30.4.4.2] [Function call_once] [Yes] [-] [-]]
[[30.5] [Condition variables] [Partial] [chrono,cv_status,notify_all_at_thread_exit] [#6195,#8,#9]]
[[30.5 6-10] [Function notify_all_at_thread_exit] [No] [-] [#9]]
[[30.5.1] [Class condition_variable] [Partial] [chrono,cv_status] [#6195,#8]]
[[30.5.2] [Class condition_variable_any] [Partial] [chrono,cv_status] [#6195,#8]]
[[30.6] [Futures] [Partial] [-] [-]]
[[30.6.1] [Overview] [Partial] [-] [-]]
[[30.6.2] [Error handling] [No] [-] [-]]
[[30.6.3] [Class future_error] [No] [-] [-]]
[[30.6.4] [Shared state] [No] [-] [-]]
[[30.6.5] [Class template promise] [Partial] [allocator,move,delete] [#10,#6194,#5]]
[[30.6.6] [Class template future] [No] [unique_future is the closest to future] [#11]]
[[30.6.7] [Class template shared_future] [Partial] [allocator,move,delete] [#10,#6194,#5]]
[[30.6.8] [Function template async] [No] [async] [#4710]]
[[30.6.8] [Class template packaged_task] [Partial] [-] [-]]
]
[table Extension
[[Section] [Description] [Comments]]
[[30.3.1.5.x] [interrupt] [-]]
[[30.3.1.5.y] [operator==,operator!=] [-]]
[[30.3.2.x] [Interruprion] [-]]
[[30.3.2.y] [at_thread_exit] [-]]
[[30.4.3.x] [Generic locking algorithms begin/end] [-]]
[[30.x] [Barriers] [-]]
[[30.y] [Thread Local Storage] [-]]
[[30.z] [Class thread_group] [-]]
]
[endsect]
[section:shared Shared Mutex library extension]
[table Clock Requirements
[[Section] [Description] [Status] [Comments]]
[[XXXX] [DDDD] [SSSS] [CCCC]]
[[XXXX] [DDDD] [SSSS] [CCCC]]
]
[endsect]
[endsect]

View File

@@ -701,7 +701,7 @@ required for storage of the result cannot be allocated.]]
[variablelist
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __packaged_task__ shall be well-formed. Invoking a copy of
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __promise__ shall be well-formed. Invoking a copy of
`f` shall have the same effect as invoking `f`]]
[[Effects:] [Store a copy of `f` with the asynchronous result associated with `*this` as a ['wait callback]. This will replace any

View File

@@ -310,6 +310,25 @@ without blocking.]]
[section:locks Lock Types]
[section:lock_tags Lock option tags]
#include <boost/thread/locks.hpp>
struct defer_lock_t {};
struct try_to_lock_t {};
struct adopt_lock_t {};
const defer_lock_t defer_lock;
const try_to_lock_t try_to_lock;
const adopt_lock_t adopt_lock;
These tags are used in scoped locks constructors to specify a specific behavior.
*`defer_lock_t`: is used to construct the scoped lock without locking it.
*`try_to_lock_t`: is used to construct the scoped lock trying to lock it.
*`adopt_lock_t`: is used to construct the scoped lock without locking it but adopting ownership.
[endsect]
[section:lock_guard Class template `lock_guard`]
#include <boost/thread/locks.hpp>

View File

@@ -45,6 +45,15 @@ all subsequent `call_once` invocations on the same `once_flag` object. ]]
[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]]
[[Note:] [The function passed to `call_once` must not also call
`call_once` passing the same `once_flag` object. This may cause
deadlock, or invoking the passed function a second time. The
alternative is to allow the second call to return immediately, but
that assumes the code knows it has been called recursively, and can
proceed even though the call to `call_once` didn't actually call the
function, in which case it could also avoid calling `call_once`
recursively.]]
]
void call_once(void (*func)(),once_flag& flag);

View File

@@ -166,3 +166,5 @@
[include time.qbk]
[include acknowledgements.qbk]
[include compliance.qbk]

View File

@@ -163,6 +163,44 @@ Each instance of __thread_id__ either refers to some thread, or __not_a_thread__
compare equal to each other, but not equal to any instances that refer to an actual thread of execution. The comparison operators on
__thread_id__ yield a total order for every non-equal thread ID.
[heading Using native interfaces with Boost.Thread resources]
__thread__ class has members `native_handle_type` and `native_handle` providing access to the underlying native handle.
This native handle can be used to change for example the scheduling.
In general, it is not safe to use this handle with operations that can conflict with the ones provided by Boost.Thread. An example of bad usage could be detaching a thread directly as it will not change the internals of the __thread__ instance, so for example the joinable function will continue to return true, while the native thread is no more joinable.
thread t(fct);
thread::native_handle_type hnd=t.native_handle();
pthread_detach(hnd);
assert(t.joinable());
[heading Using Boost.Thread interfaces in a native thread]
Any thread of execution created using the native interface is called a native thread in this documentation.
The first example of a native thread of execution is the main thread.
The user can access to some synchronization functions related to the native current thread using the `boost::this_thread` `yield`, `sleep`, functions.
int main() {
// ...
boost::this_thread::sleep();
// ...
}
Of course all the synchronization facilities provided by Boost.Thread are also available on native threads.
The `boost::this_thread` interrupt related functions behave in a degraded mode when called from a thread created using the native interface, i.e. `boost::this_thread::interruption_enabled()` returns false. As consequence the use of `boost::this_thread::disable_interruption` and `boost::this_thread::restore_interruption` will do nothing and calls to `boost::this_thread::interrupt_point()` will be just ignored.
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` wiil returns false for the native threads.
[section:thread Class `thread`]
#include <boost/thread/thread.hpp>
@@ -219,6 +257,7 @@ __thread_id__ yield a total order for every non-equal thread ID.
};
void swap(thread& lhs,thread& rhs);
detail::thread_move_t<thread> move(detail::thread_move_t<thread> t);
[section:default_constructor Default Constructor]
@@ -234,6 +273,40 @@ __thread_id__ yield a total order for every non-equal thread ID.
[endsect]
[section:move_constructor Move Constructor]
thread(detail::thread_move_t<thread> other);
[variablelist
[[Effects:] [Transfers ownership of the thread managed by `other` (if any) to the newly constructed __thread__ instance.]]
[[Postconditions:] [`other->get_id()==thread::id()`]]
[[Throws:] [Nothing]]
]
[endsect]
[section:move_assignment Move assignment operator]
thread& operator=(detail::thread_move_t<thread> other);
[variablelist
[[Effects:] [Transfers ownership of the thread managed by `other` (if
any) to `*this`. If there was a thread previously associated with
`*this` then that thread is detached.]]
[[Postconditions:] [`other->get_id()==thread::id()`]]
[[Throws:] [Nothing]]
]
[endsect]
[section:callable_constructor Thread Constructor]
template<typename Callable>
@@ -521,6 +594,26 @@ value as `this->get_id()` prior to the call.]]
[endsect]
[section:non_member_move Non-member function `move()`]
#include <boost/thread/thread.hpp>
detail::thread_move_t<thread> move(detail::thread_move_t<thread> t)
[variablelist
[[Returns:] [`t`.]]
]
Enables moving thread objects. e.g.
extern void some_func();
boost::thread t(some_func);
boost::thread t2(boost::move(t)); // transfer thread from t to t2
[endsect]
[section:id Class `boost::thread::id`]
@@ -620,7 +713,7 @@ execution.]]
[endsect]
[section:less_than_or_equal `operator>=`]
[section:less_than_or_equal `operator<=`]
bool operator<=(const id& y) const;
@@ -756,11 +849,14 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
{
template<typename TimeDuration>
void sleep(TimeDuration const& rel_time);
void sleep(system_time const& abs_time)
}
[variablelist
[[Effects:] [Suspends the current thread until the specified time has elapsed.]]
[[Effects:] [Suspends the current thread until the time period
specified by `rel_time` has elapsed or the time point specified by
`abs_time` has been reached.]]
[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]

View File

@@ -41,6 +41,11 @@ order. If a cleanup routine sets the value of associated with an instance of `bo
cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of
`boost::thread_specific_ptr` with values.
Note: on some platforms, cleanup of thread-specific data is not
performed for threads created with the platform's native API. On those
platforms such cleanup is only done for threads that are started with
`boost::thread` unless `boost::on_thread_exit()` is called manually
from that thread.
[section:thread_specific_ptr Class `thread_specific_ptr`]

View File

@@ -9,6 +9,7 @@
#define BOOST_BARRIER_JDM030602_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
@@ -27,7 +28,7 @@ namespace boost
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
boost::throw_exception(std::invalid_argument("count cannot be zero."));
}
bool wait()

View File

@@ -1,7 +1,7 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
@@ -10,6 +10,15 @@
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#if !defined BOOST_THREAD_VERSION
#define BOOST_THREAD_VERSION 1
#else
#if BOOST_THREAD_VERSION!=1 && BOOST_THREAD_VERSION!=2
#error "BOOST_THREAD_VERSION must be 1 or 2"
#endif
#endif
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
# pragma warn -8008 // Condition always true/false
# pragma warn -8080 // Identifier declared but never used
@@ -19,8 +28,14 @@
#include "platform.hpp"
// provided for backwards compatibility, since this
// macro was used for several releases by mistake.
#if defined(BOOST_THREAD_DYN_DLL)
# define BOOST_THREAD_DYN_LINK
#endif
// compatibility with the rest of Boost's auto-linking code:
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
# undef BOOST_THREAD_USE_LIB
# define BOOST_THREAD_USE_DLL
#endif
@@ -47,12 +62,18 @@
#if defined(BOOST_HAS_DECLSPEC)
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
# define BOOST_THREAD_DECL __declspec(dllexport)
# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT
//# define BOOST_THREAD_DECL __declspec(dllexport)
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
# define BOOST_THREAD_DECL __declspec(dllimport)
# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT
//# define BOOST_THREAD_DECL __declspec(dllimport)
# else
# define BOOST_THREAD_DECL
# endif
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
# define BOOST_THREAD_DECL BOOST_SYMBOL_VISIBLE
#else
# define BOOST_THREAD_DECL
#endif // BOOST_HAS_DECLSPEC
@@ -63,7 +84,7 @@
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
//
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
// once it's done with it:
// once it's done with it:
//
#if defined(BOOST_THREAD_USE_DLL)
# define BOOST_DYN_LINK

View File

@@ -6,15 +6,20 @@
#ifndef BOOST_THREAD_MOVE_HPP
#define BOOST_THREAD_MOVE_HPP
#include <boost/thread/detail/config.hpp>
#ifndef BOOST_NO_SFINAE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/remove_reference.hpp>
#endif
#include <boost/move/move.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
template<typename T>
@@ -41,18 +46,19 @@ 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)
typename enable_if<boost::is_convertible<T&,boost::detail::thread_move_t<T> >, boost::detail::thread_move_t<T> >::type move(T& t)
{
return detail::thread_move_t<T>(t);
return boost::detail::thread_move_t<T>(t);
}
#endif
template<typename T>
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t)
{
return t;
}
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -29,7 +29,7 @@
# define BOOST_THREAD_HPUX
#elif defined(__CYGWIN__)
# define BOOST_THREAD_CYGWIN
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
# define BOOST_THREAD_WIN32
#elif defined(__BEOS__)
# define BOOST_THREAD_BEOS

View File

@@ -3,10 +3,12 @@
// 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
// (C) Copyright 2007-10 Anthony Williams
#include <boost/thread/exceptions.hpp>
#ifndef BOOST_NO_IOSTREAM
#include <ostream>
#endif
#include <boost/thread/detail/move.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/xtime.hpp>
@@ -22,6 +24,7 @@
#include <memory>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -39,10 +42,13 @@ namespace boost
public detail::thread_data_base
{
public:
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
thread_data(F&& f_):
f(static_cast<F&&>(f_))
{}
thread_data(F& f_):
f(f_)
{}
#else
thread_data(F f_):
f(f_)
@@ -50,7 +56,7 @@ namespace boost
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
#endif
#endif
void run()
{
f();
@@ -75,7 +81,7 @@ namespace boost
thread_data(boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
@@ -94,14 +100,14 @@ namespace boost
thread_data(const boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
}
class BOOST_THREAD_DECL thread
{
private:
@@ -109,17 +115,16 @@ namespace boost
thread& operator=(thread&);
void release_handle();
mutable boost::mutex thread_info_mutex;
detail::thread_data_ptr thread_info;
void start_thread();
explicit thread(detail::thread_data_ptr data);
detail::thread_data_ptr get_thread_info() const;
detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename F>
static inline detail::thread_data_ptr make_thread_info(F&& f)
{
@@ -127,7 +132,7 @@ namespace boost
}
static inline detail::thread_data_ptr make_thread_info(void (*f)())
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(f));
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(static_cast<void(*&&)()>(f)));
}
#else
template<typename F>
@@ -141,28 +146,37 @@ namespace boost
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
}
struct dummy;
#endif
struct dummy;
public:
#ifdef __SUNPRO_CC
thread(const volatile thread&);
#endif
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
thread(const volatile thread&);
#endif
thread();
~thread();
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
#ifdef BOOST_MSVC
template <class F>
explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
thread_info(make_thread_info(static_cast<F&&>(f)))
{
start_thread();
}
#else
template <class F>
thread(F&& f):
thread_info(make_thread_info(static_cast<F&&>(f)))
{
start_thread();
}
#endif
thread(thread&& other)
{
thread_info.swap(other.thread_info);
}
thread& operator=(thread&& other)
{
thread_info=other.thread_info;
@@ -174,7 +188,7 @@ namespace boost
{
return static_cast<thread&&>(*this);
}
#else
#ifdef BOOST_NO_SFINAE
template <class F>
@@ -191,7 +205,7 @@ namespace boost
start_thread();
}
#endif
template <class F>
explicit thread(detail::thread_move_t<F> f):
thread_info(make_thread_info(f))
@@ -204,13 +218,13 @@ namespace boost
thread_info=x->thread_info;
x->thread_info.reset();
}
#ifdef __SUNPRO_CC
thread& operator=(thread x)
{
swap(x);
return *this;
}
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
thread& operator=(thread x)
{
swap(x);
return *this;
}
#else
thread& operator=(detail::thread_move_t<thread> x)
{
@@ -218,12 +232,12 @@ namespace boost
swap(new_thread);
return *this;
}
#endif
#endif
operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> move()
{
detail::thread_move_t<thread> x(*this);
@@ -299,7 +313,7 @@ namespace boost
thread_info.swap(x.thread_info);
}
class id;
class BOOST_SYMBOL_VISIBLE id;
id get_id() const;
@@ -327,7 +341,7 @@ namespace boost
{
this_thread::yield();
}
static inline void sleep(const system_time& xt)
{
this_thread::sleep(xt);
@@ -342,11 +356,15 @@ namespace boost
{
return lhs.swap(rhs);
}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
inline thread&& move(thread& t)
{
return static_cast<thread&&>(t);
}
inline thread&& move(thread&& t)
{
return t;
return static_cast<thread&&>(t);
}
#else
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> t)
@@ -363,110 +381,153 @@ namespace boost
bool BOOST_THREAD_DECL interruption_enabled();
bool BOOST_THREAD_DECL interruption_requested();
inline void sleep(xtime const& abs_time)
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
{
sleep(system_time(abs_time));
}
}
class thread::id
class BOOST_SYMBOL_VISIBLE thread::id
{
private:
detail::thread_data_ptr thread_data;
id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
{}
friend class thread;
friend id this_thread::get_id();
friend id BOOST_THREAD_DECL this_thread::get_id();
public:
id():
thread_data()
{}
id(const id& other):
thread_data(other.thread_data)
{}
bool operator==(const id& y) const
{
return thread_data==y.thread_data;
}
bool operator!=(const id& y) const
{
return thread_data!=y.thread_data;
}
bool operator<(const id& y) const
{
return thread_data<y.thread_data;
}
bool operator>(const id& y) const
{
return y.thread_data<thread_data;
}
bool operator<=(const id& y) const
{
return !(y.thread_data<thread_data);
}
bool operator>=(const id& y) const
{
return !(thread_data<y.thread_data);
}
#ifndef BOOST_NO_IOSTREAM
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
friend BOOST_SYMBOL_VISIBLE
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
{
if(x.thread_data)
{
return os<<x.thread_data;
io::ios_flags_saver ifs( os );
return os<< std::hex << x.thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
}
#else
template<class charT, class traits>
BOOST_SYMBOL_VISIBLE
std::basic_ostream<charT, traits>&
print(std::basic_ostream<charT, traits>& os) const
{
if(thread_data)
{
return os<<thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
}
#endif
#endif
};
#if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template<class charT, class traits>
BOOST_SYMBOL_VISIBLE
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
{
return x.print(os);
}
#endif
inline bool thread::operator==(const thread& other) const
{
return get_id()==other.get_id();
}
inline bool thread::operator!=(const thread& other) const
{
return get_id()!=other.get_id();
}
namespace detail
{
struct thread_exit_function_base
{
virtual ~thread_exit_function_base()
{}
virtual void operator()() const=0;
virtual void operator()()=0;
};
template<typename F>
struct thread_exit_function:
thread_exit_function_base
{
F f;
thread_exit_function(F f_):
f(f_)
{}
void operator()() const
void operator()()
{
f();
}
};
void add_thread_exit_function(thread_exit_function_base*);
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
}
#ifdef BOOST_NO_RVALUE_REFERENCES
template <>
struct has_move_emulation_enabled_aux<thread>
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
namespace this_thread
{
template<typename F>

View File

@@ -18,10 +18,13 @@
namespace boost
{
class thread_group:
private noncopyable
class thread_group
{
private:
thread_group(thread_group const&);
thread_group& operator=(thread_group const&);
public:
thread_group() {}
~thread_group()
{
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();

View File

@@ -12,27 +12,9 @@
#if defined(BOOST_HAS_WINTHREADS)
typedef void (__cdecl *thread_exit_handler)(void);
extern "C" BOOST_THREAD_DECL int at_thread_exit(
thread_exit_handler exit_handler
);
//Add a function to the list of functions that will
//be called when a thread is about to exit.
//Currently only implemented for Win32, but should
//later be implemented for all platforms.
//Used by Win32 implementation of Boost.Threads
//tss to perform cleanup.
//Like the C runtime library atexit() function,
//which it mimics, at_thread_exit() returns
//zero if successful and a nonzero
//value if an error occurs.
#endif //defined(BOOST_HAS_WINTHREADS)
#if defined(BOOST_HAS_WINTHREADS)
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
namespace boost
{
BOOST_THREAD_DECL void __cdecl on_process_enter(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
@@ -42,7 +24,7 @@
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
BOOST_THREAD_DECL void __cdecl on_process_exit(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
@@ -52,7 +34,7 @@
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_thread_enter(void);
BOOST_THREAD_DECL void __cdecl on_thread_enter(void);
//Function to be called just after a thread starts
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
@@ -61,7 +43,7 @@
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
//Function to be called just be fore a thread ends
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
@@ -70,10 +52,11 @@
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" void tss_cleanup_implemented(void);
void tss_cleanup_implemented();
//Dummy function used both to detect whether tss cleanup
//cleanup has been implemented and to force
//it to be linked into the Boost.Threads library.
}
#endif //defined(BOOST_HAS_WINTHREADS)

View File

@@ -24,10 +24,10 @@
namespace boost
{
class thread_interrupted
class BOOST_SYMBOL_VISIBLE thread_interrupted
{};
class thread_exception:
class BOOST_SYMBOL_VISIBLE thread_exception:
public std::exception
{
protected:
@@ -55,7 +55,7 @@ namespace boost
int m_sys_err;
};
class condition_error:
class BOOST_SYMBOL_VISIBLE condition_error:
public std::exception
{
public:
@@ -66,7 +66,7 @@ namespace boost
};
class lock_error:
class BOOST_SYMBOL_VISIBLE lock_error:
public thread_exception
{
public:
@@ -87,7 +87,7 @@ namespace boost
}
};
class thread_resource_error:
class BOOST_SYMBOL_VISIBLE thread_resource_error:
public thread_exception
{
public:
@@ -109,7 +109,7 @@ namespace boost
};
class unsupported_thread_option:
class BOOST_SYMBOL_VISIBLE unsupported_thread_option:
public thread_exception
{
public:
@@ -131,7 +131,7 @@ namespace boost
};
class invalid_thread_argument:
class BOOST_SYMBOL_VISIBLE invalid_thread_argument:
public thread_exception
{
public:
@@ -153,7 +153,7 @@ namespace boost
};
class thread_permission_error:
class BOOST_SYMBOL_VISIBLE thread_permission_error:
public thread_exception
{
public:

View File

@@ -1,4 +1,4 @@
// (C) Copyright 2008-9 Anthony Williams
// (C) Copyright 2008-10 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -9,6 +9,8 @@
#include <stdexcept>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
@@ -16,6 +18,7 @@
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/if.hpp>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <boost/function.hpp>
#include <boost/bind.hpp>
@@ -108,7 +111,7 @@ namespace boost
do_callback(lock);
return external_waiters.insert(external_waiters.end(),&cv);
}
void remove_external_waiter(waiter_list::iterator it)
{
boost::lock_guard<boost::mutex> lock(mutex);
@@ -129,7 +132,7 @@ namespace boost
struct relocker
{
boost::unique_lock<boost::mutex>& lock;
relocker(boost::unique_lock<boost::mutex>& lock_):
lock(lock_)
{
@@ -139,6 +142,8 @@ namespace boost
{
lock.lock();
}
private:
relocker& operator=(relocker const&);
};
void do_callback(boost::unique_lock<boost::mutex>& lock)
@@ -150,7 +155,7 @@ namespace boost
local_callback();
}
}
void wait(bool rethrow=true)
{
@@ -180,7 +185,7 @@ namespace boost
}
return true;
}
void mark_exceptional_finish_internal(boost::exception_ptr const& e)
{
exception=e;
@@ -208,7 +213,7 @@ namespace boost
{
callback=boost::bind(f,boost::ref(*u));
}
private:
future_object_base(future_object_base const&);
future_object_base& operator=(future_object_base const&);
@@ -218,7 +223,7 @@ namespace boost
struct future_traits
{
typedef boost::scoped_ptr<T> storage_type;
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
typedef T const& source_reference_type;
struct dummy;
typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type;
@@ -233,7 +238,7 @@ namespace boost
{
storage.reset(new T(t));
}
static void init(storage_type& storage,rvalue_source_type t)
{
storage.reset(new T(static_cast<rvalue_source_type>(t)));
@@ -244,7 +249,7 @@ namespace boost
storage.reset();
}
};
template<typename T>
struct future_traits<T&>
{
@@ -291,7 +296,7 @@ namespace boost
typedef typename future_traits<T>::source_reference_type source_reference_type;
typedef typename future_traits<T>::rvalue_source_type rvalue_source_type;
typedef typename future_traits<T>::move_dest_type move_dest_type;
storage_type result;
future_object():
@@ -323,7 +328,7 @@ namespace boost
move_dest_type get()
{
wait();
return *result;
return static_cast<move_dest_type>(*result);
}
future_state::state get_state()
@@ -348,6 +353,8 @@ namespace boost
struct future_object<void>:
detail::future_object_base
{
typedef void move_dest_type;
future_object()
{}
@@ -366,7 +373,7 @@ namespace boost
{
wait();
}
future_state::state get_state()
{
boost::lock_guard<boost::mutex> guard(mutex);
@@ -387,57 +394,70 @@ namespace boost
class future_waiter
{
struct registered_waiter;
typedef std::vector<registered_waiter>::size_type count_type;
struct registered_waiter
{
boost::shared_ptr<detail::future_object_base> future;
detail::future_object_base::waiter_list::iterator wait_iterator;
unsigned index;
count_type index;
registered_waiter(boost::shared_ptr<detail::future_object_base> const& future_,
detail::future_object_base::waiter_list::iterator wait_iterator_,
unsigned index_):
count_type index_):
future(future_),wait_iterator(wait_iterator_),index(index_)
{}
};
struct all_futures_lock
{
unsigned count;
#ifdef _MANAGED
typedef std::ptrdiff_t count_type_portable;
#else
typedef count_type count_type_portable;
#endif
count_type_portable count;
boost::scoped_array<boost::unique_lock<boost::mutex> > locks;
all_futures_lock(std::vector<registered_waiter>& futures):
count(futures.size()),locks(new boost::unique_lock<boost::mutex>[count])
{
for(unsigned i=0;i<count;++i)
for(count_type_portable i=0;i<count;++i)
{
#if defined __DECCXX || defined __SUNPRO_CC
locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex).move();
#else
locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex);
#endif
}
}
void lock()
{
boost::lock(locks.get(),locks.get()+count);
}
void unlock()
{
for(unsigned i=0;i<count;++i)
for(count_type_portable i=0;i<count;++i)
{
locks[i].unlock();
}
}
};
boost::condition_variable_any cv;
std::vector<registered_waiter> futures;
unsigned future_count;
count_type future_count;
public:
future_waiter():
future_count(0)
{}
template<typename F>
void add(F& f)
{
@@ -448,12 +468,12 @@ namespace boost
++future_count;
}
unsigned wait()
count_type wait()
{
all_futures_lock lk(futures);
for(;;)
{
for(unsigned i=0;i<futures.size();++i)
for(count_type i=0;i<futures.size();++i)
{
if(futures[i].future->done)
{
@@ -463,17 +483,17 @@ namespace boost
cv.wait(lk);
}
}
~future_waiter()
{
for(unsigned i=0;i<futures.size();++i)
for(count_type i=0;i<futures.size();++i)
{
futures[i].future->remove_external_waiter(futures[i].wait_iterator);
}
}
};
}
template <typename R>
@@ -487,13 +507,13 @@ namespace boost
{
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct is_future_type<unique_future<T> >
{
BOOST_STATIC_CONSTANT(bool, value=true);
};
template<typename T>
struct is_future_type<shared_future<T> >
{
@@ -523,7 +543,7 @@ namespace boost
f2.wait();
f3.wait();
}
template<typename F1,typename F2,typename F3,typename F4>
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4)
{
@@ -546,6 +566,9 @@ namespace boost
template<typename Iterator>
typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end)
{
if(begin==end)
return end;
detail::future_waiter waiter;
for(Iterator current=begin;current!=end;++current)
{
@@ -572,7 +595,7 @@ namespace boost
waiter.add(f3);
return waiter.wait();
}
template<typename F1,typename F2,typename F3,typename F4>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4)
{
@@ -595,7 +618,7 @@ namespace boost
waiter.add(f5);
return waiter.wait();
}
template <typename R>
class promise;
@@ -609,7 +632,7 @@ namespace boost
unique_future& operator=(unique_future& rhs);// = delete;
typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
future_ptr future;
friend class shared_future<R>;
@@ -628,11 +651,11 @@ namespace boost
unique_future()
{}
~unique_future()
{}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
unique_future(unique_future && other)
{
future.swap(other.future);
@@ -673,12 +696,12 @@ namespace boost
{
if(!future)
{
throw future_uninitialized();
boost::throw_exception(future_uninitialized());
}
return future->get();
}
// functions to check state, and wait for ready
state get_state() const
{
@@ -688,54 +711,61 @@ namespace boost
}
return future->get_state();
}
bool is_ready() const
{
return get_state()==future_state::ready;
}
bool has_exception() const
{
return future && future->has_exception();
}
bool has_value() const
{
return future && future->has_value();
}
void wait() const
{
if(!future)
{
throw future_uninitialized();
boost::throw_exception(future_uninitialized());
}
future->wait(false);
}
template<typename Duration>
bool timed_wait(Duration const& rel_time) const
{
return timed_wait_until(boost::get_system_time()+rel_time);
}
bool timed_wait_until(boost::system_time const& abs_time) const
{
if(!future)
{
throw future_uninitialized();
boost::throw_exception(future_uninitialized());
}
return future->timed_wait_until(abs_time);
}
};
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename T>
struct has_move_emulation_enabled_aux<unique_future<T> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
template <typename R>
class shared_future
{
typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
future_ptr future;
// shared_future(const unique_future<R>& other);
@@ -744,7 +774,7 @@ namespace boost
friend class detail::future_waiter;
friend class promise<R>;
friend class packaged_task<R>;
shared_future(future_ptr future_):
future(future_)
{}
@@ -767,7 +797,7 @@ namespace boost
future=other.future;
return *this;
}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
shared_future(shared_future && other)
{
future.swap(other.future);
@@ -788,7 +818,7 @@ namespace boost
other.future.reset();
return *this;
}
#else
#else
shared_future(boost::detail::thread_move_t<shared_future> other):
future(other->future)
{
@@ -826,16 +856,17 @@ namespace boost
}
// retrieving the value
//typename detail::future_object<R>::move_dest_type get()
R get()
{
if(!future)
{
throw future_uninitialized();
boost::throw_exception(future_uninitialized());
}
return future->get();
}
// functions to check state, and wait for ready
state get_state() const
{
@@ -845,18 +876,18 @@ namespace boost
}
return future->get_state();
}
bool is_ready() const
{
return get_state()==future_state::ready;
}
bool has_exception() const
{
return future && future->has_exception();
}
bool has_value() const
{
return future && future->has_value();
@@ -866,55 +897,62 @@ namespace boost
{
if(!future)
{
throw future_uninitialized();
boost::throw_exception(future_uninitialized());
}
future->wait(false);
}
template<typename Duration>
bool timed_wait(Duration const& rel_time) const
{
return timed_wait_until(boost::get_system_time()+rel_time);
}
bool timed_wait_until(boost::system_time const& abs_time) const
{
if(!future)
{
throw future_uninitialized();
boost::throw_exception(future_uninitialized());
}
return future->timed_wait_until(abs_time);
}
};
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename T>
struct has_move_emulation_enabled_aux<shared_future<T> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
template <typename R>
class promise
{
typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
future_ptr future;
bool future_obtained;
promise(promise & rhs);// = delete;
promise & operator=(promise & rhs);// = delete;
void lazy_init()
{
if(!future)
if(!atomic_load(&future))
{
future_obtained=false;
future.reset(new detail::future_object<R>);
future_ptr blank;
atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<R>));
}
}
public:
// template <class Allocator> explicit promise(Allocator a);
promise():
future(),future_obtained(false)
{}
~promise()
{
if(future)
@@ -929,17 +967,19 @@ namespace boost
}
// Assignment
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
promise(promise && rhs):
future_obtained(rhs.future_obtained)
{
future.swap(rhs.future);
rhs.future_obtained=false;
}
promise & operator=(promise&& rhs)
{
future.swap(rhs.future);
future_obtained=rhs.future_obtained;
rhs.future.reset();
rhs.future_obtained=false;
return *this;
}
#else
@@ -947,12 +987,14 @@ namespace boost
future(rhs->future),future_obtained(rhs->future_obtained)
{
rhs->future.reset();
rhs->future_obtained=false;
}
promise & operator=(boost::detail::thread_move_t<promise> rhs)
{
future=rhs->future;
future_obtained=rhs->future_obtained;
rhs->future.reset();
rhs->future_obtained=false;
return *this;
}
@@ -960,8 +1002,8 @@ namespace boost
{
return boost::detail::thread_move_t<promise>(*this);
}
#endif
#endif
void swap(promise& other)
{
future.swap(other.future);
@@ -974,7 +1016,7 @@ namespace boost
lazy_init();
if(future_obtained)
{
throw future_already_retrieved();
boost::throw_exception(future_already_retrieved());
}
future_obtained=true;
return unique_future<R>(future);
@@ -986,7 +1028,7 @@ namespace boost
boost::lock_guard<boost::mutex> lock(future->mutex);
if(future->done)
{
throw promise_already_satisfied();
boost::throw_exception(promise_already_satisfied());
}
future->mark_finished_with_result_internal(r);
}
@@ -998,7 +1040,7 @@ namespace boost
boost::lock_guard<boost::mutex> lock(future->mutex);
if(future->done)
{
throw promise_already_satisfied();
boost::throw_exception(promise_already_satisfied());
}
future->mark_finished_with_result_internal(static_cast<typename detail::future_traits<R>::rvalue_source_type>(r));
}
@@ -1009,7 +1051,7 @@ namespace boost
boost::lock_guard<boost::mutex> lock(future->mutex);
if(future->done)
{
throw promise_already_satisfied();
boost::throw_exception(promise_already_satisfied());
}
future->mark_exceptional_finish_internal(p);
}
@@ -1020,26 +1062,26 @@ namespace boost
lazy_init();
future->set_wait_callback(f,this);
}
};
template <>
class promise<void>
{
typedef boost::shared_ptr<detail::future_object<void> > future_ptr;
future_ptr future;
bool future_obtained;
promise(promise & rhs);// = delete;
promise & operator=(promise & rhs);// = delete;
void lazy_init()
{
if(!future)
if(!atomic_load(&future))
{
future_obtained=false;
future.reset(new detail::future_object<void>);
future_ptr blank;
atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<void>));
}
}
public:
@@ -1048,7 +1090,7 @@ namespace boost
promise():
future(),future_obtained(false)
{}
~promise()
{
if(future)
@@ -1063,17 +1105,19 @@ namespace boost
}
// Assignment
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
promise(promise && rhs):
future_obtained(rhs.future_obtained)
{
future.swap(rhs.future);
rhs.future_obtained=false;
}
promise & operator=(promise&& rhs)
{
future.swap(rhs.future);
future_obtained=rhs.future_obtained;
rhs.future.reset();
rhs.future_obtained=false;
return *this;
}
#else
@@ -1081,12 +1125,14 @@ namespace boost
future(rhs->future),future_obtained(rhs->future_obtained)
{
rhs->future.reset();
rhs->future_obtained=false;
}
promise & operator=(boost::detail::thread_move_t<promise> rhs)
{
future=rhs->future;
future_obtained=rhs->future_obtained;
rhs->future.reset();
rhs->future_obtained=false;
return *this;
}
@@ -1095,7 +1141,7 @@ namespace boost
return boost::detail::thread_move_t<promise>(*this);
}
#endif
void swap(promise& other)
{
future.swap(other.future);
@@ -1106,10 +1152,10 @@ namespace boost
unique_future<void> get_future()
{
lazy_init();
if(future_obtained)
{
throw future_already_retrieved();
boost::throw_exception(future_already_retrieved());
}
future_obtained=true;
return unique_future<void>(future);
@@ -1121,7 +1167,7 @@ namespace boost
boost::lock_guard<boost::mutex> lock(future->mutex);
if(future->done)
{
throw promise_already_satisfied();
boost::throw_exception(promise_already_satisfied());
}
future->mark_finished_with_result_internal();
}
@@ -1132,7 +1178,7 @@ namespace boost
boost::lock_guard<boost::mutex> lock(future->mutex);
if(future->done)
{
throw promise_already_satisfied();
boost::throw_exception(promise_already_satisfied());
}
future->mark_exceptional_finish_internal(p);
}
@@ -1143,9 +1189,16 @@ namespace boost
lazy_init();
future->set_wait_callback(f,this);
}
};
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename T>
struct has_move_emulation_enabled_aux<promise<T> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
namespace detail
{
template<typename R>
@@ -1164,7 +1217,7 @@ namespace boost
boost::lock_guard<boost::mutex> lk(this->mutex);
if(started)
{
throw task_already_started();
boost::throw_exception(task_already_started());
}
started=true;
}
@@ -1180,12 +1233,12 @@ namespace boost
this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise()));
}
}
virtual void do_run()=0;
};
template<typename R,typename F>
struct task_object:
task_base<R>
@@ -1194,10 +1247,16 @@ namespace boost
task_object(F const& f_):
f(f_)
{}
#ifndef BOOST_NO_RVALUE_REFERENCES
task_object(F&& f_):
f(f_)
{}
#else
task_object(boost::detail::thread_move_t<F> f_):
f(f_)
{}
#endif
void do_run()
{
try
@@ -1219,10 +1278,16 @@ namespace boost
task_object(F const& f_):
f(f_)
{}
#ifndef BOOST_NO_RVALUE_REFERENCES
task_object(F&& f_):
f(f_)
{}
#else
task_object(boost::detail::thread_move_t<F> f_):
f(f_)
{}
#endif
void do_run()
{
try
@@ -1238,7 +1303,7 @@ namespace boost
};
}
template<typename R>
class packaged_task
@@ -1248,12 +1313,12 @@ namespace boost
packaged_task(packaged_task&);// = delete;
packaged_task& operator=(packaged_task&);// = delete;
public:
packaged_task():
future_obtained(false)
{}
// construction and destruction
template <class F>
explicit packaged_task(F const& f):
@@ -1262,11 +1327,18 @@ namespace boost
explicit packaged_task(R(*f)()):
task(new detail::task_object<R,R(*)()>(f)),future_obtained(false)
{}
#ifndef BOOST_NO_RVALUE_REFERENCES
template <class F>
explicit packaged_task(F&& f):
task(new detail::task_object<R,F>(f)),future_obtained(false)
{}
#else
template <class F>
explicit packaged_task(boost::detail::thread_move_t<F> f):
task(new detail::task_object<R,F>(f)),future_obtained(false)
{}
#endif
// template <class F, class Allocator>
// explicit packaged_task(F const& f, Allocator a);
@@ -1283,7 +1355,7 @@ namespace boost
}
// assignment
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
packaged_task(packaged_task&& other):
future_obtained(other.future_obtained)
{
@@ -1315,7 +1387,7 @@ namespace boost
}
#endif
void swap(packaged_task& other)
void swap(packaged_task& other)
{
task.swap(other.task);
std::swap(future_obtained,other.future_obtained);
@@ -1326,7 +1398,7 @@ namespace boost
{
if(!task)
{
throw task_moved();
boost::throw_exception(task_moved());
}
else if(!future_obtained)
{
@@ -1335,17 +1407,17 @@ namespace boost
}
else
{
throw future_already_retrieved();
boost::throw_exception(future_already_retrieved());
}
}
// execution
void operator()()
{
if(!task)
{
throw task_moved();
boost::throw_exception(task_moved());
}
task->run();
}
@@ -1355,9 +1427,16 @@ namespace boost
{
task->set_wait_callback(f,this);
}
};
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename T>
struct has_move_emulation_enabled_aux<packaged_task<T> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
}

View File

@@ -11,6 +11,7 @@
#include <iterator>
#include <boost/thread/thread_time.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -27,56 +28,118 @@ namespace boost
#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
namespace detail
{
template<typename T>
#define BOOST_DEFINE_HAS_MEMBER_CALLED(member_name) \
template<typename T, bool=boost::is_class<T>::value> \
struct has_member_called_##member_name \
{ \
BOOST_STATIC_CONSTANT(bool, value=false); \
}; \
\
template<typename T> \
struct has_member_called_##member_name<T,true> \
{ \
typedef char true_type; \
struct false_type \
{ \
true_type dummy[2]; \
}; \
\
struct fallback { int member_name; }; \
struct derived: \
T, fallback \
{ \
derived(); \
}; \
\
template<int fallback::*> struct tester; \
\
template<typename U> \
static false_type has_member(tester<&U::member_name>*); \
template<typename U> \
static true_type has_member(...); \
\
BOOST_STATIC_CONSTANT( \
bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \
}
BOOST_DEFINE_HAS_MEMBER_CALLED(lock);
BOOST_DEFINE_HAS_MEMBER_CALLED(unlock);
BOOST_DEFINE_HAS_MEMBER_CALLED(try_lock);
template<typename T,bool=has_member_called_lock<T>::value >
struct has_member_lock
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U>
static true_type has_member(U*,void (U::*dummy)()=&U::lock);
static false_type has_member(void*);
BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_lock<T>::has_member((T*)NULL))==sizeof(true_type));
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct has_member_lock<T,true>
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U,typename V>
static true_type has_member(V (U::*)());
template<typename U>
static false_type has_member(U);
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type));
};
template<typename T,bool=has_member_called_unlock<T>::value >
struct has_member_unlock
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U>
static true_type has_member(U*,void (U::*dummy)()=&U::unlock);
static false_type has_member(void*);
BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_unlock<T>::has_member((T*)NULL))==sizeof(true_type));
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct has_member_try_lock
struct has_member_unlock<T,true>
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U,typename V>
static true_type has_member(V (U::*)());
template<typename U>
static true_type has_member(U*,bool (U::*dummy)()=&U::try_lock);
static false_type has_member(void*);
BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_try_lock<T>::has_member((T*)NULL))==sizeof(true_type));
static false_type has_member(U);
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type));
};
template<typename T,bool=has_member_called_try_lock<T>::value >
struct has_member_try_lock
{
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct has_member_try_lock<T,true>
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U>
static true_type has_member(bool (U::*)());
template<typename U>
static false_type has_member(U);
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
};
}
template<typename T>
struct is_mutex_type
@@ -84,7 +147,7 @@ namespace boost
BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
detail::has_member_unlock<T>::value &&
detail::has_member_try_lock<T>::value);
};
#else
template<typename T>
@@ -92,7 +155,7 @@ namespace boost
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
#endif
#endif
struct defer_lock_t
{};
@@ -100,7 +163,7 @@ namespace boost
{};
struct adopt_lock_t
{};
const defer_lock_t defer_lock={};
const try_to_lock_t try_to_lock={};
const adopt_lock_t adopt_lock={};
@@ -119,7 +182,7 @@ namespace boost
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> >
@@ -138,7 +201,7 @@ namespace boost
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<typename T>
struct is_mutex_type<detail::try_lock_wrapper<T> >
{
@@ -150,7 +213,7 @@ namespace boost
class recursive_mutex;
class recursive_timed_mutex;
class shared_mutex;
template<>
struct is_mutex_type<mutex>
{
@@ -214,13 +277,13 @@ namespace boost
unique_lock& operator=(unique_lock&);
unique_lock& operator=(upgrade_lock<Mutex>& other);
public:
#ifdef __SUNPRO_CC
unique_lock(const volatile unique_lock&);
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
unique_lock(const volatile unique_lock&);
#endif
unique_lock():
m(0),is_locked(false)
{}
explicit unique_lock(Mutex& m_):
m(&m_),is_locked(false)
{
@@ -248,7 +311,7 @@ namespace boost
{
timed_lock(target_time);
}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
unique_lock(unique_lock&& other):
m(other.m),is_locked(other.is_locked)
{
@@ -300,12 +363,12 @@ namespace boost
return detail::thread_move_t<unique_lock<Mutex> >(*this);
}
#ifdef __SUNPRO_CC
unique_lock& operator=(unique_lock<Mutex> other)
{
swap(other);
return *this;
}
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
unique_lock& operator=(unique_lock<Mutex> other)
{
swap(other);
return *this;
}
#else
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
{
@@ -321,18 +384,18 @@ namespace boost
swap(temp);
return *this;
}
void swap(unique_lock& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
void swap(detail::thread_move_t<unique_lock<Mutex> > other)
{
std::swap(m,other->m);
std::swap(is_locked,other->is_locked);
}
#endif
void swap(unique_lock& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
~unique_lock()
{
if(owns_lock())
@@ -344,7 +407,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
m->lock();
is_locked=true;
@@ -353,7 +416,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
is_locked=m->try_lock();
return is_locked;
@@ -364,7 +427,7 @@ namespace boost
is_locked=m->timed_lock(relative_time);
return is_locked;
}
bool timed_lock(::boost::system_time const& absolute_time)
{
is_locked=m->timed_lock(absolute_time);
@@ -379,12 +442,12 @@ namespace boost
{
if(!owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
m->unlock();
is_locked=false;
}
typedef void (unique_lock::*bool_type)();
operator bool_type() const
{
@@ -416,26 +479,50 @@ namespace boost
friend class upgrade_lock<Mutex>;
};
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename Mutex>
void swap(unique_lock<Mutex>&& lhs,unique_lock<Mutex>&& rhs)
{
lhs.swap(rhs);
}
#else
template<typename Mutex>
inline upgrade_lock<Mutex>&& move(upgrade_lock<Mutex>&& ul)
{
return static_cast<upgrade_lock<Mutex>&&>(ul);
}
template<typename Mutex>
inline upgrade_lock<Mutex>&& move(upgrade_lock<Mutex>& ul)
{
return static_cast<upgrade_lock<Mutex>&&>(ul);
}
#endif
template<typename Mutex>
void swap(unique_lock<Mutex>& lhs,unique_lock<Mutex>& rhs)
{
lhs.swap(rhs);
}
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename Mutex>
inline unique_lock<Mutex>&& move(unique_lock<Mutex>&& ul)
{
return ul;
return static_cast<unique_lock<Mutex>&&>(ul);
}
template<typename Mutex>
inline unique_lock<Mutex>&& move(unique_lock<Mutex>& ul)
{
return static_cast<unique_lock<Mutex>&&>(ul);
}
#endif
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename Mutex>
struct has_move_emulation_enabled_aux<unique_lock<Mutex> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
template<typename Mutex>
@@ -451,7 +538,7 @@ namespace boost
shared_lock():
m(0),is_locked(false)
{}
explicit shared_lock(Mutex& m_):
m(&m_),is_locked(false)
{
@@ -473,7 +560,9 @@ namespace boost
{
timed_lock(target_time);
}
#ifndef BOOST_NO_RVALUE_REFERENCES
#else
shared_lock(detail::thread_move_t<shared_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
@@ -534,31 +623,32 @@ namespace boost
swap(temp);
return *this;
}
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
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
void swap(shared_lock& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
Mutex* mutex() const
{
return m;
}
~shared_lock()
{
if(owns_lock())
@@ -570,7 +660,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
m->lock_shared();
is_locked=true;
@@ -579,7 +669,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
is_locked=m->try_lock_shared();
return is_locked;
@@ -588,7 +678,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
is_locked=m->timed_lock_shared(target_time);
return is_locked;
@@ -598,7 +688,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
is_locked=m->timed_lock_shared(target_time);
return is_locked;
@@ -607,12 +697,12 @@ namespace boost
{
if(!owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
m->unlock_shared();
is_locked=false;
}
typedef void (shared_lock<Mutex>::*bool_type)();
operator bool_type() const
{
@@ -629,12 +719,25 @@ namespace boost
};
#ifdef BOOST_HAS_RVALUE_REFS
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename Mutex>
struct has_move_emulation_enabled_aux<shared_lock<Mutex> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename Mutex>
void swap(shared_lock<Mutex>&& lhs,shared_lock<Mutex>&& rhs)
{
lhs.swap(rhs);
}
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)
@@ -656,7 +759,7 @@ namespace boost
upgrade_lock():
m(0),is_locked(false)
{}
explicit upgrade_lock(Mutex& m_):
m(&m_),is_locked(false)
{
@@ -673,6 +776,39 @@ namespace boost
{
try_lock();
}
#ifndef BOOST_NO_RVALUE_REFERENCES
upgrade_lock(upgrade_lock<Mutex>&& other):
m(other.m),is_locked(other.is_locked)
{
other.is_locked=false;
other.m=0;
}
upgrade_lock(unique_lock<Mutex>&& other):
m(other.m),is_locked(other.is_locked)
{
if(is_locked)
{
m->unlock_and_lock_upgrade();
}
other.is_locked=false;
other.m=0;
}
upgrade_lock& operator=(upgrade_lock<Mutex>&& other)
{
upgrade_lock temp(static_cast<upgrade_lock<Mutex>&&>(other));
swap(temp);
return *this;
}
upgrade_lock& operator=(unique_lock<Mutex>&& other)
{
upgrade_lock temp(static_cast<unique_lock<Mutex>&&>(other));
swap(temp);
return *this;
}
#else
upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
@@ -715,13 +851,14 @@ namespace boost
swap(temp);
return *this;
}
#endif
void swap(upgrade_lock& other)
{
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
~upgrade_lock()
{
if(owns_lock())
@@ -733,7 +870,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
m->lock_upgrade();
is_locked=true;
@@ -742,7 +879,7 @@ namespace boost
{
if(owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
is_locked=m->try_lock_upgrade();
return is_locked;
@@ -751,12 +888,12 @@ namespace boost
{
if(!owns_lock())
{
throw boost::lock_error();
boost::throw_exception(boost::lock_error());
}
m->unlock_upgrade();
is_locked=false;
}
typedef void (upgrade_lock::*bool_type)();
operator bool_type() const
{
@@ -774,8 +911,14 @@ namespace boost
friend class unique_lock<Mutex>;
};
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename Mutex>
struct has_move_emulation_enabled_aux<upgrade_lock<Mutex> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename Mutex>
unique_lock<Mutex>::unique_lock(upgrade_lock<Mutex>&& other):
m(other.m),is_locked(other.is_locked)
@@ -819,18 +962,33 @@ namespace boost
}
}
#ifndef BOOST_NO_RVALUE_REFERENCES
upgrade_to_unique_lock(upgrade_to_unique_lock<Mutex>&& other):
source(other.source),exclusive(move(other.exclusive))
{
other.source=0;
}
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Mutex>&& other)
{
upgrade_to_unique_lock temp(other);
swap(temp);
return *this;
}
#else
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(move(other->exclusive))
{
other->source=0;
}
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other)
{
upgrade_to_unique_lock temp(other);
swap(temp);
return *this;
}
#endif
void swap(upgrade_to_unique_lock& other)
{
std::swap(source,other.source);
@@ -851,6 +1009,13 @@ namespace boost
}
};
#ifdef BOOST_NO_RVALUE_REFERENCES
template <typename Mutex>
struct has_move_emulation_enabled_aux<upgrade_to_unique_lock<Mutex> >
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
#endif
namespace detail
{
template<typename Mutex>
@@ -861,7 +1026,7 @@ namespace boost
public:
try_lock_wrapper()
{}
explicit try_lock_wrapper(Mutex& m):
base(m,try_to_lock)
{}
@@ -875,7 +1040,7 @@ namespace boost
try_lock_wrapper(Mutex& m_,try_to_lock_t):
base(m_,try_to_lock)
{}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
try_lock_wrapper(try_lock_wrapper&& other):
base(other.move())
{}
@@ -918,15 +1083,15 @@ namespace boost
return *this;
}
void swap(try_lock_wrapper& other)
{
base::swap(other);
}
void swap(detail::thread_move_t<try_lock_wrapper<Mutex> > other)
{
base::swap(*other);
}
#endif
void swap(try_lock_wrapper& other)
{
base::swap(other);
}
void lock()
{
base::lock();
@@ -963,12 +1128,17 @@ namespace boost
}
};
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename Mutex>
void swap(try_lock_wrapper<Mutex>&& lhs,try_lock_wrapper<Mutex>&& rhs)
{
lhs.swap(rhs);
}
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)
@@ -976,7 +1146,7 @@ namespace boost
lhs.swap(rhs);
}
#endif
template<typename MutexType1,typename MutexType2>
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2)
{
@@ -1105,13 +1275,13 @@ namespace boost
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>)
{
unsigned const lock_count=2;
unsigned lock_first=0;
while(true)
for(;;)
{
switch(lock_first)
{
@@ -1133,7 +1303,7 @@ namespace boost
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)
@@ -1164,7 +1334,7 @@ namespace boost
{
unsigned const lock_count=3;
unsigned lock_first=0;
while(true)
for(;;)
{
switch(lock_first)
{
@@ -1196,7 +1366,7 @@ namespace boost
{
unsigned const lock_count=4;
unsigned lock_first=0;
while(true)
for(;;)
{
switch(lock_first)
{
@@ -1234,7 +1404,7 @@ namespace boost
{
unsigned const lock_count=5;
unsigned lock_first=0;
while(true)
for(;;)
{
switch(lock_first)
{
@@ -1278,7 +1448,7 @@ namespace boost
{
typedef int type;
};
template<typename Iterator>
struct try_lock_impl_return<Iterator,false>
{
@@ -1294,7 +1464,7 @@ namespace boost
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)
{
@@ -1336,7 +1506,7 @@ namespace boost
{
return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1;
}
namespace detail
{
@@ -1345,13 +1515,13 @@ namespace boost
{
Iterator begin;
Iterator end;
range_lock_guard(Iterator begin_,Iterator end_):
begin(begin_),end(end_)
{
lock(begin,end);
boost::lock(begin,end);
}
void release()
{
begin=end;
@@ -1376,21 +1546,21 @@ namespace boost
}
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);
Iterator const failed=boost::try_lock(++begin,end);
if(failed==end)
{
guard.release();
}
return failed;
}
}
namespace detail
{
@@ -1398,7 +1568,7 @@ namespace boost
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;
@@ -1407,14 +1577,14 @@ namespace boost
Iterator second=begin;
++second;
Iterator next=second;
for(;;)
{
unique_lock<lock_type> begin_lock(*begin,defer_lock);
if(start_with_begin)
{
begin_lock.lock();
Iterator const failed_lock=try_lock(next,end);
Iterator const failed_lock=boost::try_lock(next,end);
if(failed_lock==end)
{
begin_lock.release();
@@ -1428,7 +1598,7 @@ namespace boost
detail::range_lock_guard<Iterator> guard(next,end);
if(begin_lock.try_lock())
{
Iterator const failed_lock=try_lock(second,next);
Iterator const failed_lock=boost::try_lock(second,next);
if(failed_lock==next)
{
begin_lock.release();
@@ -1446,9 +1616,9 @@ namespace boost
}
}
}
}
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -3,53 +3,107 @@
// 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
// (C) Copyright 2007-10 Anthony Williams
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
#include "thread_data.hpp"
#include "condition_variable_fwd.hpp"
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/thread/pthread/thread_data.hpp>
#include <boost/thread/pthread/condition_variable_fwd.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace this_thread
{
void BOOST_THREAD_DECL interruption_point();
}
namespace thread_cv_detail
{
template<typename MutexType>
struct lock_on_exit
{
MutexType* m;
lock_on_exit():
m(0)
{}
void activate(MutexType& m_)
{
m_.unlock();
m=&m_;
}
~lock_on_exit()
{
if(m)
{
m->lock();
}
}
};
}
inline void condition_variable::wait(unique_lock<mutex>& m)
{
detail::interruption_checker check_for_interruption(&cond);
BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
int res=0;
{
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
guard.activate(m);
do {
res = pthread_cond_wait(&cond,&internal_mutex);
} while (res == EINTR);
}
this_thread::interruption_point();
if(res)
{
boost::throw_exception(condition_error());
}
}
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
{
detail::interruption_checker check_for_interruption(&cond);
struct timespec const timeout=detail::get_timespec(wait_until);
int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout);
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
int cond_res;
{
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
guard.activate(m);
struct timespec const timeout=detail::get_timespec(wait_until);
cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
}
this_thread::interruption_point();
if(cond_res==ETIMEDOUT)
{
return false;
}
BOOST_ASSERT(!cond_res);
if(cond_res)
{
boost::throw_exception(condition_error());
}
return true;
}
inline void condition_variable::notify_one()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
inline void condition_variable::notify_all()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
}
class condition_variable_any
{
pthread_mutex_t internal_mutex;
pthread_cond_t cond;
condition_variable_any(condition_variable&);
condition_variable_any& operator=(condition_variable&);
condition_variable_any(condition_variable_any&);
condition_variable_any& operator=(condition_variable_any&);
public:
condition_variable_any()
@@ -57,13 +111,13 @@ namespace boost
int const res=pthread_mutex_init(&internal_mutex,NULL);
if(res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
}
~condition_variable_any()
@@ -71,23 +125,21 @@ namespace boost
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
template<typename lock_type>
void wait(lock_type& m)
{
int res=0;
{
detail::interruption_checker check_for_interruption(&cond);
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
m.unlock();
res=pthread_cond_wait(&cond,&internal_mutex);
}
m.lock();
thread_cv_detail::lock_on_exit<lock_type> guard;
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
guard.activate(m);
res=pthread_cond_wait(&cond,&internal_mutex);
}
this_thread::interruption_point();
if(res)
{
throw condition_error();
boost::throw_exception(condition_error());
}
}
@@ -96,28 +148,26 @@ namespace boost
{
while(!pred()) wait(m);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
{
struct timespec const timeout=detail::get_timespec(wait_until);
int res=0;
{
detail::interruption_checker check_for_interruption(&cond);
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
m.unlock();
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
}
m.lock();
thread_cv_detail::lock_on_exit<lock_type> guard;
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
guard.activate(m);
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
}
this_thread::interruption_point();
if(res==ETIMEDOUT)
{
return false;
}
if(res)
{
throw condition_error();
boost::throw_exception(condition_error());
}
return true;
}
@@ -161,7 +211,7 @@ namespace boost
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
void notify_all()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);

View File

@@ -6,6 +6,7 @@
// (C) Copyright 2007-8 Anthony Williams
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
@@ -19,23 +20,35 @@ namespace boost
class condition_variable
{
private:
pthread_mutex_t internal_mutex;
pthread_cond_t cond;
condition_variable(condition_variable&);
condition_variable& operator=(condition_variable&);
public:
condition_variable()
{
int const res=pthread_cond_init(&cond,NULL);
int const res=pthread_mutex_init(&internal_mutex,NULL);
if(res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
boost::throw_exception(thread_resource_error());
}
}
~condition_variable()
{
BOOST_VERIFY(!pthread_cond_destroy(&cond));
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
int ret;
do {
ret = pthread_cond_destroy(&cond);
} while (ret == EINTR);
BOOST_VERIFY(!ret);
}
void wait(unique_lock<mutex>& m);
@@ -46,7 +59,8 @@ namespace boost
while(!pred()) wait(m);
}
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until);
inline 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));

View File

@@ -7,17 +7,18 @@
#include <pthread.h>
#include <boost/utility.hpp>
#include <boost/throw_exception.hpp>
#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"
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#ifdef _POSIX_TIMEOUTS
#if _POSIX_TIMEOUTS >= 0
#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif
@@ -26,10 +27,11 @@
namespace boost
{
class mutex:
boost::noncopyable
class mutex
{
private:
mutex(mutex const&);
mutex& operator=(mutex const&);
pthread_mutex_t m;
public:
mutex()
@@ -37,28 +39,53 @@ namespace boost
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
}
~mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
int ret;
do
{
ret = pthread_mutex_destroy(&m);
} while (ret == EINTR);
}
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
int res;
do
{
res = pthread_mutex_lock(&m);
} while (res == EINTR);
if(res)
{
boost::throw_exception(lock_error(res));
}
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
int ret;
do
{
ret = pthread_mutex_unlock(&m);
} while (ret == EINTR);
BOOST_VERIFY(!ret);
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
int res;
do
{
res = pthread_mutex_trylock(&m);
} while (res == EINTR);
if(res && (res!=EBUSY))
{
boost::throw_exception(lock_error(res));
}
return !res;
}
@@ -74,9 +101,11 @@ namespace boost
typedef mutex try_mutex;
class timed_mutex:
boost::noncopyable
class timed_mutex
{
private:
timed_mutex(timed_mutex const&);
timed_mutex& operator=(timed_mutex const&);
private:
pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
@@ -89,14 +118,14 @@ namespace boost
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
is_locked=false;
#endif
@@ -129,7 +158,7 @@ namespace boost
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
@@ -167,7 +196,7 @@ namespace boost
is_locked=false;
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);

View File

@@ -3,17 +3,17 @@
// once.hpp
//
// (C) Copyright 2007-8 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/config.hpp>
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
@@ -34,7 +34,7 @@ namespace boost
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
}
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
@@ -48,7 +48,7 @@ namespace boost
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
boost::uintmax_t const epoch=flag.epoch;
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
if(epoch<this_thread_epoch)
{
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
@@ -58,10 +58,13 @@ namespace boost
if(flag.epoch==uninitialized_flag)
{
flag.epoch=being_initialized;
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
f();
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
@@ -69,6 +72,7 @@ namespace boost
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
throw;
}
#endif
flag.epoch=--detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
}

View File

@@ -18,15 +18,25 @@ namespace boost
class pthread_mutex_scoped_lock
{
pthread_mutex_t* m;
bool locked;
public:
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
m(m_)
m(m_),locked(true)
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
~pthread_mutex_scoped_lock()
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
locked=false;
}
~pthread_mutex_scoped_lock()
{
if(locked)
{
unlock();
}
}
};

View File

@@ -7,6 +7,7 @@
#include <pthread.h>
#include <boost/utility.hpp>
#include <boost/throw_exception.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
@@ -16,8 +17,8 @@
#endif
#include <boost/date_time/posix_time/conversion.hpp>
#include <errno.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#ifdef _POSIX_TIMEOUTS
#if _POSIX_TIMEOUTS >= 0
@@ -25,43 +26,76 @@
#endif
#endif
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK)
#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class recursive_mutex:
boost::noncopyable
class recursive_mutex
{
private:
recursive_mutex(recursive_mutex const&);
recursive_mutex& operator=(recursive_mutex const&);
pthread_mutex_t m;
#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
pthread_cond_t cond;
bool is_locked;
pthread_t owner;
unsigned count;
#endif
public:
recursive_mutex()
{
#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
pthread_mutexattr_t attr;
int const init_attr_res=pthread_mutexattr_init(&attr);
if(init_attr_res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
if(set_attr_res)
{
throw thread_resource_error();
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
boost::throw_exception(thread_resource_error());
}
int const res=pthread_mutex_init(&m,&attr);
if(res)
{
throw thread_resource_error();
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
boost::throw_exception(thread_resource_error());
}
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
#else
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
boost::throw_exception(thread_resource_error());
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
boost::throw_exception(thread_resource_error());
}
is_locked=false;
count=0;
#endif
}
~recursive_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
@@ -71,32 +105,77 @@ namespace boost
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
#else
void lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && pthread_equal(owner,pthread_self()))
{
++count;
return;
}
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
}
is_locked=true;
++count;
owner=pthread_self();
}
void unlock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(!--count)
{
is_locked=false;
}
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && !pthread_equal(owner,pthread_self()))
{
return false;
}
is_locked=true;
++count;
owner=pthread_self();
return true;
}
#endif
typedef unique_lock<recursive_mutex> scoped_lock;
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
};
typedef recursive_mutex recursive_try_mutex;
class recursive_timed_mutex:
boost::noncopyable
class recursive_timed_mutex
{
private:
recursive_timed_mutex(recursive_timed_mutex const&);
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
private:
pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
pthread_cond_t cond;
bool is_locked;
pthread_t owner;
@@ -105,38 +184,38 @@ namespace boost
public:
recursive_timed_mutex()
{
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
pthread_mutexattr_t attr;
int const init_attr_res=pthread_mutexattr_init(&attr);
if(init_attr_res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
if(set_attr_res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
int const res=pthread_mutex_init(&m,&attr);
if(res)
{
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
#else
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
is_locked=false;
count=0;
@@ -145,7 +224,7 @@ namespace boost
~recursive_timed_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
@@ -156,7 +235,7 @@ namespace boost
return timed_lock(get_system_time()+relative_time);
}
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
@@ -166,7 +245,7 @@ namespace boost
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
@@ -196,7 +275,7 @@ namespace boost
++count;
return;
}
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
@@ -215,7 +294,7 @@ namespace boost
}
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);

View File

@@ -27,7 +27,7 @@ namespace boost
bool upgrade;
bool exclusive_waiting_blocked;
};
state_data state;
@@ -41,7 +41,7 @@ namespace boost
exclusive_cond.notify_one();
shared_cond.notify_all();
}
public:
shared_mutex()
@@ -58,7 +58,7 @@ namespace boost
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked)
{
shared_cond.wait(lk);
@@ -69,7 +69,7 @@ namespace boost
bool try_lock_shared()
{
boost::mutex::scoped_lock lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked)
{
return false;
@@ -85,7 +85,7 @@ namespace boost
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked)
{
if(!shared_cond.timed_wait(lk,timeout))
@@ -107,7 +107,7 @@ namespace boost
{
boost::mutex::scoped_lock lk(state_change);
bool const last_reader=!--state.shared_count;
if(last_reader)
{
if(state.upgrade)
@@ -128,7 +128,7 @@ namespace boost
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
@@ -150,7 +150,7 @@ namespace boost
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
exclusive_cond.notify_one();
release_waiters();
return false;
}
break;
@@ -169,7 +169,7 @@ namespace boost
bool try_lock()
{
boost::mutex::scoped_lock lk(state_change);
if(state.shared_count || state.exclusive)
{
return false;
@@ -179,7 +179,7 @@ namespace boost
state.exclusive=true;
return true;
}
}
void unlock()
@@ -225,7 +225,7 @@ namespace boost
template<typename TimeDuration>
bool timed_lock_upgrade(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
return timed_lock_upgrade(get_system_time()+relative_time);
}
bool try_lock_upgrade()
@@ -248,7 +248,7 @@ namespace boost
boost::mutex::scoped_lock lk(state_change);
state.upgrade=false;
bool const last_reader=!--state.shared_count;
if(last_reader)
{
state.exclusive_waiting_blocked=false;
@@ -278,7 +278,7 @@ namespace boost
state.exclusive_waiting_blocked=false;
release_waiters();
}
void unlock_and_lock_shared()
{
boost::mutex::scoped_lock lk(state_change);
@@ -287,7 +287,7 @@ namespace boost
state.exclusive_waiting_blocked=false;
release_waiters();
}
void unlock_upgrade_and_lock_shared()
{
boost::mutex::scoped_lock lk(state_change);

View File

@@ -12,7 +12,8 @@
#include <boost/thread/mutex.hpp>
#include <boost/optional.hpp>
#include <pthread.h>
#include "condition_variable_fwd.hpp"
#include <boost/assert.hpp>
#include <boost/thread/pthread/condition_variable_fwd.hpp>
#include <map>
#include <boost/config/abi_prefix.hpp>
@@ -20,7 +21,7 @@
namespace boost
{
class thread;
namespace detail
{
struct tss_cleanup_function;
@@ -38,7 +39,7 @@ namespace boost
struct thread_data_base;
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
struct BOOST_THREAD_DECL thread_data_base:
enable_shared_from_this<thread_data_base>
{
@@ -55,6 +56,7 @@ namespace boost
std::map<void const*,boost::detail::tss_data_node> tss_data;
bool interrupt_enabled;
bool interrupt_requested;
pthread_mutex_t* cond_mutex;
pthread_cond_t* current_cond;
thread_data_base():
@@ -76,6 +78,8 @@ namespace boost
class interruption_checker
{
thread_data_base* const thread_info;
pthread_mutex_t* m;
bool set;
void check_for_interruption()
{
@@ -85,26 +89,38 @@ namespace boost
throw thread_interrupted();
}
}
void operator=(interruption_checker&);
public:
explicit interruption_checker(pthread_cond_t* cond):
thread_info(detail::get_current_thread_data())
explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
thread_info(detail::get_current_thread_data()),m(cond_mutex),
set(thread_info && thread_info->interrupt_enabled)
{
if(thread_info && thread_info->interrupt_enabled)
if(set)
{
lock_guard<mutex> guard(thread_info->data_mutex);
check_for_interruption();
thread_info->cond_mutex=cond_mutex;
thread_info->current_cond=cond;
BOOST_VERIFY(!pthread_mutex_lock(m));
}
else
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
}
~interruption_checker()
{
if(thread_info && thread_info->interrupt_enabled)
if(set)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
lock_guard<mutex> guard(thread_info->data_mutex);
thread_info->cond_mutex=NULL;
thread_info->current_cond=NULL;
check_for_interruption();
}
else
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
}
};
@@ -113,14 +129,26 @@ namespace boost
namespace this_thread
{
void BOOST_THREAD_DECL yield();
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
#ifdef __DECXXX
/// Workaround of DECCXX issue of incorrect template substitution
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
{
this_thread::sleep(get_system_time()+rel_time);
}
template<>
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
#else
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
template<typename TimeDuration>
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
{
this_thread::sleep(get_system_time()+rel_time);
}
#endif
}
}

View File

@@ -17,7 +17,7 @@ namespace boost
return new T();
}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename T,typename A1>
inline T* heap_new(A1&& a1)
{

View File

@@ -6,6 +6,7 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/date_time/time_clock.hpp>
#include <boost/date_time/microsec_time_clock.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
@@ -17,7 +18,11 @@ namespace boost
inline system_time get_system_time()
{
#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
return boost::date_time::microsec_clock<system_time>::universal_time();
#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
return boost::date_time::second_clock<system_time>::universal_time();
#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
}
namespace detail

View File

@@ -62,6 +62,8 @@ namespace boost
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
typedef T element_type;
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}

View File

@@ -3,14 +3,14 @@
// basic_recursive_mutex.hpp
//
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2006-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "thread_primitives.hpp"
#include "basic_timed_mutex.hpp"
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/basic_timed_mutex.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -42,7 +42,7 @@ namespace boost
long const current_thread_id=win32::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
}
void lock()
{
long const current_thread_id=win32::GetCurrentThreadId();
@@ -83,7 +83,7 @@ namespace boost
}
return false;
}
bool try_basic_lock(long current_thread_id)
{
if(mutex.try_lock())
@@ -94,7 +94,7 @@ namespace boost
}
return false;
}
bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
{
if(mutex.timed_lock(target))
@@ -105,7 +105,7 @@ namespace boost
}
return false;
}
};
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;

View File

@@ -3,15 +3,15 @@
// basic_timed_mutex_win32.hpp
//
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2006-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
#include "thread_primitives.hpp"
#include "interlocked_read.hpp"
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/detail/interlocked.hpp>
@@ -52,24 +52,39 @@ namespace boost
win32::CloseHandle(old_event);
}
}
bool try_lock()
{
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
}
void lock()
{
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
}
bool timed_lock(::boost::system_time const& wait_until)
{
if(!win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit))
if(try_lock())
{
return true;
return;
}
long old_count=active_count;
mark_waiting_and_try_lock(old_count);
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
do
{
BOOST_VERIFY(win32::WaitForSingleObject(
sem,::boost::detail::win32::infinite)==0);
clear_waiting_and_try_lock(old_count);
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
}
}
void mark_waiting_and_try_lock(long& old_count)
{
for(;;)
{
long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
@@ -80,6 +95,33 @@ namespace boost
}
old_count=current;
}
}
void clear_waiting_and_try_lock(long& old_count)
{
old_count&=~lock_flag_value;
old_count|=event_set_flag_value;
for(;;)
{
long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
break;
}
old_count=current;
}
}
bool timed_lock(::boost::system_time const& wait_until)
{
if(try_lock())
{
return true;
}
long old_count=active_count;
mark_waiting_and_try_lock(old_count);
if(old_count&lock_flag_value)
{
@@ -93,18 +135,7 @@ namespace boost
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
old_count&=~lock_flag_value;
old_count|=event_set_flag_value;
for(;;)
{
long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
break;
}
old_count=current;
}
clear_waiting_and_try_lock(old_count);
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
@@ -140,7 +171,7 @@ namespace boost
void* get_event()
{
void* current_event=::boost::detail::interlocked_read_acquire(&event);
if(!current_event)
{
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
@@ -165,9 +196,9 @@ namespace boost
}
return current_event;
}
};
}
}

View File

@@ -6,13 +6,13 @@
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/mutex.hpp>
#include "thread_primitives.hpp"
#include <boost/thread/win32/thread_primitives.hpp>
#include <limits.h>
#include <boost/assert.hpp>
#include <algorithm>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/thread/xtime.hpp>
#include <vector>
#include <boost/intrusive_ptr.hpp>
@@ -26,7 +26,7 @@ namespace boost
class basic_cv_list_entry;
void intrusive_ptr_add_ref(basic_cv_list_entry * p);
void intrusive_ptr_release(basic_cv_list_entry * p);
class basic_cv_list_entry
{
private:
@@ -38,7 +38,7 @@ namespace boost
basic_cv_list_entry(basic_cv_list_entry&);
void operator=(basic_cv_list_entry&);
public:
explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
@@ -55,7 +55,7 @@ namespace boost
{
BOOST_INTERLOCKED_INCREMENT(&waiters);
}
void remove_waiter()
{
BOOST_INTERLOCKED_DECREMENT(&waiters);
@@ -97,7 +97,7 @@ namespace boost
{
BOOST_INTERLOCKED_INCREMENT(&p->references);
}
inline void intrusive_ptr_release(basic_cv_list_entry * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
@@ -125,13 +125,13 @@ namespace boost
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
}
template<typename lock_type>
struct relocker
{
lock_type& lock;
bool unlocked;
relocker(lock_type& lock_):
lock(lock_),unlocked(false)
{}
@@ -146,13 +146,13 @@ namespace boost
{
lock.lock();
}
}
private:
relocker(relocker&);
void operator=(relocker&);
};
entry_ptr get_wait_entry()
{
@@ -177,15 +177,15 @@ namespace boost
return generations.back();
}
}
struct entry_manager
{
entry_ptr const entry;
entry_manager(entry_ptr const& entry_):
entry(entry_)
{}
~entry_manager()
{
entry->remove_waiter();
@@ -200,14 +200,14 @@ namespace boost
void operator=(entry_manager&);
entry_manager(entry_manager&);
};
protected:
template<typename lock_type>
bool do_wait(lock_type& lock,timeout wait_until)
{
relocker<lock_type> locker(lock);
entry_manager entry(get_wait_entry());
locker.unlock();
@@ -219,7 +219,7 @@ namespace boost
{
return false;
}
woken=entry->woken();
}
return woken;
@@ -235,7 +235,7 @@ namespace boost
}
return true;
}
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
@@ -243,7 +243,7 @@ namespace boost
basic_condition_variable():
total_count(0),active_generation_count(0),wake_sem(0)
{}
~basic_condition_variable()
{}
@@ -267,7 +267,7 @@ namespace boost
generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
}
}
void notify_all()
{
if(detail::interlocked_read_acquire(&total_count))
@@ -288,7 +288,7 @@ namespace boost
wake_sem=detail::win32::handle(0);
}
}
};
}
@@ -301,10 +301,10 @@ namespace boost
public:
condition_variable()
{}
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
void wait(unique_lock<mutex>& m)
{
do_wait(m,detail::timeout::sentinel());
@@ -315,7 +315,7 @@ namespace boost
{
while(!pred()) wait(m);
}
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
{
@@ -348,7 +348,7 @@ namespace boost
return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};
class condition_variable_any:
private detail::basic_condition_variable
{
@@ -358,10 +358,10 @@ namespace boost
public:
condition_variable_any()
{}
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
template<typename lock_type>
void wait(lock_type& m)
{
@@ -373,7 +373,7 @@ namespace boost
{
while(!pred()) wait(m);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
{

View File

@@ -5,7 +5,7 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "basic_timed_mutex.hpp"
#include <boost/thread/win32/basic_timed_mutex.hpp>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
@@ -20,9 +20,11 @@ namespace boost
}
class mutex:
boost::noncopyable,
public ::boost::detail::underlying_mutex
{
private:
mutex(mutex const&);
mutex& operator=(mutex const&);
public:
mutex()
{
@@ -40,9 +42,11 @@ namespace boost
typedef mutex try_mutex;
class timed_mutex:
boost::noncopyable,
public ::boost::detail::basic_timed_mutex
{
private:
timed_mutex(timed_mutex const&);
timed_mutex& operator=(timed_mutex const&);
public:
timed_mutex()
{

View File

@@ -30,81 +30,90 @@ namespace std
namespace boost
{
typedef long once_flag;
struct once_flag
{
long status;
long count;
};
#define BOOST_ONCE_INIT 0
#define BOOST_ONCE_INIT {0,0}
namespace detail
{
struct win32_mutex_scoped_lock
{
void* const mutex_handle;
explicit win32_mutex_scoped_lock(void* mutex_handle_):
mutex_handle(mutex_handle_)
{
BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite));
}
~win32_mutex_scoped_lock()
{
BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0);
}
private:
void operator=(win32_mutex_scoped_lock&);
};
#ifdef BOOST_NO_ANSI_APIS
typedef wchar_t once_char_type;
#else
typedef char once_char_type;
#endif
unsigned const once_mutex_name_fixed_length=54;
unsigned const once_mutex_name_length=once_mutex_name_fixed_length+
sizeof(void*)*2+sizeof(unsigned long)*2+1;
template <class I>
void int_to_string(I p, wchar_t* buf)
void int_to_string(I p, once_char_type* buf)
{
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
{
*buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f);
}
*buf = 0;
}
#else
template <class I>
void int_to_string(I p, char* buf)
{
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
{
*buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
}
*buf = 0;
}
#endif
// create a named mutex. It doesn't really matter what this name is
// as long as it is unique both to this process, and to the address of "flag":
inline void* create_once_mutex(void* flag_address)
{
#ifdef BOOST_NO_ANSI_APIS
typedef wchar_t char_type;
static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
once_char_type const a=L'A';
#else
typedef char char_type;
static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
once_char_type const a='A';
#endif
unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type);
unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1;
unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
char_type mutex_name[once_mutex_name_length];
*buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
}
*buf = 0;
}
inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
{
#ifdef BOOST_NO_ANSI_APIS
static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
#else
static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
#endif
BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
(sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t));
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length);
detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
#ifdef BOOST_NO_ANSI_APIS
return win32::CreateMutexW(0, 0, mutex_name);
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address),
mutex_name + once_mutex_name_fixed_length);
detail::int_to_string(win32::GetCurrentProcessId(),
mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
}
inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
{
if(!*mutex_name)
{
name_once_mutex(mutex_name,flag_address);
}
#ifdef BOOST_NO_ANSI_APIS
return ::boost::detail::win32::OpenEventW(
#else
return win32::CreateMutexA(0, 0, mutex_name);
return ::boost::detail::win32::OpenEventA(
#endif
::boost::detail::win32::synchronize |
::boost::detail::win32::event_modify_state,
false,
mutex_name);
}
inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
{
if(!*mutex_name)
{
name_once_mutex(mutex_name,flag_address);
}
#ifdef BOOST_NO_ANSI_APIS
return ::boost::detail::win32::CreateEventW(
#else
return ::boost::detail::win32::CreateEventA(
#endif
0,::boost::detail::win32::manual_reset_event,
::boost::detail::win32::event_initially_reset,
mutex_name);
}
}
@@ -114,19 +123,79 @@ namespace boost
// Try for a quick win: if the procedure has already been called
// just skip through:
long const function_complete_flag_value=0xc15730e2;
long const running_value=0x7f0725e3;
long status;
bool counted=false;
detail::win32::handle_manager event_handle;
detail::once_char_type mutex_name[detail::once_mutex_name_length];
mutex_name[0]=0;
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
while((status=::boost::detail::interlocked_read_acquire(&flag.status))
!=function_complete_flag_value)
{
void* const mutex_handle(::boost::detail::create_once_mutex(&flag));
BOOST_ASSERT(mutex_handle);
detail::win32::handle_manager const closer(mutex_handle);
detail::win32_mutex_scoped_lock const lock(mutex_handle);
if(flag!=function_complete_flag_value)
status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0);
if(!status)
{
f();
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
try
{
if(!event_handle)
{
event_handle=detail::open_once_event(mutex_name,&flag);
}
if(event_handle)
{
::boost::detail::win32::ResetEvent(event_handle);
}
f();
if(!counted)
{
BOOST_INTERLOCKED_INCREMENT(&flag.count);
counted=true;
}
BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value);
if(!event_handle &&
(::boost::detail::interlocked_read_acquire(&flag.count)>1))
{
event_handle=detail::create_once_event(mutex_name,&flag);
}
if(event_handle)
{
::boost::detail::win32::SetEvent(event_handle);
}
break;
}
catch(...)
{
BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
if(!event_handle)
{
event_handle=detail::open_once_event(mutex_name,&flag);
}
if(event_handle)
{
::boost::detail::win32::SetEvent(event_handle);
}
throw;
}
}
if(!counted)
{
BOOST_INTERLOCKED_INCREMENT(&flag.count);
counted=true;
status=::boost::detail::interlocked_read_acquire(&flag.status);
if(status==function_complete_flag_value)
{
break;
}
if(!event_handle)
{
event_handle=detail::create_once_event(mutex_name,&flag);
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
event_handle,::boost::detail::win32::infinite));
}
}
}

View File

@@ -3,7 +3,7 @@
// recursive_mutex.hpp
//
// (C) Copyright 2006-7 Anthony Williams
// (C) Copyright 2006-7 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -11,7 +11,7 @@
#include <boost/utility.hpp>
#include "basic_recursive_mutex.hpp"
#include <boost/thread/win32/basic_recursive_mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
@@ -20,9 +20,11 @@
namespace boost
{
class recursive_mutex:
boost::noncopyable,
public ::boost::detail::basic_recursive_mutex
{
private:
recursive_mutex(recursive_mutex const&);
recursive_mutex& operator=(recursive_mutex const&);
public:
recursive_mutex()
{
@@ -40,9 +42,11 @@ namespace boost
typedef recursive_mutex recursive_try_mutex;
class recursive_timed_mutex:
boost::noncopyable,
public ::boost::detail::basic_recursive_timed_mutex
{
private:
recursive_timed_mutex(recursive_timed_mutex const&);
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
public:
recursive_timed_mutex()
{

View File

@@ -19,9 +19,11 @@
namespace boost
{
class shared_mutex:
private boost::noncopyable
class shared_mutex
{
private:
shared_mutex(shared_mutex const&);
shared_mutex& operator=(shared_mutex const&);
private:
struct state_data
{
@@ -37,7 +39,7 @@ namespace boost
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
}
};
template<typename T>
T interlocked_compare_exchange(T* target,T new_value,T comparand)
@@ -49,34 +51,47 @@ namespace boost
return *reinterpret_cast<T const*>(&res);
}
enum
{
unlock_sem = 0,
exclusive_sem = 1
};
state_data state;
detail::win32::handle semaphores[2];
detail::win32::handle &unlock_sem;
detail::win32::handle &exclusive_sem;
detail::win32::handle upgrade_sem;
void release_waiters(state_data old_state)
{
if(old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
public:
shared_mutex():
unlock_sem(semaphores[0]),
exclusive_sem(semaphores[1])
shared_mutex()
{
unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
if (!semaphores[exclusive_sem])
{
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
boost::throw_exception(thread_resource_error());
}
upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
if (!upgrade_sem)
{
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
boost::throw_exception(thread_resource_error());
}
state_data state_={0};
state=state_;
}
@@ -84,8 +99,8 @@ namespace boost
~shared_mutex()
{
detail::win32::CloseHandle(upgrade_sem);
detail::win32::CloseHandle(unlock_sem);
detail::win32::CloseHandle(exclusive_sem);
detail::win32::CloseHandle(semaphores[unlock_sem]);
detail::win32::CloseHandle(semaphores[exclusive_sem]);
}
bool try_lock_shared()
@@ -97,8 +112,12 @@ namespace boost
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
{
++new_state.shared_count;
if(!new_state.shared_count)
{
return false;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
@@ -131,10 +150,18 @@ namespace boost
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
@@ -149,8 +176,8 @@ namespace boost
{
return true;
}
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
if(res==detail::win32::timeout)
{
for(;;)
@@ -166,6 +193,10 @@ namespace boost
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
return false;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
@@ -182,7 +213,7 @@ namespace boost
}
return false;
}
BOOST_ASSERT(res==0);
}
}
@@ -194,7 +225,7 @@ namespace boost
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
if(new_state.upgrade)
@@ -212,7 +243,7 @@ namespace boost
new_state.shared_waiting=0;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
@@ -258,7 +289,7 @@ namespace boost
{
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
@@ -282,6 +313,11 @@ namespace boost
if(new_state.shared_count || new_state.exclusive)
{
++new_state.exclusive_waiting;
if(!new_state.exclusive_waiting)
{
boost::throw_exception(boost::lock_error());
}
new_state.exclusive_waiting_blocked=true;
}
else
@@ -301,7 +337,12 @@ namespace boost
{
return true;
}
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until));
if(wait_res==detail::win32::timeout)
{
for(;;)
@@ -374,10 +415,18 @@ namespace boost
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
new_state.upgrade=true;
}
@@ -393,8 +442,8 @@ namespace boost
{
return;
}
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
}
}
@@ -411,9 +460,13 @@ namespace boost
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
return false;
}
new_state.upgrade=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
@@ -432,7 +485,7 @@ namespace boost
state_data new_state=old_state;
new_state.upgrade=false;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
if(new_state.exclusive_waiting)
@@ -442,7 +495,7 @@ namespace boost
}
new_state.shared_waiting=0;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
@@ -463,13 +516,13 @@ namespace boost
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
new_state.upgrade=false;
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
@@ -508,7 +561,7 @@ namespace boost
}
release_waiters(old_state);
}
void unlock_and_lock_shared()
{
state_data old_state=state;
@@ -533,7 +586,7 @@ namespace boost
}
release_waiters(old_state);
}
void unlock_upgrade_and_lock_shared()
{
state_data old_state=state;
@@ -557,7 +610,7 @@ namespace boost
}
release_waiters(old_state);
}
};
}

View File

@@ -8,8 +8,8 @@
#include <boost/thread/detail/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/thread/thread_time.hpp>
#include "thread_primitives.hpp"
#include "thread_heap_alloc.hpp"
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/thread_heap_alloc.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -23,8 +23,8 @@ namespace boost
struct thread_data_base;
void intrusive_ptr_add_ref(thread_data_base * p);
void intrusive_ptr_release(thread_data_base * p);
struct thread_data_base
struct BOOST_SYMBOL_VISIBLE thread_data_base
{
long count;
detail::win32::handle_manager thread_handle;
@@ -48,7 +48,7 @@ namespace boost
{
BOOST_INTERLOCKED_INCREMENT(&p->count);
}
friend void intrusive_ptr_release(thread_data_base * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
@@ -61,7 +61,7 @@ namespace boost
{
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
}
typedef detail::win32::handle native_handle_type;
virtual void run()=0;
@@ -69,7 +69,7 @@ namespace boost
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
struct BOOST_SYMBOL_VISIBLE timeout
{
unsigned long start;
uintmax_t milliseconds;
@@ -92,7 +92,7 @@ namespace boost
abs_time(abs_time_)
{}
struct remaining_time
struct BOOST_SYMBOL_VISIBLE remaining_time
{
bool more;
unsigned long milliseconds;
@@ -130,7 +130,7 @@ namespace boost
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
@@ -139,11 +139,16 @@ namespace boost
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
inline uintmax_t pin_to_zero(intmax_t value)
{
return (value<0)?0u:(uintmax_t)value;
}
}
namespace this_thread
@@ -151,26 +156,26 @@ namespace boost
void BOOST_THREAD_DECL yield();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline void interruptible_wait(unsigned long milliseconds)
inline void interruptible_wait(uintmax_t milliseconds)
{
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
}
inline void interruptible_wait(system_time const& abs_time)
inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time)
{
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
}
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
{
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
}
inline void sleep(system_time const& abs_time)
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
{
interruptible_wait(abs_time);
}
}
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -5,9 +5,10 @@
#ifndef THREAD_HEAP_ALLOC_HPP
#define THREAD_HEAP_ALLOC_HPP
#include <new>
#include "thread_primitives.hpp"
#include <boost/thread/win32/thread_primitives.hpp>
#include <stdexcept>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
@@ -55,21 +56,21 @@ namespace boost
{
namespace detail
{
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
inline void* allocate_raw_heap_memory(unsigned size)
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
if(!heap_memory)
{
throw std::bad_alloc();
boost::throw_exception(std::bad_alloc());
}
return heap_memory;
}
inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
inline void free_raw_heap_memory(void* heap_memory)
{
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
}
template<typename T>
inline T* heap_new()
{
@@ -86,7 +87,7 @@ namespace boost
}
}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename T,typename A1>
inline T* heap_new(A1&& a1)
{
@@ -225,7 +226,7 @@ namespace boost
{
return heap_new_impl<T,A1&>(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2 const& a2)
{
@@ -371,8 +372,8 @@ namespace boost
{
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
#endif
#endif
template<typename T>
inline void heap_delete(T* data)
{

View File

@@ -3,14 +3,15 @@
// win32_thread_primitives.hpp
//
// (C) Copyright 2005-7 Anthony Williams
// (C) Copyright 2007 David Deakins
// (C) Copyright 2005-7 Anthony Williams
// (C) Copyright 2007 David Deakins
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/detail/interlocked.hpp>
@@ -30,14 +31,18 @@ namespace boost
unsigned const infinite=INFINITE;
unsigned const timeout=WAIT_TIMEOUT;
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
unsigned const event_modify_state=EVENT_MODIFY_STATE;
unsigned const synchronize=SYNCHRONIZE;
# ifdef BOOST_NO_ANSI_APIS
using ::CreateMutexW;
using ::CreateEventW;
using ::OpenEventW;
using ::CreateSemaphoreW;
# else
using ::CreateMutexA;
using ::CreateEventA;
using ::OpenEventA;
using ::CreateSemaphoreA;
# endif
using ::CloseHandle;
@@ -89,7 +94,7 @@ namespace boost
{
namespace win32
{
# ifdef _WIN64
typedef unsigned __int64 ulong_ptr;
# else
@@ -99,6 +104,8 @@ namespace boost
unsigned const infinite=~0U;
unsigned const timeout=258U;
handle const invalid_handle_value=(handle)(-1);
unsigned const event_modify_state=2;
unsigned const synchronize=0x100000u;
extern "C"
{
@@ -107,10 +114,12 @@ namespace boost
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
__declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
# else
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
__declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
__declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*);
# endif
__declspec(dllimport) int __stdcall CloseHandle(void*);
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
@@ -161,40 +170,49 @@ namespace boost
auto_reset_event=false,
manual_reset_event=true
};
enum initial_event_state
{
event_initially_reset=false,
event_initially_set=true
};
inline handle create_anonymous_event(event_type type,initial_event_state state)
{
#if !defined(BOOST_NO_ANSI_APIS)
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=win32::CreateEventA(0,type,state,0);
#else
handle const res=win32::CreateEventW(0,type,state,0);
#endif
#endif
if(!res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
return res;
}
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
#else
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
#endif
#endif
if(!res)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
return res;
}
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
#else
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
#endif
return res;
}
inline handle duplicate_handle(handle source)
{
@@ -204,7 +222,7 @@ namespace boost
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
if(!success)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
return new_handle;
}
@@ -228,7 +246,7 @@ namespace boost
BOOST_VERIFY(CloseHandle(handle_to_manage));
}
}
public:
explicit handle_manager(handle handle_to_manage_):
handle_to_manage(handle_to_manage_)
@@ -236,7 +254,7 @@ namespace boost
handle_manager():
handle_to_manage(0)
{}
handle_manager& operator=(handle new_handle)
{
cleanup();
@@ -270,13 +288,13 @@ namespace boost
{
return !handle_to_manage;
}
~handle_manager()
{
cleanup();
}
};
}
}
}
@@ -309,7 +327,7 @@ namespace boost
{
return _interlockedbittestandreset(x,bit)!=0;
}
}
}
}
@@ -328,7 +346,7 @@ namespace boost
mov edx,x;
lock bts [edx],eax;
setc al;
};
};
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
@@ -338,9 +356,9 @@ namespace boost
mov edx,x;
lock btr [edx],eax;
setc al;
};
};
}
}
}
}

View File

@@ -22,16 +22,18 @@ namespace boost
pthread_key_t epoch_tss_key;
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
extern "C" void delete_epoch_tss_data(void* data)
extern "C"
{
free(data);
}
static void delete_epoch_tss_data(void* data)
{
free(data);
}
extern "C" void create_epoch_tss_key()
{
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
static void create_epoch_tss_key()
{
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
}
}
}
boost::uintmax_t& get_once_per_thread_epoch()

View File

@@ -2,7 +2,7 @@
// William E. Kempf
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
@@ -13,7 +13,8 @@
#include <boost/thread/locks.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#ifdef __linux__
#include <boost/throw_exception.hpp>
#ifdef __GLIBC__
#include <sys/sysinfo.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/types.h>
@@ -49,7 +50,7 @@ namespace boost
extern "C"
{
void tls_destructor(void* data)
static void tls_destructor(void* data)
{
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
if(thread_info)
@@ -74,7 +75,7 @@ namespace boost
{
current=next;
++next;
if(current->second.func && current->second.value)
if(current->second.func && (current->second.value!=0))
{
(*current->second.func)(current->second.value);
}
@@ -85,14 +86,14 @@ namespace boost
}
}
}
void create_current_thread_tls_key()
{
BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
}
}
boost::detail::thread_data_base* get_current_thread_data()
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
@@ -105,12 +106,12 @@ namespace boost
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
}
}
namespace
{
extern "C"
{
void* thread_proxy(void* param)
static void* thread_proxy(void* param)
{
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
thread_info->self.reset();
@@ -145,7 +146,7 @@ namespace boost
{
interrupt_enabled=false;
}
void run()
{}
@@ -186,7 +187,7 @@ namespace boost
if (res != 0)
{
thread_info->self.reset();
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
}
@@ -195,19 +196,18 @@ namespace boost
detach();
}
detail::thread_data_ptr thread::get_thread_info() const
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
{
lock_guard<mutex> l(thread_info_mutex);
return thread_info;
}
void thread::join()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
{
bool do_join=false;
{
unique_lock<mutex> lock(local_thread_info->data_mutex);
while(!local_thread_info->done)
@@ -215,7 +215,7 @@ namespace boost
local_thread_info->done_condition.wait(lock);
}
do_join=!local_thread_info->join_started;
if(do_join)
{
local_thread_info->join_started=true;
@@ -236,8 +236,7 @@ namespace boost
local_thread_info->joined=true;
local_thread_info->done_condition.notify_all();
}
lock_guard<mutex> l1(thread_info_mutex);
if(thread_info==local_thread_info)
{
thread_info.reset();
@@ -247,11 +246,11 @@ namespace boost
bool thread::timed_join(system_time const& wait_until)
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
{
bool do_join=false;
{
unique_lock<mutex> lock(local_thread_info->data_mutex);
while(!local_thread_info->done)
@@ -262,7 +261,7 @@ namespace boost
}
}
do_join=!local_thread_info->join_started;
if(do_join)
{
local_thread_info->join_started=true;
@@ -283,8 +282,7 @@ namespace boost
local_thread_info->joined=true;
local_thread_info->done_condition.notify_all();
}
lock_guard<mutex> l1(thread_info_mutex);
if(thread_info==local_thread_info)
{
thread_info.reset();
@@ -295,18 +293,15 @@ namespace boost
bool thread::joinable() const
{
return get_thread_info();
return (get_thread_info)();
}
void thread::detach()
{
detail::thread_data_ptr local_thread_info;
{
lock_guard<mutex> l1(thread_info_mutex);
thread_info.swap(local_thread_info);
}
thread_info.swap(local_thread_info);
if(local_thread_info)
{
lock_guard<mutex> lock(local_thread_info->data_mutex);
@@ -321,11 +316,15 @@ namespace boost
namespace this_thread
{
#ifdef __DECXXX
/// Workaround of DECCXX issue of incorrect template substitution
template<>
#endif
void sleep(const system_time& st)
{
detail::thread_data_base* const thread_info=detail::get_current_thread_data();
if(thread_info)
{
unique_lock<mutex> lk(thread_info->sleep_mutex);
@@ -334,7 +333,7 @@ namespace boost
else
{
xtime const xt=get_xtime(st);
for (int foo=0; foo < 5; ++foo)
{
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
@@ -344,7 +343,7 @@ namespace boost
# elif defined(BOOST_HAS_NANOSLEEP)
timespec ts;
to_timespec_duration(xt, ts);
// nanosleep takes a timespec that is an offset, not
// an absolute time.
nanosleep(&ts, 0);
@@ -380,8 +379,6 @@ namespace boost
{
#if defined(PTW32_VERSION) || defined(__hpux)
return pthread_num_processors_np();
#elif defined(_GNU_SOURCE)
return get_nprocs();
#elif defined(__APPLE__) || defined(__FreeBSD__)
int count;
size_t size=sizeof(count);
@@ -389,6 +386,8 @@ namespace boost
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#elif defined(__GLIBC__)
return get_nprocs();
#else
return 0;
#endif
@@ -396,7 +395,7 @@ namespace boost
thread::id thread::get_id() const
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
{
return id(local_thread_info);
@@ -409,13 +408,14 @@ namespace boost
void thread::interrupt()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
local_thread_info->interrupt_requested=true;
if(local_thread_info->current_cond)
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
}
}
@@ -423,7 +423,7 @@ namespace boost
bool thread::interruption_requested() const
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
@@ -437,7 +437,7 @@ namespace boost
thread::native_handle_type thread::native_handle()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
@@ -448,8 +448,8 @@ namespace boost
return pthread_t();
}
}
namespace this_thread
{
@@ -472,13 +472,13 @@ namespace boost
}
}
}
bool interruption_enabled()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
return thread_info && thread_info->interrupt_enabled;
}
bool interruption_requested()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
@@ -501,7 +501,7 @@ namespace boost
detail::get_current_thread_data()->interrupt_enabled=false;
}
}
disable_interruption::~disable_interruption()
{
if(detail::get_current_thread_data())
@@ -517,7 +517,7 @@ namespace boost
detail::get_current_thread_data()->interrupt_enabled=true;
}
}
restore_interruption::~restore_interruption()
{
if(detail::get_current_thread_data())
@@ -574,18 +574,18 @@ namespace boost
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
current_thread_data->tss_data.erase(key);
}
void set_tss_data(void const* key,
boost::shared_ptr<tss_cleanup_function> func,
void* tss_data,bool cleanup_existing)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func && current_node->value)
if(cleanup_existing && current_node->func && (current_node->value!=0))
{
(*current_node->func)(current_node->value);
}
if(func || tss_data)
if(func || (tss_data!=0))
{
current_node->func=func;
current_node->value=tss_data;

View File

@@ -1,11 +1,14 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2009 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)
// boostinspect:nounnamed
#include <boost/assert.hpp>
namespace {
const int MILLISECONDS_PER_SECOND = 1000;
const int NANOSECONDS_PER_SECOND = 1000000000;
@@ -18,7 +21,7 @@ inline void to_time(int milliseconds, boost::xtime& xt)
{
int res = 0;
res = boost::xtime_get(&xt, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
@@ -30,7 +33,6 @@ inline void to_time(int milliseconds, boost::xtime& xt)
xt.nsec -= NANOSECONDS_PER_SECOND;
}
}
#if defined(BOOST_HAS_PTHREADS)
inline void to_timespec(const boost::xtime& xt, timespec& ts)
{
@@ -55,7 +57,7 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
if (boost::xtime_cmp(xt, cur) <= 0)
{
@@ -86,7 +88,7 @@ inline void to_duration(boost::xtime xt, int& milliseconds)
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
if (boost::xtime_cmp(xt, cur) <= 0)
milliseconds = 0;
@@ -108,7 +110,7 @@ inline void to_microduration(boost::xtime xt, int& microseconds)
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
if (boost::xtime_cmp(xt, cur) <= 0)
microseconds = 0;

View File

@@ -8,13 +8,15 @@
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
namespace boost
{
/*
This file is a "null" implementation of tss cleanup; it's
purpose is to to eliminate link errors in cases
where it is known that tss cleanup is not needed.
*/
extern "C" void tss_cleanup_implemented(void)
void tss_cleanup_implemented(void)
{
/*
This function's sole purpose is to cause a link error in cases where
@@ -30,5 +32,7 @@
longer needed and can be removed.
*/
}
}
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)

View File

@@ -9,7 +9,6 @@
#include <boost/thread/thread.hpp>
#include <algorithm>
#include <windows.h>
#ifndef UNDER_CE
#include <process.h>
#endif
@@ -17,8 +16,11 @@
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <windows.h>
#include <memory>
namespace boost
{
@@ -31,7 +33,12 @@ namespace boost
{
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);
#if defined(UNDER_CE)
// Windows CE does not define the TLS_OUT_OF_INDEXES constant.
BOOST_ASSERT(current_thread_tls_key!=0xFFFFFFFF);
#else
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
#endif
}
void cleanup_tls_key()
@@ -55,10 +62,13 @@ namespace boost
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
if(current_thread_tls_key)
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
else
boost::throw_exception(thread_resource_error());
}
#ifdef BOOST_NO_THREADEX
#ifndef BOOST_HAS_THREADEX
// Windows CE doesn't define _beginthreadex
struct ThreadProxyData
@@ -71,22 +81,25 @@ namespace boost
DWORD WINAPI ThreadProxy(LPVOID args)
{
ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args);
std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
DWORD ret=data->start_address_(data->arglist_);
delete data;
return ret;
}
typedef void* uintptr_t;
inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
void* arglist, unsigned initflag, unsigned* thrdaddr)
{
DWORD threadID;
ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
new ThreadProxyData(start_address,arglist),initflag,&threadID);
if (hthread!=0)
*thrdaddr=threadID;
data,initflag,&threadID);
if (hthread==0) {
delete data;
return 0;
}
*thrdaddr=threadID;
return reinterpret_cast<uintptr_t const>(hthread);
}
@@ -153,11 +166,11 @@ namespace boost
boost::detail::heap_delete(current_node);
}
}
set_current_thread_data(0);
}
}
unsigned __stdcall thread_start_function(void* param)
{
detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
@@ -188,7 +201,7 @@ namespace boost
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
if(!new_thread)
{
throw thread_resource_error();
boost::throw_exception(thread_resource_error());
}
intrusive_ptr_add_ref(thread_info.get());
thread_info->thread_handle=(detail::win32::handle)(new_thread);
@@ -209,7 +222,7 @@ namespace boost
++count;
interruption_enabled=false;
}
void run()
{}
private:
@@ -220,7 +233,15 @@ namespace boost
void make_external_thread_data()
{
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
set_current_thread_data(me);
try
{
set_current_thread_data(me);
}
catch(...)
{
detail::heap_delete(me);
throw;
}
}
detail::thread_data_base* get_or_make_current_thread_data()
@@ -233,27 +254,27 @@ namespace boost
}
return current_thread_data;
}
}
thread::~thread()
{
detach();
}
thread::id thread::get_id() const
{
return thread::id(get_thread_info());
return thread::id((get_thread_info)());
}
bool thread::joinable() const
{
return get_thread_info();
return (get_thread_info)();
}
void thread::join()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
@@ -263,7 +284,7 @@ namespace boost
bool thread::timed_join(boost::system_time const& wait_until)
{
detail::thread_data_ptr local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
@@ -274,7 +295,7 @@ namespace boost
}
return true;
}
void thread::detach()
{
release_handle();
@@ -282,41 +303,39 @@ namespace boost
void thread::release_handle()
{
lock_guard<mutex> l1(thread_info_mutex);
thread_info=0;
}
void thread::interrupt()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
local_thread_info->interrupt();
}
}
bool thread::interruption_requested() const
{
detail::thread_data_ptr local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=(get_thread_info)();
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
}
unsigned thread::hardware_concurrency()
{
SYSTEM_INFO info={0};
SYSTEM_INFO info={{0}};
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}
thread::native_handle_type thread::native_handle()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=(get_thread_info)();
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
}
detail::thread_data_ptr thread::get_thread_info() const
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
{
boost::mutex::scoped_lock l(thread_info_mutex);
return thread_info;
}
@@ -326,7 +345,7 @@ namespace boost
{
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={0};
LARGE_INTEGER due_time={{0}};
if(target_time.relative)
{
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
@@ -355,13 +374,29 @@ namespace boost
else
{
long const hundred_nanoseconds_in_one_second=10000000;
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
posix_time::time_duration::tick_type const ticks_per_second=
target_time.abs_time.time_of_day().ticks_per_second();
if(ticks_per_second>hundred_nanoseconds_in_one_second)
{
posix_time::time_duration::tick_type const
ticks_per_hundred_nanoseconds=
ticks_per_second/hundred_nanoseconds_in_one_second;
due_time.QuadPart+=
target_time.abs_time.time_of_day().fractional_seconds()/
ticks_per_hundred_nanoseconds;
}
else
{
due_time.QuadPart+=
target_time.abs_time.time_of_day().fractional_seconds()*
(hundred_nanoseconds_in_one_second/ticks_per_second);
}
}
}
return due_time;
}
}
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
{
@@ -382,10 +417,10 @@ namespace boost
}
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
@@ -396,7 +431,7 @@ namespace boost
if(timer_handle!=0)
{
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
if(set_time_succeeded)
{
@@ -412,17 +447,17 @@ namespace boost
}
}
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
{
if(!using_timer)
{
time_left=target_time.remaining_milliseconds();
}
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
@@ -469,12 +504,12 @@ namespace boost
throw thread_interrupted();
}
}
bool interruption_enabled()
{
return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
}
bool interruption_requested()
{
return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
@@ -484,7 +519,7 @@ namespace boost
{
detail::win32::Sleep(0);
}
disable_interruption::disable_interruption():
interruption_was_enabled(interruption_enabled())
{
@@ -493,7 +528,7 @@ namespace boost
get_current_thread_data()->interruption_enabled=false;
}
}
disable_interruption::~disable_interruption()
{
if(get_current_thread_data())
@@ -509,7 +544,7 @@ namespace boost
get_current_thread_data()->interruption_enabled=true;
}
}
restore_interruption::~restore_interruption()
{
if(get_current_thread_data())
@@ -525,8 +560,8 @@ namespace boost
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
heap_new<thread_exit_callback_node>(func,
current_thread_data->thread_exit_callbacks);
heap_new<thread_exit_callback_node>(
func,current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
@@ -556,7 +591,7 @@ namespace boost
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
if(tss_data_node* const current_node=find_tss_data(key))
@@ -568,30 +603,31 @@ namespace boost
current_node->func=func;
current_node->value=tss_data;
}
else
else if(func && tss_data)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
tss_data_node* const new_node=
heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
}
}
BOOST_THREAD_DECL void __cdecl on_process_enter()
{}
BOOST_THREAD_DECL void __cdecl on_thread_enter()
{}
BOOST_THREAD_DECL void __cdecl on_process_exit()
{
boost::cleanup_tls_key();
}
BOOST_THREAD_DECL void __cdecl on_thread_exit()
{
boost::run_thread_exit_callbacks();
}
}
extern "C" BOOST_THREAD_DECL void on_process_enter()
{}
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()
{
boost::run_thread_exit_callbacks();
}

View File

@@ -24,27 +24,27 @@
{
case DLL_PROCESS_ATTACH:
{
on_process_enter();
on_thread_enter();
boost::on_process_enter();
boost::on_thread_enter();
break;
}
case DLL_THREAD_ATTACH:
{
on_thread_enter();
boost::on_thread_enter();
break;
}
case DLL_THREAD_DETACH:
{
on_thread_exit();
boost::on_thread_exit();
break;
}
case DLL_PROCESS_DETACH:
{
on_thread_exit();
on_process_exit();
boost::on_thread_exit();
boost::on_process_exit();
break;
}
}
@@ -52,7 +52,9 @@
return TRUE;
}
extern "C" void tss_cleanup_implemented(void)
namespace boost
{
void tss_cleanup_implemented()
{
/*
This function's sole purpose is to cause a link error in cases where
@@ -68,5 +70,7 @@
longer needed and can be removed.
*/
}
}
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)

View File

@@ -11,7 +11,7 @@
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if defined(__MINGW32__) && !defined(_WIN64)
#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__)
#include <boost/thread/detail/tss_hooks.hpp>
@@ -19,7 +19,10 @@
#include <cstdlib>
extern "C" void tss_cleanup_implemented(void) {}
namespace boost
{
void tss_cleanup_implemented() {}
}
namespace {
void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
@@ -28,33 +31,25 @@ namespace {
{
case DLL_THREAD_DETACH:
{
on_thread_exit();
boost::on_thread_exit();
break;
}
}
}
void on_after_ctors(void)
{
on_process_enter();
}
void on_before_dtors(void)
{
on_thread_exit();
}
void on_after_dtors(void)
{
on_process_exit();
}
}
#if defined(__MINGW64__) || (__MINGW32_MAJOR_VERSION >3) || \
((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
extern "C"
{
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
}
#else
extern "C" {
void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors;
void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors;
void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors;
void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter;
void (* before_dtors)() __attribute__((section(".dtors"))) = boost::on_thread_exit;
void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit;
ULONG __tls_index__ = 0;
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
@@ -62,10 +57,8 @@ extern "C" {
PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
}
extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
{
(DWORD) &__tls_start__,
@@ -75,6 +68,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
(DWORD) 0,
(DWORD) 0
};
#endif
#elif defined(_MSC_VER) && !defined(UNDER_CE)
@@ -89,13 +83,13 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
//Definitions required by implementation
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
typedef void (__cdecl *_PVFV)(void);
typedef void (__cdecl *_PVFV)();
#define INIRETSUCCESS
#define PVAPI void
#define PVAPI void __cdecl
#else
typedef int (__cdecl *_PVFV)(void);
typedef int (__cdecl *_PVFV)();
#define INIRETSUCCESS 0
#define PVAPI int
#define PVAPI int __cdecl
#endif
typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
@@ -112,9 +106,9 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
{
//Forward declarations
static PVAPI on_tls_prepare(void);
static PVAPI on_process_init(void);
static PVAPI on_process_term(void);
static PVAPI on_tls_prepare();
static PVAPI on_process_init();
static PVAPI on_process_term();
static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
//The .CRT$Xxx information is taken from Codeguru:
@@ -169,7 +163,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
#pragma warning(disable:4189)
#endif
PVAPI on_tls_prepare(void)
PVAPI on_tls_prepare()
{
//The following line has an important side effect:
//if the TLS directory is not already there, it will
@@ -210,7 +204,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
#pragma warning(pop)
#endif
PVAPI on_process_init(void)
PVAPI on_process_init()
{
//Schedule on_thread_exit() to be called for the main
//thread before destructors of global objects have been
@@ -221,18 +215,18 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
//for destructors of global objects, so that
//shouldn't be a problem.
atexit(on_thread_exit);
atexit(boost::on_thread_exit);
//Call Boost process entry callback here
on_process_enter();
boost::on_process_enter();
return INIRETSUCCESS;
}
PVAPI on_process_term(void)
PVAPI on_process_term()
{
on_process_exit();
boost::on_process_exit();
return INIRETSUCCESS;
}
@@ -241,7 +235,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
switch (dwReason)
{
case DLL_THREAD_DETACH:
on_thread_exit();
boost::on_thread_exit();
break;
}
}
@@ -251,10 +245,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
switch (dwReason)
{
case DLL_THREAD_DETACH:
on_thread_exit();
boost::on_thread_exit();
break;
case DLL_PROCESS_DETACH:
on_process_exit();
boost::on_process_exit();
break;
}
return true;
@@ -265,8 +259,9 @@ extern "C"
{
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
}
extern "C" void tss_cleanup_implemented(void)
namespace boost
{
void tss_cleanup_implemented()
{
/*
This function's sole purpose is to cause a link error in cases where
@@ -282,6 +277,8 @@ extern "C"
longer needed and can be removed.
*/
}
}
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)

View File

@@ -42,6 +42,7 @@ rule thread-run ( sources )
[ thread-run test_thread_move_return.cpp ]
[ thread-run test_thread_launching.cpp ]
[ thread-run test_thread_mf.cpp ]
[ thread-run test_thread_exit.cpp ]
[ thread-run test_move_function.cpp ]
[ thread-run test_mutex.cpp ]
[ thread-run test_condition_notify_one.cpp ]
@@ -61,4 +62,29 @@ rule thread-run ( sources )
[ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
[ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
;
#explicit tickets ;
test-suite tickets
:
[ thread-run test_6170.cpp ]
;
explicit oth_tickets ;
test-suite oth_tickets
:
[ thread-run test_2501.cpp ]
[ thread-run test_4521.cpp ]
[ thread-run test_4648.cpp ]
[ thread-run test_4882.cpp ]
[ thread-run test_5351.cpp ]
[ thread-run test_5502.cpp ]
[ thread-run test_5542_1.cpp ]
[ thread-run test_5542_2.cpp ]
[ thread-run test_5542_3.cpp ]
[ thread-run test_6130.cpp ]
[ thread-run test_6174.cpp ]
;
}

10
test/test_2501.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include <boost/thread/shared_mutex.hpp>
int main() {
boost::shared_mutex mtx; boost::upgrade_lock<boost::shared_mutex> lk(mtx);
boost::upgrade_to_unique_lock<boost::shared_mutex> lk2(lk);
return 0;
}

21
test/test_4521.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include <boost/thread.hpp>
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
int main() {
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::unique_future<int> fi=pt.get_future();
boost::thread task(boost::move(pt)); // launch task on a thread
fi.wait(); // wait for it to finish
//assert(fi.is_ready());
//assert(fi.has_value());
//assert(!fi.has_exception());
//assert(fi.get_state()==boost::future_state::ready);
//assert(fi.get()==42);
}

42
test/test_4648.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include <iostream>
#include <boost/thread.hpp>
#include <boost/current_function.hpp>
class boostThreadLocksTest
{
public:
boost::shared_mutex myMutex;
//boost::upgrade_lock<boost::shared_mutex> myLock;
static int firstFunction(boostThreadLocksTest *pBoostThreadLocksTest);
static int secondFunction(boostThreadLocksTest *pBoostThreadLocksTest,
boost::upgrade_lock<boost::shared_mutex>& upgr);
boostThreadLocksTest()
:myMutex()
//, myLock(myMutex,boost::defer_lock_t())
{};
};
int boostThreadLocksTest::firstFunction(boostThreadLocksTest *pBoostThreadLocksTest)
{
std::cout<<"Entering "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
boost::upgrade_lock<boost::shared_mutex> myLock(pBoostThreadLocksTest->myMutex);
pBoostThreadLocksTest->secondFunction(pBoostThreadLocksTest, myLock);
std::cout<<"Returned From Call "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
std::cout<<"Returning from "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
return(0);
}
int boostThreadLocksTest::secondFunction(boostThreadLocksTest *pBoostThreadLocksTest, boost::upgrade_lock<boost::shared_mutex>& upgr) {
std::cout<<"Before Exclusive Locking "<<boost::this_thread::get_id()<<" "<<"secondFunction"<<std::endl;
boost::upgrade_to_unique_lock<boost::shared_mutex> localUniqueLock(upgr);
std::cout<<"After Exclusive Locking "<<boost::this_thread::get_id()<<" "<<"secondFunction"<<std::endl;
return(0);
}
int main() {
boostThreadLocksTest myObject;
boost::thread_group myThreadGroup;
myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
myThreadGroup.join_all();
return 0;
}

50
test/test_4882.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <iostream>
boost::shared_mutex mutex;
void thread()
{
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
try
{
for (int i =0; i<10; ++i)
{
boost::system_time timeout = boost::get_system_time() + boost::posix_time::milliseconds(50);
if (mutex.timed_lock(timeout))
{
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
mutex.unlock();
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
}
}
}
catch (boost::lock_error& le)
{
std::cerr << "lock_error exception\n";
}
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
}
int main()
{
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
const int nrThreads = 20;
boost::thread* threads[nrThreads];
for (int i = 0; i < nrThreads; ++i)
threads[i] = new boost::thread(&thread);
for (int i = 0; i < nrThreads; ++i)
{
threads[i]->join();
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
delete threads[i];
}
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
return 0;
}

45
test/test_5351.cpp Normal file
View File

@@ -0,0 +1,45 @@
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/thread/future.hpp>
using namespace boost::posix_time;
using namespace boost;
int foo()
{
this_thread::sleep(seconds(10));
return 0;
}
int main(int argc, char** argv)
{
boost::packaged_task<int> pt(&foo);
boost::unique_future<int> fi = pt.get_future();
boost::thread task(boost::move(pt)); // launch task on a thread
task.interrupt();
try
{
int v = fi.get();
}
catch (boost::thread_interrupted& exc)
{
std::cout << "OK: " << std::endl;
return 0;
}
catch (boost::exception& exc)
{
std::cout << __LINE__ << " ERROR: " << boost::diagnostic_information(exc) << std::endl;
return 1;
}
catch (...)
{
std::cout << __LINE__ << " ERROR: " << std::endl;
return 2;
}
std::cout << __LINE__ << " ERROR: " << std::endl;
return 3;
}

86
test/test_5502.cpp Normal file
View File

@@ -0,0 +1,86 @@
// bm.cpp
// g++ test.cpp -lboost_thread-mt && ./a.out
// the ration of XXX and YYY determines
// if this works or deadlocks
int XXX = 20;
int YYY = 10;
#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <unistd.h>
#include <iostream>
#include <boost/detail/lightweight_test.hpp>
using namespace std;
void sleepmillis(useconds_t miliis)
{
usleep(miliis * 1000);
}
void worker1(boost::shared_mutex * lk, int * x)
{
(*x)++; // 1
cout << "lock b try " << *x << endl;
while (1)
{
if (lk->timed_lock(boost::posix_time::milliseconds(XXX))) break;
sleepmillis(YYY);
}
cout << "lock b got " << *x << endl;
(*x)++; // 2
lk->unlock();
}
void worker2(boost::shared_mutex * lk, int * x)
{
cout << "lock c try" << endl;
lk->lock_shared();
(*x)++;
cout << "lock c got" << endl;
lk->unlock_shared();
cout << "lock c unlocked" << endl;
(*x)++;
}
int main()
{
// create
boost::shared_mutex* lk = new boost::shared_mutex();
// read lock
cout << "lock a" << endl;
lk->lock_shared();
int x1 = 0;
boost::thread t1(boost::bind(worker1, lk, &x1));
while (!x1)
;
BOOST_TEST(x1 == 1);
sleepmillis(500);
BOOST_TEST(x1 == 1);
int x2 = 0;
boost::thread t2(boost::bind(worker2, lk, &x2));
t2.join();
BOOST_TEST(x2 == 2);
lk->unlock_shared();
cout << "unlock a" << endl;
for (int i = 0; i < 2000; i++)
{
if (x1 == 2) break;
sleepmillis(10);
}
BOOST_TEST(x1 == 2);
t1.join();
delete lk;
return 0;
}

62
test/test_5542_1.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include <iostream>
#include <boost/thread.hpp>
class Worker
{
public:
Worker()
{
// the thread is not-a-thread until we call start()
}
void start(int N)
{
std::cout << "start\n";
m_Thread = boost::thread(&Worker::processQueue, this, N);
std::cout << "started\n";
}
void join()
{
m_Thread.join();
}
void processQueue(unsigned N)
{
float ms = N * 1e3;
boost::posix_time::milliseconds workTime(ms);
std::cout << "Worker: started, will work for "
<< ms << "ms"
<< std::endl;
// We're busy, honest!
boost::this_thread::sleep(workTime);
std::cout << "Worker: completed" << std::endl;
}
private:
boost::thread m_Thread;
};
int main(int argc, char* argv[])
{
std::cout << "main: startup" << std::endl;
Worker worker;
std::cout << "main: create worker" << std::endl;
worker.start(3);
std::cout << "main: waiting for thread" << std::endl;
worker.join();
std::cout << "main: done" << std::endl;
return 0;
}

11
test/test_5542_2.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include <boost/thread.hpp>
void run_thread() {
return;
}
int main() {
boost::thread t(run_thread);
return 0;
}

30
test/test_5542_3.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
void workerFunc()
{
boost::posix_time::seconds workTime(3);
std::cout << "Worker: running" << std::endl;
// Pretend to do something useful...
boost::this_thread::sleep(workTime);
std::cout << "Worker: finished" << std::endl;
}
int main(int argc, char* argv[])
{
std::cout << "main: startup" << std::endl;
boost::thread workerThread(workerFunc);
std::cout << "main: waiting for thread" << std::endl;
workerThread.join();
std::cout << "main: done" << std::endl;
return 0;
}

22
test/test_6130.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include <boost/thread.hpp>
#include <assert.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
boost::mutex mtx;
boost::condition_variable cv;
int main()
{
for (int i=0; i<3; ++i) {
const time_t wait_time = ::time(0)+1;
boost::mutex::scoped_lock lk(mtx);
const bool res = cv.timed_wait(lk, boost::posix_time::from_time_t(wait_time));
const time_t end_time = ::time(0);
assert(end_time >= wait_time);
std::cerr << end_time - wait_time << " OK\n";
}
return 0;
}

26
test/test_6170.cpp Normal file
View File

@@ -0,0 +1,26 @@
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
// Including this will cause ambiguous errors in boost::move
#include <boost/unordered_map.hpp>
using namespace boost;
typedef upgrade_lock<shared_mutex> auto_upgrade_lock;
typedef upgrade_to_unique_lock<shared_mutex> auto_upgrade_unique_lock;
void testUpgrade(void)
{
shared_mutex mtx;
auto_upgrade_lock lock(mtx);
// Do some read-only stuff
auto_upgrade_unique_lock writeLock(lock);
// Do some write-only stuff with the upgraded lock
}
int main()
{
testUpgrade();
return 0;
}

35
test/test_6174.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include <boost/thread.hpp>
#include <boost/config.hpp>
#ifndef BOOST_NO_RVALUE_REFERENCES
struct MovableButNonCopyable {
#ifndef BOOST_NO_DEFAULTED_FUNCTIONS
MovableButNonCopyable() = default;
MovableButNonCopyable(MovableButNonCopyable const&) = delete;
MovableButNonCopyable& operator=(MovableButNonCopyable const&) = delete;
MovableButNonCopyable(MovableButNonCopyable&&) = default;
MovableButNonCopyable& operator=(MovableButNonCopyable&&) = default;
#else
MovableButNonCopyable() {};
MovableButNonCopyable(MovableButNonCopyable&&) {};
MovableButNonCopyable& operator=(MovableButNonCopyable&&) {
return *this;
};
private:
MovableButNonCopyable(MovableButNonCopyable const&);
MovableButNonCopyable& operator=(MovableButNonCopyable const&);
#endif
};
int main()
{
boost::packaged_task<MovableButNonCopyable>(MovableButNonCopyable());
return 0;
}
#else
int main()
{
return 0;
}
#endif

View File

@@ -55,9 +55,9 @@ void test_barrier()
BOOST_CHECK_EQUAL(global_parameter,5);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: barrier test suite");
test->add(BOOST_TEST_CASE(&test_barrier));

View File

@@ -178,9 +178,9 @@ void test_condition_wait_is_a_interruption_point()
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_waits));

View File

@@ -211,9 +211,9 @@ void test_condition_notify_all()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_all));

View File

@@ -144,9 +144,9 @@ void test_condition_notify_one()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));

View File

@@ -162,9 +162,9 @@ void test_timed_wait_times_out()
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*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));

View File

@@ -1,4 +1,4 @@
// (C) Copyright 2008-9 Anthony Williams
// (C) Copyright 2008-10 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -14,11 +14,11 @@
#include <boost/test/unit_test.hpp>
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
template<typename T>
typename boost::remove_reference<T>::type&& cast_to_rval(T&& t)
{
return t;
return static_cast<typename boost::remove_reference<T>::type&&>(t);
}
#else
template<typename T>
@@ -41,7 +41,7 @@ public:
X():
i(42)
{}
#ifdef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_RVALUE_REFERENCES
X(X&& other):
i(other.i)
{
@@ -89,7 +89,7 @@ void set_promise_exception_thread(boost::promise<int>* p)
void test_store_value_from_thread()
{
boost::promise<int> pi2;
boost::unique_future<int> fi2=pi2.get_future();
boost::unique_future<int> fi2(pi2.get_future());
boost::thread(set_promise_thread,&pi2);
int j=fi2.get();
BOOST_CHECK(j==42);
@@ -556,7 +556,7 @@ void wait_callback(boost::promise<int>& pi)
}
}
void do_nothing_callback(boost::promise<int>& pi)
void do_nothing_callback(boost::promise<int>& /*pi*/)
{
boost::lock_guard<boost::mutex> lk(callback_mutex);
++callback_called;
@@ -1041,6 +1041,8 @@ void test_wait_for_any_from_range()
}
boost::thread(::cast_to_rval(tasks[i]));
BOOST_CHECK(boost::wait_for_any(futures,futures)==futures);
boost::unique_future<int>* const future=boost::wait_for_any(futures,futures+count);
BOOST_CHECK(future==(futures+i));
@@ -1155,9 +1157,9 @@ void test_wait_for_all_five_futures()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: futures test suite");
test->add(BOOST_TEST_CASE(test_initial_state));

View File

@@ -296,10 +296,80 @@ void test_lock_five_in_range()
}
}
void test_lock_ten_in_range()
class dummy_iterator:
public std::iterator<std::forward_iterator_tag,
dummy_mutex>
{
private:
dummy_mutex* p;
public:
explicit dummy_iterator(dummy_mutex* p_):
p(p_)
{}
bool operator==(dummy_iterator const& other) const
{
return p==other.p;
}
bool operator!=(dummy_iterator const& other) const
{
return p!=other.p;
}
bool operator<(dummy_iterator const& other) const
{
return p<other.p;
}
dummy_mutex& operator*() const
{
return *p;
}
dummy_mutex* operator->() const
{
return p;
}
dummy_iterator operator++(int)
{
dummy_iterator temp(*this);
++p;
return temp;
}
dummy_iterator& operator++()
{
++p;
return *this;
}
};
void test_lock_five_in_range_custom_iterator()
{
unsigned const num_mutexes=5;
dummy_mutex mutexes[num_mutexes];
boost::lock(dummy_iterator(mutexes),dummy_iterator(mutexes+num_mutexes));
for(unsigned i=0;i<num_mutexes;++i)
{
BOOST_CHECK(mutexes[i].is_locked);
}
}
class dummy_mutex2:
public dummy_mutex
{};
void test_lock_ten_in_range_inherited_mutex()
{
unsigned const num_mutexes=10;
dummy_mutex mutexes[num_mutexes];
dummy_mutex2 mutexes[num_mutexes];
boost::lock(mutexes,mutexes+num_mutexes);
@@ -498,9 +568,9 @@ void test_try_lock_five()
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
@@ -510,7 +580,8 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
test->add(BOOST_TEST_CASE(&test_lock_ten_in_range));
test->add(BOOST_TEST_CASE(&test_lock_five_in_range_custom_iterator));
test->add(BOOST_TEST_CASE(&test_lock_ten_in_range_inherited_mutex));
test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));

View File

@@ -11,9 +11,9 @@ void test_hardware_concurrency_is_non_zero()
BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));

View File

@@ -4,7 +4,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
@@ -546,9 +545,9 @@ void test_shared_lock()
BOOST_CHECK(dummy.shared_timed_locked_absolute);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,

View File

@@ -1,6 +1,6 @@
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
@@ -89,10 +89,17 @@ namespace user_test_ns
}
bool move_called=false;
struct nc:
public boost::shared_ptr<int>
{
#ifndef BOOST_NO_RVALUE_REFERENCES
nc() {}
nc(nc&&)
{
move_called=true;
}
#endif
nc move()
{
move_called=true;
@@ -101,16 +108,30 @@ namespace user_test_ns
};
}
#ifdef BOOST_NO_RVALUE_REFERENCES
namespace boost
{
template <>
struct has_move_emulation_enabled_aux<user_test_ns::nc>
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
}
#endif
void test_move_for_user_defined_type_unaffected()
{
user_test_ns::nc src;
#ifndef BOOST_NO_RVALUE_REFERENCES
user_test_ns::nc dest=boost::move(src);
#else
user_test_ns::nc dest=move(src);
#endif
BOOST_CHECK(user_test_ns::move_called);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));

View File

@@ -331,9 +331,9 @@ void test_recursive_timed_mutex()
timed_test(&do_test_recursive_timed_mutex, 3);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
test->add(BOOST_TEST_CASE(&test_mutex));

View File

@@ -178,9 +178,9 @@ void test_call_once_retried_on_exception()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
test->add(BOOST_TEST_CASE(test_call_once));

View File

@@ -270,9 +270,9 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_multiple_readers));

View File

@@ -138,6 +138,14 @@ void test_can_lock_upgrade_if_currently_locked_shared()
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
}
void test_can_lock_upgrade_to_unique_if_currently_locked_upgrade()
{
boost::shared_mutex mtx;
boost::upgrade_lock<boost::shared_mutex> l(mtx);
boost::upgrade_to_unique_lock<boost::shared_mutex> ul(l);
BOOST_CHECK(ul.owns_lock());
}
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
{
@@ -275,13 +283,14 @@ void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
writer.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_to_unique_if_currently_locked_upgrade));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));

View File

@@ -251,9 +251,9 @@ void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));

View File

@@ -216,9 +216,9 @@ void test_swap()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
test->add(BOOST_TEST_CASE(test_sleep));

73
test/test_thread_exit.cpp Normal file
View File

@@ -0,0 +1,73 @@
// (C) Copyright 2009 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include "boost/thread/thread.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/condition.hpp"
#include "boost/thread/future.hpp"
#include <utility>
#include <memory>
#include <string>
#include <boost/test/unit_test.hpp>
boost::thread::id exit_func_thread_id;
void exit_func()
{
exit_func_thread_id=boost::this_thread::get_id();
}
void tf1()
{
boost::this_thread::at_thread_exit(exit_func);
BOOST_CHECK(exit_func_thread_id!=boost::this_thread::get_id());
}
void test_thread_exit_func_runs_when_thread_exits()
{
exit_func_thread_id=boost::thread::id();
boost::thread t(tf1);
boost::thread::id const t_id=t.get_id();
t.join();
BOOST_CHECK(exit_func_thread_id==t_id);
}
struct fo
{
void operator()()
{
exit_func_thread_id=boost::this_thread::get_id();
}
};
void tf2()
{
boost::this_thread::at_thread_exit(fo());
BOOST_CHECK(exit_func_thread_id!=boost::this_thread::get_id());
}
void test_can_use_function_object_for_exit_func()
{
exit_func_thread_id=boost::thread::id();
boost::thread t(tf2);
boost::thread::id const t_id=t.get_id();
t.join();
BOOST_CHECK(exit_func_thread_id==t_id);
}
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: futures test suite");
test->add(BOOST_TEST_CASE(test_thread_exit_func_runs_when_thread_exits));
test->add(BOOST_TEST_CASE(test_can_use_function_object_for_exit_func));
return test;
}

View File

@@ -135,9 +135,9 @@ void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
BOOST_CHECK(id==t_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));

View File

@@ -209,9 +209,9 @@ void test_thread_member_function_one_argument()
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread launching test suite");
test->add(BOOST_TEST_CASE(test_thread_function_no_arguments));

View File

@@ -44,9 +44,9 @@ void test_move_assign()
BOOST_CHECK_EQUAL(the_id,y_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_move_on_construction));

View File

@@ -25,9 +25,9 @@ void test_move_from_function_move_return()
BOOST_CHECK_EQUAL(the_id,x_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_move_from_function_move_return));

View File

@@ -25,9 +25,9 @@ void test_move_from_function_return_local()
BOOST_CHECK_EQUAL(the_id,x_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_move_from_function_return_local));

View File

@@ -343,9 +343,9 @@ void test_tss_cleanup_not_called_for_null_pointer()
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
test->add(BOOST_TEST_CASE(test_tss));

View File

@@ -95,9 +95,9 @@ void test_xtime_condvar_backwards_compatibility()
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
test->add(BOOST_TEST_CASE(&test_xtime_cmp));