mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
113 Commits
boost-1.49
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c484c376d3 | ||
|
|
851d6a987f | ||
|
|
9bebd7b35f | ||
|
|
309acb9597 | ||
|
|
a56887167e | ||
|
|
e984dff4e4 | ||
|
|
685e4d446b | ||
|
|
8af680f307 | ||
|
|
6c60cce60d | ||
|
|
5882a675bb | ||
|
|
a5e95845b3 | ||
|
|
5b83d81e40 | ||
|
|
c8e5ad564d | ||
|
|
5edfa273ff | ||
|
|
4db57bcb10 | ||
|
|
3f13340903 | ||
|
|
6abb53c9d3 | ||
|
|
fdd20a519e | ||
|
|
67cc49f333 | ||
|
|
31a34cd0b5 | ||
|
|
ef8c08ba99 | ||
|
|
2991ca6c6f | ||
|
|
52bace18b2 | ||
|
|
767d14ae4f | ||
|
|
1a5c911e36 | ||
|
|
6e42a04e43 | ||
|
|
28be2cfeef | ||
|
|
8be168fd87 | ||
|
|
eee95fef57 | ||
|
|
9ea179b052 | ||
|
|
6868280409 | ||
|
|
e00b764454 | ||
|
|
999613c686 | ||
|
|
c2661d7eb5 | ||
|
|
4d21dd1f47 | ||
|
|
a0a0e57527 | ||
|
|
d8af0d0b4e | ||
|
|
113288e3b0 | ||
|
|
afecfd7c2d | ||
|
|
94d89aac5f | ||
|
|
8831b13efc | ||
|
|
01f99da03a | ||
|
|
080654e3ef | ||
|
|
2ac2eb2a61 | ||
|
|
61b940b705 | ||
|
|
4a4f87e017 | ||
|
|
6d5e7f63a7 | ||
|
|
f77285f375 | ||
|
|
dc5d03a6dc | ||
|
|
ea0961b7f6 | ||
|
|
33d9f9774c | ||
|
|
86097fa038 | ||
|
|
70d9dbc45a | ||
|
|
3926fd3a20 | ||
|
|
7861cf1146 | ||
|
|
0516b86a6e | ||
|
|
ec735d3e9b | ||
|
|
1c5c070983 | ||
|
|
a5c02b73dc | ||
|
|
918b920670 | ||
|
|
de67d2e27e | ||
|
|
bc89df04cb | ||
|
|
c26a4cf082 | ||
|
|
6e1a866b13 | ||
|
|
f91986ad0d | ||
|
|
795cc23f3e | ||
|
|
a3695bd4a0 | ||
|
|
08dc521daf | ||
|
|
8b916d21b1 | ||
|
|
c40f47a78a | ||
|
|
e9fb470b06 | ||
|
|
343d049772 | ||
|
|
86f9480da4 | ||
|
|
8696b610ca | ||
|
|
6f13227eda | ||
|
|
58d5110e61 | ||
|
|
76e53c7bc5 | ||
|
|
cfb08be1a8 | ||
|
|
b5bbb7fb1c | ||
|
|
a76c33f8cc | ||
|
|
810306b8f3 | ||
|
|
6c22bdb3bd | ||
|
|
6a0d3e98bc | ||
|
|
3809321037 | ||
|
|
eef695bdf0 | ||
|
|
ab01ab1e4d | ||
|
|
c8d8a108a7 | ||
|
|
7afd9efcc5 | ||
|
|
56ded87ad2 | ||
|
|
82e503339b | ||
|
|
713d0c7ace | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 |
@@ -43,7 +43,6 @@ 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
|
||||
;
|
||||
|
||||
@@ -181,6 +180,7 @@ rule requirements ( properties * )
|
||||
alias thread_sources
|
||||
: ## win32 sources ##
|
||||
win32/thread.cpp
|
||||
win32/exceptions.cpp
|
||||
win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp
|
||||
: ## requirements ##
|
||||
@@ -190,6 +190,7 @@ alias thread_sources
|
||||
alias thread_sources
|
||||
: ## pthread sources ##
|
||||
pthread/thread.cpp
|
||||
pthread/exceptions.cpp
|
||||
pthread/once.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>pthread
|
||||
|
||||
@@ -26,6 +26,30 @@ 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
|
||||
|
||||
# PDF Options:
|
||||
# TOC Generation: this is needed for FOP-0.9 and later:
|
||||
#<xsl:param>fop1.extensions=1
|
||||
# Or enable this if you're using XEP:
|
||||
<xsl:param>xep.extensions=1
|
||||
# TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9!
|
||||
<xsl:param>fop.extensions=0
|
||||
# No indent on body text:
|
||||
<xsl:param>body.start.indent=0pt
|
||||
# Margin size:
|
||||
<xsl:param>page.margin.inner=0.5in
|
||||
# Margin size:
|
||||
<xsl:param>page.margin.outer=0.5in
|
||||
# Yes, we want graphics for admonishments:
|
||||
<xsl:param>admon.graphics=1
|
||||
# Set this one for PDF generation *only*:
|
||||
# default pnd graphics are awful in PDF form,
|
||||
# better use SVG's instead:
|
||||
<format>pdf:<xsl:param>admon.graphics.extension=".svg"
|
||||
<format>pdf:<xsl:param>admon.graphics.path=$(boost-images)/
|
||||
;
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:acknowledgements Acknowledgments]
|
||||
|
||||
The original implementation of __boost_thread__ was written by William Kempf, with contributions from numerous others. This new
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:barriers Barriers]
|
||||
|
||||
A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is
|
||||
|
||||
@@ -1,69 +1,4 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:changes Changes since]
|
||||
|
||||
[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.
|
||||
|
||||
[heading Changes since boost 1.35]
|
||||
|
||||
The 1.36.0 release of Boost includes a few new features in the thread library:
|
||||
|
||||
* New generic __lock_multiple_ref__ and __try_lock_multiple_ref__ functions for locking multiple mutexes at once.
|
||||
|
||||
* Rvalue reference support for move semantics where the compilers supports it.
|
||||
|
||||
* A few bugs fixed and missing functions added (including the serious win32 condition variable bug).
|
||||
|
||||
* `scoped_try_lock` types are now backwards-compatible with Boost 1.34.0 and previous releases.
|
||||
|
||||
* Support for passing function arguments to the thread function by supplying additional arguments to the __thread__ constructor.
|
||||
|
||||
* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts.
|
||||
|
||||
[heading Changes since boost 1.34]
|
||||
[section:changes Changes since boost 1.34]
|
||||
|
||||
Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface
|
||||
changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking
|
||||
@@ -119,26 +54,4 @@ been moved to __thread_id__.
|
||||
|
||||
* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
|
||||
|
||||
* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
|
||||
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
|
||||
|
||||
[endsect]
|
||||
|
||||
[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]
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
[/
|
||||
(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]
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:condvar_ref Condition Variables]
|
||||
|
||||
[heading Synopsis]
|
||||
@@ -74,8 +67,6 @@ optimizations in some cases, based on the knowledge of the mutex type;
|
||||
|
||||
[section:condition_variable Class `condition_variable`]
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable
|
||||
@@ -84,9 +75,6 @@ optimizations in some cases, based on the knowledge of the mutex type;
|
||||
condition_variable();
|
||||
~condition_variable();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
void wait(boost::unique_lock<boost::mutex>& lock);
|
||||
|
||||
template<typename predicate_type>
|
||||
@@ -296,8 +284,6 @@ return true;
|
||||
|
||||
[section:condition_variable_any Class `condition_variable_any`]
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable_any
|
||||
@@ -306,9 +292,6 @@ return true;
|
||||
condition_variable_any();
|
||||
~condition_variable_any();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& lock);
|
||||
|
||||
@@ -502,8 +485,6 @@ return true;
|
||||
|
||||
[section:condition Typedef `condition`]
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
typedef condition_variable_any condition;
|
||||
|
||||
The typedef `condition` is provided for backwards compatibility with previous boost releases.
|
||||
|
||||
@@ -1,968 +0,0 @@
|
||||
[/
|
||||
(C) Copyright 2008-9 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:reference Futures Reference]
|
||||
|
||||
[section:future_state `state` enum]
|
||||
|
||||
namespace future_state
|
||||
{
|
||||
enum state {uninitialized, waiting, ready};
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:unique_future `unique_future` class template]
|
||||
|
||||
template <typename R>
|
||||
class unique_future
|
||||
{
|
||||
unique_future(unique_future & rhs);// = delete;
|
||||
unique_future& operator=(unique_future& rhs);// = delete;
|
||||
|
||||
public:
|
||||
typedef future_state::state state;
|
||||
|
||||
unique_future();
|
||||
~unique_future();
|
||||
|
||||
// move support
|
||||
unique_future(unique_future && other);
|
||||
unique_future& operator=(unique_future && other);
|
||||
|
||||
void swap(unique_future& other);
|
||||
|
||||
// retrieving the value
|
||||
R&& get();
|
||||
|
||||
// functions to check state
|
||||
state get_state() const;
|
||||
bool is_ready() const;
|
||||
bool has_exception() const;
|
||||
bool has_value() const;
|
||||
|
||||
// waiting for the result to be ready
|
||||
void wait() const;
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration const& rel_time) const;
|
||||
bool timed_wait_until(boost::system_time const& abs_time) const;
|
||||
};
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
|
||||
unique_future();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an uninitialized future.]]
|
||||
|
||||
[[Postconditions:] [[unique_future_is_ready_link `this->is_ready`] returns `false`. [unique_future_get_state_link
|
||||
`this->get_state()`] returns __uninitialized__.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
~unique_future();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_constructor Move Constructor]
|
||||
|
||||
unique_future(unique_future && other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a new future, and transfers ownership of the asynchronous result associated with `other` to `*this`.]]
|
||||
|
||||
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
|
||||
call. `other->get_state()` returns __uninitialized__. If `other` was associated with an asynchronous result, that result is now
|
||||
associated with `*this`. `other` is not associated with any asynchronous result.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_assignment Move Assignment Operator]
|
||||
|
||||
unique_future& operator=(unique_future && other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the asynchronous result associated with `other` to `*this`.]]
|
||||
|
||||
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
|
||||
call. `other->get_state()` returns __uninitialized__. If `other` was associated with an asynchronous result, that result is now
|
||||
associated with `*this`. `other` is not associated with any asynchronous result. If `*this` was associated with an asynchronous
|
||||
result prior to the call, that result no longer has an associated __unique_future__ instance.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:swap Member function `swap()`]
|
||||
|
||||
void swap(unique_future & other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Swaps ownership of the asynchronous results associated with `other` and `*this`.]]
|
||||
|
||||
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
|
||||
call. `other->get_state()` returns the value of `this->get_state()` prior to the call. If `other` was associated with an
|
||||
asynchronous result, that result is now associated with `*this`, otherwise `*this` has no associated result. If `*this` was
|
||||
associated with an asynchronous result, that result is now associated with `other`, otherwise `other` has no associated result.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:get Member function `get()`]
|
||||
|
||||
R&& get();
|
||||
R& unique_future<R&>::get();
|
||||
void unique_future<void>::get();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready as-if by a call to
|
||||
__unique_future_wait__, and retrieves the result (whether that is a value or an exception).]]
|
||||
|
||||
[[Returns:] [If the result type `R` is a reference, returns the stored reference. If `R` is `void`, there is no return
|
||||
value. Otherwise, returns an rvalue-reference to the value stored in the asynchronous result.]]
|
||||
|
||||
[[Postconditions:] [[unique_future_is_ready_link `this->is_ready()`] returns `true`. [unique_future_get_state_link
|
||||
`this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception stored in the
|
||||
asynchronous result in place of a value.]]
|
||||
|
||||
[[Notes:] [`get()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait Member function `wait()`]
|
||||
|
||||
void wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready. If the result is not ready on
|
||||
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
|
||||
['wait callback] if such a callback is called.]]
|
||||
|
||||
[[Postconditions:] [[unique_future_is_ready_link `this->is_ready()`] returns `true`. [unique_future_get_state_link
|
||||
`this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Notes:] [`wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_duration Member function `timed_wait()`]
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration const& wait_duration);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time specified by
|
||||
`wait_duration` has elapsed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is
|
||||
invoked prior to waiting.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
|
||||
elapsed, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
|
||||
['wait callback] if such a callback is called.]]
|
||||
|
||||
[[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and
|
||||
[unique_future_get_state_link `this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Notes:] [`timed_wait()` is an ['interruption point]. `Duration` must be a type that meets the Boost.DateTime time duration requirements.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_absolute Member function `timed_wait()`]
|
||||
|
||||
bool timed_wait(boost::system_time const& wait_timeout);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time point specified by
|
||||
`wait_timeout` has passed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is invoked
|
||||
prior to waiting.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
|
||||
passed, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
|
||||
['wait callback] if such a callback is called.]]
|
||||
|
||||
[[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and
|
||||
[unique_future_get_state_link `this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Notes:] [`timed_wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:is_ready Member function `is_ready()`]
|
||||
|
||||
bool is_ready();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready for retrieval, `false`
|
||||
otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:has_value Member function `has_value()`]
|
||||
|
||||
bool has_value();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with a value rather than an exception.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
|
||||
stored value, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:has_exception Member function `has_exception()`]
|
||||
|
||||
bool has_exception();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with an exception rather than a value.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
|
||||
stored exception, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_state Member function `get_state()`]
|
||||
|
||||
future_state::state get_state();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Determine the state of the asynchronous result associated with `*this`, if any.]]
|
||||
|
||||
[[Returns:] [__uninitialized__ if `*this` is not associated with an asynchronous result. __ready__ if the asynchronous result
|
||||
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared_future `shared_future` class template]
|
||||
|
||||
template <typename R>
|
||||
class shared_future
|
||||
{
|
||||
public:
|
||||
typedef future_state::state state;
|
||||
|
||||
shared_future();
|
||||
~shared_future();
|
||||
|
||||
// copy support
|
||||
shared_future(shared_future const& other);
|
||||
shared_future& operator=(shared_future const& other);
|
||||
|
||||
// move support
|
||||
shared_future(shared_future && other);
|
||||
shared_future(unique_future<R> && other);
|
||||
shared_future& operator=(shared_future && other);
|
||||
shared_future& operator=(unique_future<R> && other);
|
||||
|
||||
void swap(shared_future& other);
|
||||
|
||||
// retrieving the value
|
||||
R get();
|
||||
|
||||
// functions to check state, and wait for ready
|
||||
state get_state() const;
|
||||
bool is_ready() const;
|
||||
bool has_exception() const;
|
||||
bool has_value() const;
|
||||
|
||||
// waiting for the result to be ready
|
||||
void wait() const;
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration const& rel_time) const;
|
||||
bool timed_wait_until(boost::system_time const& abs_time) const;
|
||||
};
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
|
||||
shared_future();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an uninitialized future.]]
|
||||
|
||||
[[Postconditions:] [[shared_future_is_ready_link `this->is_ready`] returns `false`. [shared_future_get_state_link
|
||||
`this->get_state()`] returns __uninitialized__.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get Member function `get()`]
|
||||
|
||||
const R& get();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready as-if by a call to
|
||||
__shared_future_wait__, and returns a `const` reference to the result.]]
|
||||
|
||||
[[Returns:] [If the result type `R` is a reference, returns the stored reference. If `R` is `void`, there is no return
|
||||
value. Otherwise, returns a `const` reference to the value stored in the asynchronous result.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the
|
||||
result associated with `*this` is not ready at the point of the call, and the current thread is interrupted.]]
|
||||
|
||||
[[Notes:] [`get()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait Member function `wait()`]
|
||||
|
||||
void wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready. If the result is not ready on
|
||||
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
|
||||
['wait callback] if such a callback is called.]]
|
||||
|
||||
[[Postconditions:] [[shared_future_is_ready_link `this->is_ready()`] returns `true`. [shared_future_get_state_link
|
||||
`this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Notes:] [`wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_duration Member function `timed_wait()`]
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration const& wait_duration);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time specified by
|
||||
`wait_duration` has elapsed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is
|
||||
invoked prior to waiting.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
|
||||
elapsed, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
|
||||
['wait callback] if such a callback is called.]]
|
||||
|
||||
[[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and
|
||||
[shared_future_get_state_link `this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Notes:] [`timed_wait()` is an ['interruption point]. `Duration` must be a type that meets the Boost.DateTime time duration requirements.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_absolute Member function `timed_wait()`]
|
||||
|
||||
bool timed_wait(boost::system_time const& wait_timeout);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time point specified by
|
||||
`wait_timeout` has passed. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is invoked
|
||||
prior to waiting.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has
|
||||
passed, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result
|
||||
associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the
|
||||
['wait callback] if such a callback is called.]]
|
||||
|
||||
[[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and
|
||||
[shared_future_get_state_link `this->get_state()`] returns __ready__.]]
|
||||
|
||||
[[Notes:] [`timed_wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:is_ready Member function `is_ready()`]
|
||||
|
||||
bool is_ready();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready for retrieval, `false`
|
||||
otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:has_value Member function `has_value()`]
|
||||
|
||||
bool has_value();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with a value rather than an exception.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
|
||||
stored value, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:has_exception Member function `has_exception()`]
|
||||
|
||||
bool has_exception();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Checks to see if the asynchronous result associated with `*this` is set with an exception rather than a value.]]
|
||||
|
||||
[[Returns:] [`true` if `*this` is associated with an asynchronous result, that result is ready for retrieval, and the result is a
|
||||
stored exception, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_state Member function `get_state()`]
|
||||
|
||||
future_state::state get_state();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Determine the state of the asynchronous result associated with `*this`, if any.]]
|
||||
|
||||
[[Returns:] [__uninitialized__ if `*this` is not associated with an asynchronous result. __ready__ if the asynchronous result
|
||||
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:promise `promise` class template]
|
||||
|
||||
template <typename R>
|
||||
class promise
|
||||
{
|
||||
promise(promise & rhs);// = delete;
|
||||
promise & operator=(promise & rhs);// = delete;
|
||||
public:
|
||||
// template <class Allocator> explicit promise(Allocator a);
|
||||
|
||||
promise();
|
||||
~promise();
|
||||
|
||||
// Move support
|
||||
promise(promise && rhs);
|
||||
promise & operator=(promise&& rhs);
|
||||
|
||||
void swap(promise& other);
|
||||
// Result retrieval
|
||||
unique_future<R> get_future();
|
||||
|
||||
// Set the value
|
||||
void set_value(R& r);
|
||||
void set_value(R&& r);
|
||||
void set_exception(boost::exception_ptr e);
|
||||
|
||||
template<typename F>
|
||||
void set_wait_callback(F f);
|
||||
};
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
|
||||
promise();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a new __promise__ with no associated result.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_constructor Move Constructor]
|
||||
|
||||
promise(promise && other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a new __promise__, and transfers ownership of the result associated with `other` to `*this`, leaving `other`
|
||||
with no associated result.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_assignment Move Assignment Operator]
|
||||
|
||||
promise& operator=(promise && other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the result associated with `other` to `*this`, leaving `other` with no associated result. If there
|
||||
was already a result associated with `*this`, and that result was not ['ready], sets any futures associated with that result to
|
||||
['ready] with a __broken_promise__ exception as the result. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
~promise();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys `*this`. If there was a result associated with `*this`, and that result is not ['ready], sets any futures
|
||||
associated with that task to ['ready] with a __broken_promise__ exception as the result.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_future Member Function `get_future()`]
|
||||
|
||||
unique_future<R> get_future();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with
|
||||
`*this`. Returns a __unique_future__ associated with the result associated with `*this`. ]]
|
||||
|
||||
[[Throws:] [__future_already_retrieved__ if the future associated with the task has already been retrieved. `std::bad_alloc` if any
|
||||
memory necessary could not be allocated.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:set_value Member Function `set_value()`]
|
||||
|
||||
void set_value(R&& r);
|
||||
void set_value(const R& r);
|
||||
void promise<R&>::set_value(R& r);
|
||||
void promise<void>::set_value();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with
|
||||
`*this`. Store the value `r` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous
|
||||
result are woken.]]
|
||||
|
||||
[[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_value__ or
|
||||
__shared_future_has_value__ for those futures shall return `true`.]]
|
||||
|
||||
[[Throws:] [__promise_already_satisfied__ if the result associated with `*this` is already ['ready]. `std::bad_alloc` if the memory
|
||||
required for storage of the result cannot be allocated. Any exception thrown by the copy or move-constructor of `R`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:set_exception Member Function `set_exception()`]
|
||||
|
||||
void set_exception(boost::exception_ptr e);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with
|
||||
`*this`. Store the exception `e` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous
|
||||
result are woken.]]
|
||||
|
||||
[[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_exception__ or
|
||||
__shared_future_has_exception__ for those futures shall return `true`.]]
|
||||
|
||||
[[Throws:] [__promise_already_satisfied__ if the result associated with `*this` is already ['ready]. `std::bad_alloc` if the memory
|
||||
required for storage of the result cannot be allocated.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:set_wait_callback Member Function `set_wait_callback()`]
|
||||
|
||||
template<typename F>
|
||||
void set_wait_callback(F f);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[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
|
||||
existing wait callback store alongside that result. If a thread subsequently calls one of the wait functions on a __unique_future__
|
||||
or __shared_future__ associated with this result, and the result is not ['ready], `f(*this)` shall be invoked.]]
|
||||
|
||||
[[Throws:] [`std::bad_alloc` if memory cannot be allocated for the required storage.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:packaged_task `packaged_task` class template]
|
||||
|
||||
template<typename R>
|
||||
class packaged_task
|
||||
{
|
||||
packaged_task(packaged_task&);// = delete;
|
||||
packaged_task& operator=(packaged_task&);// = delete;
|
||||
|
||||
public:
|
||||
// construction and destruction
|
||||
template <class F>
|
||||
explicit packaged_task(F const& f);
|
||||
|
||||
explicit packaged_task(R(*f)());
|
||||
|
||||
template <class F>
|
||||
explicit packaged_task(F&& f);
|
||||
|
||||
// template <class F, class Allocator>
|
||||
// explicit packaged_task(F const& f, Allocator a);
|
||||
// template <class F, class Allocator>
|
||||
// explicit packaged_task(F&& f, Allocator a);
|
||||
|
||||
~packaged_task()
|
||||
{}
|
||||
|
||||
// move support
|
||||
packaged_task(packaged_task&& other);
|
||||
packaged_task& operator=(packaged_task&& other);
|
||||
|
||||
void swap(packaged_task& other);
|
||||
// result retrieval
|
||||
unique_future<R> get_future();
|
||||
|
||||
// execution
|
||||
void operator()();
|
||||
|
||||
template<typename F>
|
||||
void set_wait_callback(F f);
|
||||
};
|
||||
|
||||
[section:task_constructor Task Constructor]
|
||||
|
||||
template<typename F>
|
||||
packaged_task(F const &f);
|
||||
|
||||
packaged_task(R(*f)());
|
||||
|
||||
template<typename F>
|
||||
packaged_task(F&&f);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`f()` is a valid expression with a return type convertible to `R`. Invoking a copy of `f` shall behave the same
|
||||
as invoking `f`.]]
|
||||
|
||||
[[Effects:] [Constructs a new __packaged_task__ with a copy of `f` stored as the associated task.]]
|
||||
|
||||
[[Throws:] [Any exceptions thrown by the copy (or move) constructor of `f`. `std::bad_alloc` if memory for the internal data
|
||||
structures could not be allocated.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_constructor Move Constructor]
|
||||
|
||||
packaged_task(packaged_task && other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a new __packaged_task__, and transfers ownership of the task associated with `other` to `*this`, leaving `other`
|
||||
with no associated task.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_assignment Move Assignment Operator]
|
||||
|
||||
packaged_task& operator=(packaged_task && other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the task associated with `other` to `*this`, leaving `other` with no associated task. If there
|
||||
was already a task associated with `*this`, and that task has not been invoked, sets any futures associated with that task to
|
||||
['ready] with a __broken_promise__ exception as the result. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
~packaged_task();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys `*this`. If there was a task associated with `*this`, and that task has not been invoked, sets any futures
|
||||
associated with that task to ['ready] with a __broken_promise__ exception as the result.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_future Member Function `get_future()`]
|
||||
|
||||
unique_future<R> get_future();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns a __unique_future__ associated with the result of the task associated with `*this`. ]]
|
||||
|
||||
[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of
|
||||
__packaged_task__. __future_already_retrieved__ if the future associated with the task has already been retrieved.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:call_operator Member Function `operator()()`]
|
||||
|
||||
void operator()();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Invoke the task associated with `*this` and store the result in the corresponding future. If the task returns normally,
|
||||
the return value is stored as the asynchronous result, otherwise the exception thrown is stored. Any threads blocked waiting for the
|
||||
asynchronous result associated with this task are woken.]]
|
||||
|
||||
[[Postconditions:] [All futures waiting on the asynchronous result are ['ready]]]
|
||||
|
||||
[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of
|
||||
__packaged_task__. __task_already_started__ if the task has already been invoked.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:set_wait_callback Member Function `set_wait_callback()`]
|
||||
|
||||
template<typename F>
|
||||
void set_wait_callback(F f);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __packaged_task__ 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 task associated with `*this` as a ['wait callback]. This will replace any existing wait
|
||||
callback store alongside that task. If a thread subsequently calls one of the wait functions on a __unique_future__ or
|
||||
__shared_future__ associated with this task, and the result of the task is not ['ready], `f(*this)` shall be invoked.]]
|
||||
|
||||
[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of
|
||||
__packaged_task__.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for_any Non-member function `wait_for_any()`]
|
||||
|
||||
template<typename Iterator>
|
||||
Iterator wait_for_any(Iterator begin,Iterator end);
|
||||
|
||||
template<typename F1,typename F2>
|
||||
unsigned wait_for_any(F1& f1,F2& f2);
|
||||
|
||||
template<typename F1,typename F2,typename F3>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3);
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4);
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4,typename F5>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [The types `Fn` shall be specializations of
|
||||
__unique_future__ or __shared_future__, and `Iterator` shall be a
|
||||
forward iterator with a `value_type` which is a specialization of
|
||||
__unique_future__ or __shared_future__.]]
|
||||
|
||||
[[Effects:] [Waits until at least one of the specified futures is ['ready].]]
|
||||
|
||||
[[Returns:] [The range-based overload returns an `Iterator` identifying the first future in the range that was detected as
|
||||
['ready]. The remaining overloads return the zero-based index of the first future that was detected as ['ready] (first parameter =>
|
||||
0, second parameter => 1, etc.).]]
|
||||
|
||||
[[Throws:] [__thread_interrupted__ if the current thread is interrupted. Any exception thrown by the ['wait callback] associated
|
||||
with any of the futures being waited for. `std::bad_alloc` if memory could not be allocated for the internal wait structures.]]
|
||||
|
||||
[[Notes:] [`wait_for_any()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for_all Non-member function `wait_for_all()`]
|
||||
|
||||
template<typename Iterator>
|
||||
void wait_for_all(Iterator begin,Iterator end);
|
||||
|
||||
template<typename F1,typename F2>
|
||||
void wait_for_all(F1& f1,F2& f2);
|
||||
|
||||
template<typename F1,typename F2,typename F3>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3);
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4);
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4,typename F5>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [The types `Fn` shall be specializations of
|
||||
__unique_future__ or __shared_future__, and `Iterator` shall be a
|
||||
forward iterator with a `value_type` which is a specialization of
|
||||
__unique_future__ or __shared_future__.]]
|
||||
|
||||
[[Effects:] [Waits until all of the specified futures are ['ready].]]
|
||||
|
||||
[[Throws:] [Any exceptions thrown by a call to `wait()` on the specified futures.]]
|
||||
|
||||
[[Notes:] [`wait_for_all()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
187
doc/futures.qbk
187
doc/futures.qbk
@@ -1,187 +0,0 @@
|
||||
[/
|
||||
(C) Copyright 2008-9 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:futures Futures]
|
||||
|
||||
[template future_state_link[link_text] [link thread.synchronization.futures.reference.future_state [link_text]]]
|
||||
[def __uninitialized__ [future_state_link `boost::future_state::uninitialized`]]
|
||||
[def __ready__ [future_state_link `boost::future_state::ready`]]
|
||||
[def __waiting__ [future_state_link `boost::future_state::waiting`]]
|
||||
|
||||
[def __future_uninitialized__ `boost::future_uninitialized`]
|
||||
[def __broken_promise__ `boost::broken_promise`]
|
||||
[def __future_already_retrieved__ `boost::future_already_retrieved`]
|
||||
[def __task_moved__ `boost::task_moved`]
|
||||
[def __task_already_started__ `boost::task_already_started`]
|
||||
[def __promise_already_satisfied__ `boost::promise_already_satisfied`]
|
||||
|
||||
[def __thread_interrupted__ `boost::thread_interrupted`]
|
||||
|
||||
|
||||
[template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]]
|
||||
[def __unique_future__ [unique_future_link `boost::unique_future`]]
|
||||
|
||||
[template unique_future_get_link[link_text] [link thread.synchronization.futures.reference.unique_future.get [link_text]]]
|
||||
[def __unique_future_get__ [unique_future_get_link `boost::unique_future<R>::get()`]]
|
||||
|
||||
[template unique_future_wait_link[link_text] [link thread.synchronization.futures.reference.unique_future.wait [link_text]]]
|
||||
[def __unique_future_wait__ [unique_future_wait_link `boost::unique_future<R>::wait()`]]
|
||||
|
||||
[template unique_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.unique_future.is_ready [link_text]]]
|
||||
[def __unique_future_is_ready__ [unique_future_is_ready_link `boost::unique_future<R>::is_ready()`]]
|
||||
|
||||
[template unique_future_has_value_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_value [link_text]]]
|
||||
[def __unique_future_has_value__ [unique_future_has_value_link `boost::unique_future<R>::has_value()`]]
|
||||
|
||||
[template unique_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_exception [link_text]]]
|
||||
[def __unique_future_has_exception__ [unique_future_has_exception_link `boost::unique_future<R>::has_exception()`]]
|
||||
|
||||
[template unique_future_get_state_link[link_text] [link thread.synchronization.futures.reference.unique_future.get_state [link_text]]]
|
||||
[def __unique_future_get_state__ [unique_future_get_state_link `boost::unique_future<R>::get_state()`]]
|
||||
|
||||
[template shared_future_link[link_text] [link thread.synchronization.futures.reference.shared_future [link_text]]]
|
||||
[def __shared_future__ [shared_future_link `boost::shared_future`]]
|
||||
|
||||
[template shared_future_get_link[link_text] [link thread.synchronization.futures.reference.shared_future.get [link_text]]]
|
||||
[def __shared_future_get__ [shared_future_get_link `boost::shared_future<R>::get()`]]
|
||||
|
||||
[template shared_future_wait_link[link_text] [link thread.synchronization.futures.reference.shared_future.wait [link_text]]]
|
||||
[def __shared_future_wait__ [shared_future_wait_link `boost::shared_future<R>::wait()`]]
|
||||
|
||||
[template shared_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.shared_future.is_ready [link_text]]]
|
||||
[def __shared_future_is_ready__ [shared_future_is_ready_link `boost::shared_future<R>::is_ready()`]]
|
||||
|
||||
[template shared_future_has_value_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_value [link_text]]]
|
||||
[def __shared_future_has_value__ [shared_future_has_value_link `boost::shared_future<R>::has_value()`]]
|
||||
|
||||
[template shared_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_exception [link_text]]]
|
||||
[def __shared_future_has_exception__ [shared_future_has_exception_link `boost::shared_future<R>::has_exception()`]]
|
||||
|
||||
[template shared_future_get_state_link[link_text] [link thread.synchronization.futures.reference.shared_future.get_state [link_text]]]
|
||||
[def __shared_future_get_state__ [shared_future_get_state_link `boost::shared_future<R>::get_state()`]]
|
||||
|
||||
[template promise_link[link_text] [link thread.synchronization.futures.reference.promise [link_text]]]
|
||||
[def __promise__ [promise_link `boost::promise`]]
|
||||
|
||||
[template packaged_task_link[link_text] [link thread.synchronization.futures.reference.packaged_task [link_text]]]
|
||||
[def __packaged_task__ [packaged_task_link `boost::packaged_task`]]
|
||||
|
||||
[template wait_for_any_link[link_text] [link thread.synchronization.futures.reference.wait_for_any [link_text]]]
|
||||
[def __wait_for_any__ [wait_for_any_link `boost::wait_for_any()`]]
|
||||
|
||||
[template wait_for_all_link[link_text] [link thread.synchronization.futures.reference.wait_for_all [link_text]]]
|
||||
[def __wait_for_all__ [wait_for_all_link `boost::wait_for_all()`]]
|
||||
|
||||
|
||||
[section:overview Overview]
|
||||
|
||||
The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or
|
||||
on a single thread in response to external stimuli, or on-demand.
|
||||
|
||||
This is done through the provision of four class templates: __unique_future__ and __shared_future__ which are used to retrieve the
|
||||
asynchronous results, and __promise__ and __packaged_task__ which are used to generate the asynchronous results.
|
||||
|
||||
An instance of __unique_future__ holds the one and only reference to a result. Ownership can be transferred between instances using
|
||||
the move constructor or move-assignment operator, but at most one instance holds a reference to a given asynchronous result. When
|
||||
the result is ready, it is returned from __unique_future_get__ by rvalue-reference to allow the result to be moved or copied as
|
||||
appropriate for the type.
|
||||
|
||||
On the other hand, many instances of __shared_future__ may reference the same result. Instances can be freely copied and assigned,
|
||||
and __shared_future_get__ returns a `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
|
||||
instance of __unique_future__ into an instance of __shared_future__, thus transferring ownership of the associated asynchronous
|
||||
result, but not vice-versa.
|
||||
|
||||
You can wait for futures either individually or with one of the __wait_for_any__ and __wait_for_all__ functions.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:creating Creating asynchronous values]
|
||||
|
||||
You can set the value in a future with either a __promise__ or a __packaged_task__. A __packaged_task__ is a callable object that
|
||||
wraps a function or callable object. When the packaged task is invoked, it invokes the contained function in turn, and populates a
|
||||
future with the return value. This is an answer to the perennial question: "how do I return a value from a thread?": package the
|
||||
function you wish to run as a __packaged_task__ and pass the packaged task to the thread constructor. The future retrieved from the
|
||||
packaged task can then be used to obtain the return value. If the function throws an exception, that is stored in the future in
|
||||
place of the return value.
|
||||
|
||||
int calculate_the_answer_to_life_the_universe_and_everything()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
A __promise__ is a bit more low level: it just provides explicit functions to store a value or an exception in the associated
|
||||
future. A promise can therefore be used where the value may come from more than one possible source, or where a single operation may
|
||||
produce multiple values.
|
||||
|
||||
boost::promise<int> pi;
|
||||
boost::unique_future<int> fi;
|
||||
fi=pi.get_future();
|
||||
|
||||
pi.set_value(42);
|
||||
|
||||
assert(fi.is_ready());
|
||||
assert(fi.has_value());
|
||||
assert(!fi.has_exception());
|
||||
assert(fi.get_state()==boost::future_state::ready);
|
||||
assert(fi.get()==42);
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lazy_futures Wait Callbacks and Lazy Futures]
|
||||
|
||||
Both __promise__ and __packaged_task__ support ['wait callbacks] that are invoked when a thread blocks in a call to `wait()` or
|
||||
`timed_wait()` on a future that is waiting for the result from the __promise__ or __packaged_task__, in the thread that is doing the
|
||||
waiting. These can be set using the `set_wait_callback()` member function on the __promise__ or __packaged_task__ in question.
|
||||
|
||||
This allows ['lazy futures] where the result is not actually computed until it is needed by some thread. In the example below, the
|
||||
call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task to set the value. If you remove the call to
|
||||
`f.get()`, the task is not ever run.
|
||||
|
||||
int calculate_the_answer_to_life_the_universe_and_everything()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
void invoke_lazy_task(boost::packaged_task<int>& task)
|
||||
{
|
||||
try
|
||||
{
|
||||
task();
|
||||
}
|
||||
catch(boost::task_already_started&)
|
||||
{}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything);
|
||||
task.set_wait_callback(invoke_lazy_task);
|
||||
boost::unique_future<int> f(task.get_future());
|
||||
|
||||
assert(f.get()==42);
|
||||
}
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[include future_ref.qbk]
|
||||
|
||||
[endsect]
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:mutex_concepts Mutex Concepts]
|
||||
|
||||
A mutex object facilitates protection against data races and allows thread-safe synchronization of data between threads. A thread
|
||||
@@ -310,29 +303,8 @@ 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>
|
||||
|
||||
template<typename Lockable>
|
||||
class lock_guard
|
||||
{
|
||||
@@ -397,8 +369,6 @@ object passed to the constructor.]]
|
||||
|
||||
[section:unique_lock Class template `unique_lock`]
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
template<typename Lockable>
|
||||
class unique_lock
|
||||
{
|
||||
@@ -640,8 +610,6 @@ __owns_lock_ref__ returns `false`.]]
|
||||
|
||||
[section:shared_lock Class template `shared_lock`]
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
template<typename Lockable>
|
||||
class shared_lock
|
||||
{
|
||||
@@ -875,8 +843,6 @@ __owns_lock_shared_ref__ returns `false`.]]
|
||||
|
||||
[section:upgrade_lock Class template `upgrade_lock`]
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
template<typename Lockable>
|
||||
class upgrade_lock
|
||||
{
|
||||
@@ -924,8 +890,6 @@ state (including the destructor) must be called by the same thread that acquired
|
||||
|
||||
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`]
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
template <class Lockable>
|
||||
class upgrade_to_unique_lock
|
||||
{
|
||||
@@ -950,189 +914,4 @@ __lockable_concept_type__ is downgraded back to ['upgrade ownership].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:scoped_try_lock Mutex-specific class `scoped_try_lock`]
|
||||
|
||||
class MutexType::scoped_try_lock
|
||||
{
|
||||
private:
|
||||
MutexType::scoped_try_lock(MutexType::scoped_try_lock<MutexType>& other);
|
||||
MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock<MutexType>& other);
|
||||
public:
|
||||
MutexType::scoped_try_lock();
|
||||
explicit MutexType::scoped_try_lock(MutexType& m);
|
||||
MutexType::scoped_try_lock(MutexType& m_,adopt_lock_t);
|
||||
MutexType::scoped_try_lock(MutexType& m_,defer_lock_t);
|
||||
MutexType::scoped_try_lock(MutexType& m_,try_to_lock_t);
|
||||
|
||||
MutexType::scoped_try_lock(MutexType::scoped_try_lock<MutexType>&& other);
|
||||
MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock<MutexType>&& other);
|
||||
|
||||
void swap(MutexType::scoped_try_lock&& other);
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
bool owns_lock() const;
|
||||
|
||||
MutexType* mutex() const;
|
||||
MutexType* release();
|
||||
bool operator!() const;
|
||||
|
||||
typedef ``['unspecified-bool-type]`` bool_type;
|
||||
operator bool_type() const;
|
||||
};
|
||||
|
||||
The member typedef `scoped_try_lock` is provided for each distinct
|
||||
`MutexType` as a typedef to a class with the preceding definition. The
|
||||
semantics of each constructor and member function are identical to
|
||||
those of [unique_lock_link `boost::unique_lock<MutexType>`] for the same `MutexType`, except
|
||||
that the constructor that takes a single reference to a mutex will
|
||||
call [try_lock_ref_link `m.try_lock()`] rather than `m.lock()`.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lock_functions Lock functions]
|
||||
|
||||
[section:lock_multiple Non-member function `lock(Lockable1,Lockable2,...)`]
|
||||
|
||||
template<typename Lockable1,typename Lockable2>
|
||||
void lock(Lockable1& l1,Lockable2& l2);
|
||||
|
||||
template<typename Lockable1,typename Lockable2,typename Lockable3>
|
||||
void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3);
|
||||
|
||||
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4>
|
||||
void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4);
|
||||
|
||||
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4,typename Lockable5>
|
||||
void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Locks the __lockable_concept_type__ objects supplied as
|
||||
arguments in an unspecified and indeterminate order in a way that
|
||||
avoids deadlock. It is safe to call this function concurrently from
|
||||
multiple threads with the same mutexes (or other lockable objects) in
|
||||
different orders without risk of deadlock. If any of the __lock_ref__
|
||||
or __try_lock_ref__ operations on the supplied
|
||||
__lockable_concept_type__ objects throws an exception any locks
|
||||
acquired by the function will be released before the function exits.]]
|
||||
|
||||
[[Throws:] [Any exceptions thrown by calling __lock_ref__ or
|
||||
__try_lock_ref__ on the supplied __lockable_concept_type__ objects.]]
|
||||
|
||||
[[Postcondition:] [All the supplied __lockable_concept_type__ objects
|
||||
are locked by the calling thread.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lock_range Non-member function `lock(begin,end)`]
|
||||
|
||||
template<typename ForwardIterator>
|
||||
void lock(ForwardIterator begin,ForwardIterator end);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [The `value_type` of `ForwardIterator` must implement the __lockable_concept__]]
|
||||
|
||||
[[Effects:] [Locks all the __lockable_concept_type__ objects in the
|
||||
supplied range in an unspecified and indeterminate order in a way that
|
||||
avoids deadlock. It is safe to call this function concurrently from
|
||||
multiple threads with the same mutexes (or other lockable objects) in
|
||||
different orders without risk of deadlock. If any of the __lock_ref__
|
||||
or __try_lock_ref__ operations on the __lockable_concept_type__
|
||||
objects in the supplied range throws an exception any locks acquired
|
||||
by the function will be released before the function exits.]]
|
||||
|
||||
[[Throws:] [Any exceptions thrown by calling __lock_ref__ or
|
||||
__try_lock_ref__ on the supplied __lockable_concept_type__ objects.]]
|
||||
|
||||
[[Postcondition:] [All the __lockable_concept_type__ objects in the
|
||||
supplied range are locked by the calling thread.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_lock_multiple Non-member function `try_lock(Lockable1,Lockable2,...)`]
|
||||
|
||||
template<typename Lockable1,typename Lockable2>
|
||||
int try_lock(Lockable1& l1,Lockable2& l2);
|
||||
|
||||
template<typename Lockable1,typename Lockable2,typename Lockable3>
|
||||
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3);
|
||||
|
||||
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4>
|
||||
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4);
|
||||
|
||||
template<typename Lockable1,typename Lockable2,typename Lockable3,typename Lockable4,typename Lockable5>
|
||||
int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Calls __try_lock_ref__ on each of the
|
||||
__lockable_concept_type__ objects supplied as arguments. If any of the
|
||||
calls to __try_lock_ref__ returns `false` then all locks acquired are
|
||||
released and the zero-based index of the failed lock is returned.
|
||||
|
||||
If any of the __try_lock_ref__ operations on the supplied
|
||||
__lockable_concept_type__ objects throws an exception any locks
|
||||
acquired by the function will be released before the function exits.]]
|
||||
|
||||
[[Returns:] [`-1` if all the supplied __lockable_concept_type__ objects
|
||||
are now locked by the calling thread, the zero-based index of the
|
||||
object which could not be locked otherwise.]]
|
||||
|
||||
[[Throws:] [Any exceptions thrown by calling __try_lock_ref__ on the
|
||||
supplied __lockable_concept_type__ objects.]]
|
||||
|
||||
[[Postcondition:] [If the function returns `-1`, all the supplied
|
||||
__lockable_concept_type__ objects are locked by the calling
|
||||
thread. Otherwise any locks acquired by this function will have been
|
||||
released.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_lock_range Non-member function `try_lock(begin,end)`]
|
||||
|
||||
template<typename ForwardIterator>
|
||||
ForwardIterator try_lock(ForwardIterator begin,ForwardIterator end);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [The `value_type` of `ForwardIterator` must implement the __lockable_concept__]]
|
||||
|
||||
[[Effects:] [Calls __try_lock_ref__ on each of the
|
||||
__lockable_concept_type__ objects in the supplied range. If any of the
|
||||
calls to __try_lock_ref__ returns `false` then all locks acquired are
|
||||
released and an iterator referencing the failed lock is returned.
|
||||
|
||||
If any of the __try_lock_ref__ operations on the supplied
|
||||
__lockable_concept_type__ objects throws an exception any locks
|
||||
acquired by the function will be released before the function exits.]]
|
||||
|
||||
[[Returns:] [`end` if all the supplied __lockable_concept_type__
|
||||
objects are now locked by the calling thread, an iterator referencing
|
||||
the object which could not be locked otherwise.]]
|
||||
|
||||
[[Throws:] [Any exceptions thrown by calling __try_lock_ref__ on the
|
||||
supplied __lockable_concept_type__ objects.]]
|
||||
|
||||
[[Postcondition:] [If the function returns `end` then all the
|
||||
__lockable_concept_type__ objects in the supplied range are locked by
|
||||
the calling thread, otherwise all locks acquired by the function have
|
||||
been released.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:mutex_types Mutex Types]
|
||||
|
||||
[section:mutex Class `mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
@@ -26,7 +17,7 @@
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given
|
||||
@@ -53,8 +44,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
|
||||
[section:try_mutex Typedef `try_mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost.
|
||||
@@ -63,8 +52,6 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
|
||||
|
||||
[section:timed_mutex Class `timed_mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
@@ -84,7 +71,7 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
@@ -112,8 +99,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
|
||||
[section:recursive_mutex Class `recursive_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
@@ -129,7 +114,7 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can
|
||||
@@ -158,8 +143,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
|
||||
[section:recursive_try_mutex Typedef `recursive_try_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost.
|
||||
@@ -168,8 +151,6 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
|
||||
|
||||
[section:recursive_timed_mutex Class `recursive_timed_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
@@ -190,7 +171,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
typedef scoped_lock scoped_timed_lock;
|
||||
};
|
||||
|
||||
|
||||
24
doc/once.qbk
24
doc/once.qbk
@@ -1,18 +1,9 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:once One-time Initialization]
|
||||
|
||||
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
|
||||
|
||||
[section:once_flag Typedef `once_flag`]
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
typedef platform-specific-type once_flag;
|
||||
#define BOOST_ONCE_INIT platform-specific-initializer
|
||||
|
||||
@@ -24,8 +15,6 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
|
||||
|
||||
[section:call_once Non-member function `call_once`]
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
template<typename Callable>
|
||||
void call_once(once_flag& flag,Callable func);
|
||||
|
||||
@@ -35,8 +24,8 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
|
||||
be equivalent to calling the original. ]]
|
||||
|
||||
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
|
||||
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
|
||||
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
|
||||
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func(args)`, and the invocation of
|
||||
`call_once` is effective if and only if `func(args)` returns without exception. If an exception is thrown, the exception is
|
||||
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
|
||||
without invoking `func`. ]]
|
||||
|
||||
@@ -45,15 +34,6 @@ 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);
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:overview Overview]
|
||||
|
||||
__boost_thread__ enables the use of multiple threads of execution with shared data in portable C++ code. It provides classes and
|
||||
@@ -19,12 +12,4 @@ closely follow the proposals presented to the C++ Standards Committee, in partic
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
|
||||
|
||||
In order to use the classes and functions described here, you can
|
||||
either include the specific headers specified by the descriptions of
|
||||
each class or function, or include the master thread library header:
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
which includes all the other headers in turn.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:shared_mutex Class `shared_mutex`]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
class shared_mutex
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[article Thread
|
||||
[quickbook 1.4]
|
||||
[authors [Williams, Anthony]]
|
||||
@@ -38,12 +31,6 @@
|
||||
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.lock [link_text]]]
|
||||
[def __lock_ref__ [lock_ref_link `lock()`]]
|
||||
|
||||
[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]]
|
||||
[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]]
|
||||
|
||||
[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]]
|
||||
[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]]
|
||||
|
||||
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.unlock [link_text]]]
|
||||
[def __unlock_ref__ [unlock_ref_link `unlock()`]]
|
||||
|
||||
@@ -107,10 +94,8 @@
|
||||
[def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]]
|
||||
[def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]]
|
||||
|
||||
[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]]
|
||||
|
||||
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
|
||||
[def __unique_lock__ [unique_lock_link `boost::unique_lock`]]
|
||||
[def __unique_lock__ [link thread.synchronization.locks.unique_lock `boost::unique_lock`]]
|
||||
[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]]
|
||||
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
|
||||
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
|
||||
@@ -158,7 +143,6 @@
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[include futures.qbk]
|
||||
[endsect]
|
||||
|
||||
[include tss.qbk]
|
||||
@@ -166,5 +150,3 @@
|
||||
[include time.qbk]
|
||||
|
||||
[include acknowledgements.qbk]
|
||||
|
||||
[include compliance.qbk]
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:thread_management Thread Management]
|
||||
|
||||
[heading Synopsis]
|
||||
@@ -163,48 +156,8 @@ 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>
|
||||
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
@@ -214,9 +167,6 @@ As the single way to interrupt a thread is through a __thread__ instance, `inter
|
||||
template <class F>
|
||||
explicit thread(F f);
|
||||
|
||||
template <class F,class A1,class A2,...>
|
||||
thread(F f,A1 a1,A2 a2,...);
|
||||
|
||||
template <class F>
|
||||
thread(detail::thread_move_t<F> f);
|
||||
|
||||
@@ -257,7 +207,6 @@ As the single way to interrupt a thread is through a __thread__ instance, `inter
|
||||
};
|
||||
|
||||
void swap(thread& lhs,thread& rhs);
|
||||
detail::thread_move_t<thread> move(detail::thread_move_t<thread> t);
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
|
||||
@@ -273,40 +222,6 @@ As the single way to interrupt a thread is through a __thread__ instance, `inter
|
||||
|
||||
[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>
|
||||
@@ -328,30 +243,6 @@ not of type __thread_interrupted__, then `std::terminate()` will be called.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:multiple_argument_constructor Thread Constructor with arguments]
|
||||
|
||||
template <class F,class A1,class A2,...>
|
||||
thread(F f,A1 a1,A2 a2,...);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`F` and each `A`n must by copyable or movable.]]
|
||||
|
||||
[[Effects:] [As if [link
|
||||
thread.thread_management.thread.callable_constructor
|
||||
`thread(boost::bind(f,a1,a2,...))`. Consequently, `f` and each `a`n
|
||||
are copied into internal storage for access by the new thread.]]]
|
||||
|
||||
[[Postconditions:] [`*this` refers to the newly created thread of execution.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
[[Note:] [Currently up to nine additional arguments `a1` to `a9` can be specified in addition to the function `f`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor Thread Destructor]
|
||||
|
||||
~thread();
|
||||
@@ -582,8 +473,6 @@ value as `this->get_id()` prior to the call.]]
|
||||
|
||||
[section:non_member_swap Non-member function `swap()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
void swap(thread& lhs,thread& rhs);
|
||||
|
||||
[variablelist
|
||||
@@ -594,31 +483,9 @@ 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`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
class thread::id
|
||||
{
|
||||
public:
|
||||
@@ -713,7 +580,7 @@ execution.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:less_than_or_equal `operator<=`]
|
||||
[section:less_than_or_equal `operator>=`]
|
||||
|
||||
bool operator<=(const id& y) const;
|
||||
|
||||
@@ -767,8 +634,6 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[section:get_id Non-member function `get_id()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
thread::id get_id();
|
||||
@@ -786,8 +651,6 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[section:interruption_point Non-member function `interruption_point()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void interruption_point();
|
||||
@@ -805,8 +668,6 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[section:interruption_requested Non-member function `interruption_requested()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
bool interruption_requested();
|
||||
@@ -824,8 +685,6 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[section:interruption_enabled Non-member function `interruption_enabled()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
bool interruption_enabled();
|
||||
@@ -843,20 +702,15 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[section:sleep Non-member function `sleep()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template<typename TimeDuration>
|
||||
void sleep(TimeDuration const& rel_time);
|
||||
void sleep(system_time const& abs_time)
|
||||
}
|
||||
|
||||
[variablelist
|
||||
|
||||
[[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.]]
|
||||
[[Effects:] [Suspends the current thread until the specified time has elapsed.]]
|
||||
|
||||
[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
|
||||
|
||||
@@ -868,8 +722,6 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
|
||||
[section:yield Non-member function `yield()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void yield();
|
||||
@@ -887,8 +739,6 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
|
||||
[section:disable_interruption Class `disable_interruption`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
class disable_interruption
|
||||
@@ -940,8 +790,6 @@ interruption state on destruction. Instances of `disable_interruption` cannot be
|
||||
|
||||
[section:restore_interruption Class `restore_interruption`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
class restore_interruption
|
||||
@@ -996,29 +844,18 @@ is destroyed, interruption is again disabled. Instances of `restore_interruption
|
||||
|
||||
[section:atthreadexit Non-member function template `at_thread_exit()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
template<typename Callable>
|
||||
void at_thread_exit(Callable func);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [A copy of `func` is placed in
|
||||
thread-specific storage. This copy is invoked when the current thread
|
||||
exits (even if the thread has been interrupted).]]
|
||||
[[Effects:] [A copy of `func` is taken and stored to in thread-specific storage. This copy is invoked when the current thread exits.]]
|
||||
|
||||
[[Postconditions:] [A copy of `func` has been saved for invocation on thread exit.]]
|
||||
|
||||
[[Throws:] [`std::bad_alloc` if memory cannot be allocated for the copy of the function, __thread_resource_error__ if any other
|
||||
error occurs within the thread library. Any exception thrown whilst copying `func` into internal storage.]]
|
||||
|
||||
[[Note:] [This function is *not* called if the thread was terminated
|
||||
forcefully using platform-specific APIs, or if the thread is
|
||||
terminated due to a call to `exit()`, `abort()` or
|
||||
`std::terminate()`. In particular, returning from `main()` is
|
||||
equivalent to call to `exit()`, so will not call any functions
|
||||
registered with `at_thread_exit()`]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -1027,8 +864,6 @@ registered with `at_thread_exit()`]]
|
||||
|
||||
[section:threadgroup Class `thread_group`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
class thread_group:
|
||||
private noncopyable
|
||||
{
|
||||
@@ -1036,8 +871,7 @@ registered with `at_thread_exit()`]]
|
||||
thread_group();
|
||||
~thread_group();
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc);
|
||||
thread* create_thread(const function0<void>& threadfunc);
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
void join_all();
|
||||
@@ -1074,8 +908,7 @@ registered with `at_thread_exit()`]]
|
||||
|
||||
[section:create_thread Member function `create_thread()`]
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc);
|
||||
thread* create_thread(const function0<void>& threadfunc);
|
||||
|
||||
[variablelist
|
||||
|
||||
|
||||
11
doc/time.qbk
11
doc/time.qbk
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:time Date and Time Requirements]
|
||||
|
||||
As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a
|
||||
@@ -47,8 +40,6 @@ date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] c
|
||||
|
||||
[section:system_time Typedef `system_time`]
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library.
|
||||
@@ -57,8 +48,6 @@ See the documentation for [link date_time.posix_time.ptime_class `boost::posix_t
|
||||
|
||||
[section:get_system_time Non-member function `get_system_time()`]
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
system_time get_system_time();
|
||||
|
||||
[variablelist
|
||||
|
||||
14
doc/tss.qbk
14
doc/tss.qbk
@@ -1,10 +1,3 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section Thread Local Storage]
|
||||
|
||||
[heading Synopsis]
|
||||
@@ -41,16 +34,9 @@ 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`]
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
|
||||
@@ -50,9 +50,8 @@ boost::mutex io_mutex;
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 1000000) {
|
||||
while (n < 100) {
|
||||
buf.send(n);
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
@@ -66,24 +65,18 @@ void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
buf.send(-1);
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
boost::thread thrd1(&sender);
|
||||
boost::thread thrd2(&receiver);
|
||||
boost::thread thrd3(&receiver);
|
||||
boost::thread thrd4(&receiver);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
thrd3.join();
|
||||
thrd4.join();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ int main(int argc, char* argv[])
|
||||
std::cout << "---Noise ON..." << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000000000; ++i)
|
||||
for (int i = 0; i < 1000000; ++i)
|
||||
cond.notify_all();
|
||||
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// (C) Copyright 2008-9 Anthony Williams
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -21,6 +21,5 @@
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#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>
|
||||
@@ -28,7 +27,7 @@ namespace boost
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
boost::throw_exception(std::invalid_argument("count cannot be zero."));
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
bool wait()
|
||||
|
||||
@@ -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,15 +10,6 @@
|
||||
#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
|
||||
@@ -28,14 +19,8 @@
|
||||
|
||||
#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_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
|
||||
# undef BOOST_THREAD_USE_LIB
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
#endif
|
||||
@@ -62,18 +47,12 @@
|
||||
|
||||
#if defined(BOOST_HAS_DECLSPEC)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT
|
||||
//# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
|
||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT
|
||||
//# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# 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
|
||||
@@ -84,7 +63,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
|
||||
|
||||
@@ -6,20 +6,13 @@
|
||||
#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>
|
||||
@@ -44,21 +37,18 @@ namespace boost
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename 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 boost::detail::thread_move_t<T>(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t)
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, detail::thread_move_t<T> >::type move(T& t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
# define BOOST_THREAD_HPUX
|
||||
#elif defined(__CYGWIN__)
|
||||
# define BOOST_THREAD_CYGWIN
|
||||
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
|
||||
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
# define BOOST_THREAD_WIN32
|
||||
#elif defined(__BEOS__)
|
||||
# define BOOST_THREAD_BEOS
|
||||
@@ -42,9 +42,9 @@
|
||||
#elif defined(__QNXNTO__)
|
||||
# define BOOST_THREAD_QNXNTO
|
||||
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_POSIX
|
||||
# endif
|
||||
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For every supported platform add a new entry into the dispatch table below.
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
// 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-10 Anthony Williams
|
||||
|
||||
// (C) Copyright 2007-8 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>
|
||||
@@ -24,7 +22,6 @@
|
||||
#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>
|
||||
|
||||
@@ -42,13 +39,10 @@ namespace boost
|
||||
public detail::thread_data_base
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
thread_data(F&& f_):
|
||||
f(static_cast<F&&>(f_))
|
||||
{}
|
||||
thread_data(F& f_):
|
||||
f(f_)
|
||||
{}
|
||||
#else
|
||||
thread_data(F f_):
|
||||
f(f_)
|
||||
@@ -56,7 +50,7 @@ namespace boost
|
||||
thread_data(detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
#endif
|
||||
#endif
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
@@ -81,7 +75,7 @@ namespace boost
|
||||
thread_data(boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
@@ -100,14 +94,14 @@ namespace boost
|
||||
thread_data(const boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class BOOST_THREAD_DECL thread
|
||||
{
|
||||
private:
|
||||
@@ -115,16 +109,17 @@ 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 BOOST_PREVENT_MACRO_SUBSTITUTION () const;
|
||||
detail::thread_data_ptr get_thread_info() const;
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F&& f)
|
||||
{
|
||||
@@ -132,7 +127,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(*)()> >(static_cast<void(*&&)()>(f)));
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(f));
|
||||
}
|
||||
#else
|
||||
template<typename F>
|
||||
@@ -146,37 +141,25 @@ namespace boost
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
|
||||
}
|
||||
|
||||
#endif
|
||||
struct dummy;
|
||||
public:
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
thread(const volatile thread&);
|
||||
#endif
|
||||
public:
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
#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
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
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;
|
||||
@@ -188,15 +171,7 @@ namespace boost
|
||||
{
|
||||
return static_cast<thread&&>(*this);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef BOOST_NO_SFINAE
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
#else
|
||||
template <class F>
|
||||
explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
|
||||
@@ -204,10 +179,9 @@ namespace boost
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template <class F>
|
||||
explicit thread(detail::thread_move_t<F> f):
|
||||
thread(detail::thread_move_t<F> f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
@@ -218,26 +192,19 @@ namespace boost
|
||||
thread_info=x->thread_info;
|
||||
x->thread_info.reset();
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
thread& operator=(thread x)
|
||||
{
|
||||
swap(x);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
|
||||
thread& operator=(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread new_thread(x);
|
||||
swap(new_thread);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
operator detail::thread_move_t<thread>()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
|
||||
detail::thread_move_t<thread> move()
|
||||
{
|
||||
detail::thread_move_t<thread> x(*this);
|
||||
@@ -313,7 +280,7 @@ namespace boost
|
||||
thread_info.swap(x.thread_info);
|
||||
}
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE id;
|
||||
class id;
|
||||
id get_id() const;
|
||||
|
||||
|
||||
@@ -341,7 +308,7 @@ namespace boost
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
|
||||
|
||||
static inline void sleep(const system_time& xt)
|
||||
{
|
||||
this_thread::sleep(xt);
|
||||
@@ -356,15 +323,11 @@ namespace boost
|
||||
{
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
inline thread&& move(thread& t)
|
||||
{
|
||||
return static_cast<thread&&>(t);
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
inline thread&& move(thread&& t)
|
||||
{
|
||||
return static_cast<thread&&>(t);
|
||||
return t;
|
||||
}
|
||||
#else
|
||||
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> t)
|
||||
@@ -375,159 +338,137 @@ namespace boost
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
class BOOST_THREAD_DECL disable_interruption
|
||||
{
|
||||
disable_interruption(const disable_interruption&);
|
||||
disable_interruption& operator=(const disable_interruption&);
|
||||
|
||||
bool interruption_was_enabled;
|
||||
friend class restore_interruption;
|
||||
public:
|
||||
disable_interruption();
|
||||
~disable_interruption();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL restore_interruption
|
||||
{
|
||||
restore_interruption(const restore_interruption&);
|
||||
restore_interruption& operator=(const restore_interruption&);
|
||||
public:
|
||||
explicit restore_interruption(disable_interruption& d);
|
||||
~restore_interruption();
|
||||
};
|
||||
|
||||
thread::id BOOST_THREAD_DECL get_id();
|
||||
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
bool BOOST_THREAD_DECL interruption_enabled();
|
||||
bool BOOST_THREAD_DECL interruption_requested();
|
||||
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
|
||||
inline void sleep(xtime const& abs_time)
|
||||
{
|
||||
sleep(system_time(abs_time));
|
||||
}
|
||||
}
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread::id
|
||||
class 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 BOOST_THREAD_DECL this_thread::get_id();
|
||||
friend id 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 BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
|
||||
{
|
||||
if(x.thread_data)
|
||||
{
|
||||
io::ios_flags_saver ifs( os );
|
||||
return os<< std::hex << x.thread_data;
|
||||
return os<<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()()=0;
|
||||
virtual void operator()() const=0;
|
||||
};
|
||||
|
||||
|
||||
template<typename F>
|
||||
struct thread_exit_function:
|
||||
thread_exit_function_base
|
||||
{
|
||||
F f;
|
||||
|
||||
|
||||
thread_exit_function(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
|
||||
|
||||
void 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>
|
||||
@@ -537,6 +478,83 @@ namespace boost
|
||||
detail::add_thread_exit_function(thread_exit_func);
|
||||
}
|
||||
}
|
||||
|
||||
class thread_group:
|
||||
private noncopyable
|
||||
{
|
||||
public:
|
||||
~thread_group()
|
||||
{
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
std::auto_ptr<thread> new_thread(new thread(threadfunc));
|
||||
threads.push_back(new_thread.get());
|
||||
return new_thread.release();
|
||||
}
|
||||
|
||||
void add_thread(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
threads.push_back(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_thread(thread* thrd)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
|
||||
if(it!=threads.end())
|
||||
{
|
||||
threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void join_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<thread*> threads;
|
||||
mutable mutex m;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
|
||||
#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-9 Anthony Williams
|
||||
|
||||
#include <list>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4251)
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
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();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
std::auto_ptr<thread> new_thread(new thread(threadfunc));
|
||||
threads.push_back(new_thread.get());
|
||||
return new_thread.release();
|
||||
}
|
||||
|
||||
void add_thread(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
threads.push_back(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_thread(thread* thrd)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
|
||||
if(it!=threads.end())
|
||||
{
|
||||
threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void join_all()
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_all()
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<thread*> threads;
|
||||
mutable shared_mutex m;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
|
||||
#define BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-9 Anthony Williams
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace this_thread
|
||||
{
|
||||
class BOOST_THREAD_DECL disable_interruption
|
||||
{
|
||||
disable_interruption(const disable_interruption&);
|
||||
disable_interruption& operator=(const disable_interruption&);
|
||||
|
||||
bool interruption_was_enabled;
|
||||
friend class restore_interruption;
|
||||
public:
|
||||
disable_interruption();
|
||||
~disable_interruption();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL restore_interruption
|
||||
{
|
||||
restore_interruption(const restore_interruption&);
|
||||
restore_interruption& operator=(const restore_interruption&);
|
||||
public:
|
||||
explicit restore_interruption(disable_interruption& d);
|
||||
~restore_interruption();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -12,9 +12,27 @@
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
BOOST_THREAD_DECL void __cdecl on_process_enter(void);
|
||||
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);
|
||||
//Function to be called when the exe or dll
|
||||
//that uses Boost.Threads first starts
|
||||
//or is first loaded.
|
||||
@@ -24,7 +42,7 @@ namespace boost
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_process_exit(void);
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
|
||||
//Function to be called when the exe or dll
|
||||
//that uses Boost.Threads first starts
|
||||
//or is first loaded.
|
||||
@@ -34,7 +52,7 @@ namespace boost
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_thread_enter(void);
|
||||
extern "C" BOOST_THREAD_DECL void 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
|
||||
@@ -43,7 +61,7 @@ namespace boost
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
|
||||
extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
|
||||
//Function to be called just be fore a thread ends
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
@@ -52,11 +70,10 @@ namespace boost
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
void tss_cleanup_implemented();
|
||||
extern "C" void tss_cleanup_implemented(void);
|
||||
//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)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-9 Anthony Williams
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -24,38 +24,25 @@
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_interrupted
|
||||
class BOOST_THREAD_DECL thread_interrupted
|
||||
{};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_exception:
|
||||
public std::exception
|
||||
{
|
||||
protected:
|
||||
thread_exception():
|
||||
m_sys_err(0)
|
||||
{}
|
||||
|
||||
thread_exception(int sys_err_code):
|
||||
m_sys_err(sys_err_code)
|
||||
{}
|
||||
|
||||
class BOOST_THREAD_DECL thread_exception : public std::exception
|
||||
{
|
||||
protected:
|
||||
thread_exception();
|
||||
thread_exception(int sys_err_code);
|
||||
|
||||
public:
|
||||
~thread_exception() throw()
|
||||
{}
|
||||
|
||||
public:
|
||||
~thread_exception() throw();
|
||||
|
||||
int native_error() const
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
int native_error() const;
|
||||
|
||||
private:
|
||||
int m_sys_err;
|
||||
};
|
||||
private:
|
||||
int m_sys_err;
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE condition_error:
|
||||
class condition_error:
|
||||
public std::exception
|
||||
{
|
||||
public:
|
||||
@@ -66,117 +53,62 @@ namespace boost
|
||||
};
|
||||
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE lock_error:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
lock_error()
|
||||
{}
|
||||
|
||||
lock_error(int sys_err_code):
|
||||
thread_exception(sys_err_code)
|
||||
{}
|
||||
|
||||
~lock_error() throw()
|
||||
{}
|
||||
|
||||
class BOOST_THREAD_DECL lock_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
lock_error();
|
||||
lock_error(int sys_err_code);
|
||||
~lock_error() throw();
|
||||
|
||||
virtual const char* what() const throw()
|
||||
{
|
||||
return "boost::lock_error";
|
||||
}
|
||||
};
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_resource_error:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
thread_resource_error()
|
||||
{}
|
||||
|
||||
thread_resource_error(int sys_err_code):
|
||||
thread_exception(sys_err_code)
|
||||
{}
|
||||
|
||||
~thread_resource_error() throw()
|
||||
{}
|
||||
|
||||
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
thread_resource_error();
|
||||
thread_resource_error(int sys_err_code);
|
||||
~thread_resource_error() throw();
|
||||
|
||||
virtual const char* what() const throw()
|
||||
{
|
||||
return "boost::thread_resource_error";
|
||||
}
|
||||
|
||||
};
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE unsupported_thread_option:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
unsupported_thread_option()
|
||||
{}
|
||||
|
||||
unsupported_thread_option(int sys_err_code):
|
||||
thread_exception(sys_err_code)
|
||||
{}
|
||||
|
||||
~unsupported_thread_option() throw()
|
||||
{}
|
||||
|
||||
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
|
||||
{
|
||||
public:
|
||||
unsupported_thread_option();
|
||||
unsupported_thread_option(int sys_err_code);
|
||||
~unsupported_thread_option() throw();
|
||||
|
||||
virtual const char* what() const throw()
|
||||
{
|
||||
return "boost::unsupported_thread_option";
|
||||
}
|
||||
|
||||
};
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE invalid_thread_argument:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
invalid_thread_argument()
|
||||
{}
|
||||
|
||||
invalid_thread_argument(int sys_err_code):
|
||||
thread_exception(sys_err_code)
|
||||
{}
|
||||
|
||||
~invalid_thread_argument() throw()
|
||||
{}
|
||||
|
||||
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
|
||||
{
|
||||
public:
|
||||
invalid_thread_argument();
|
||||
invalid_thread_argument(int sys_err_code);
|
||||
~invalid_thread_argument() throw();
|
||||
|
||||
virtual const char* what() const throw()
|
||||
{
|
||||
return "boost::invalid_thread_argument";
|
||||
}
|
||||
|
||||
};
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_permission_error:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
thread_permission_error()
|
||||
{}
|
||||
|
||||
thread_permission_error(int sys_err_code):
|
||||
thread_exception(sys_err_code)
|
||||
{}
|
||||
|
||||
~thread_permission_error() throw()
|
||||
{}
|
||||
|
||||
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
thread_permission_error();
|
||||
thread_permission_error(int sys_err_code);
|
||||
~thread_permission_error() throw();
|
||||
|
||||
virtual const char* what() const throw()
|
||||
{
|
||||
return "boost::thread_permission_error";
|
||||
}
|
||||
|
||||
};
|
||||
virtual const char* what() const throw();
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#endif // BOOST_THREAD_CONFIG_PDM070801_H
|
||||
|
||||
// Change log:
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,107 +3,53 @@
|
||||
// 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-10 Anthony Williams
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#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 "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include "thread_data.hpp"
|
||||
#include "condition_variable_fwd.hpp"
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
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)
|
||||
{
|
||||
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());
|
||||
}
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
|
||||
}
|
||||
|
||||
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
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();
|
||||
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);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(cond_res)
|
||||
{
|
||||
boost::throw_exception(condition_error());
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
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_any&);
|
||||
condition_variable_any& operator=(condition_variable_any&);
|
||||
condition_variable_any(condition_variable&);
|
||||
condition_variable_any& operator=(condition_variable&);
|
||||
|
||||
public:
|
||||
condition_variable_any()
|
||||
@@ -111,13 +57,13 @@ namespace boost
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw 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());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
@@ -125,21 +71,23 @@ 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;
|
||||
{
|
||||
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);
|
||||
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();
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error());
|
||||
throw condition_error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,40 +96,31 @@ 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;
|
||||
{
|
||||
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);
|
||||
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();
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error());
|
||||
throw condition_error();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
@@ -211,7 +150,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);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// (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>
|
||||
@@ -20,35 +19,23 @@ 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_mutex_init(&internal_mutex,NULL);
|
||||
int const res=pthread_cond_init(&cond,NULL);
|
||||
if(res)
|
||||
{
|
||||
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());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
int ret;
|
||||
do {
|
||||
ret = pthread_cond_destroy(&cond);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& m);
|
||||
@@ -59,18 +46,7 @@ namespace boost
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
template<typename duration_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration);
|
||||
}
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until);
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
|
||||
@@ -7,18 +7,16 @@
|
||||
|
||||
#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 <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
@@ -27,11 +25,10 @@
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class mutex
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
mutex(mutex const&);
|
||||
mutex& operator=(mutex const&);
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
mutex()
|
||||
@@ -39,53 +36,28 @@ namespace boost
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_destroy(&m);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
}
|
||||
|
||||
|
||||
void lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_lock(&m);
|
||||
} while (res == EINTR);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res));
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_unlock(&m);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_trylock(&m);
|
||||
} while (res == EINTR);
|
||||
if(res && (res!=EBUSY))
|
||||
{
|
||||
boost::throw_exception(lock_error(res));
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
@@ -101,11 +73,9 @@ namespace boost
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
timed_mutex(timed_mutex const&);
|
||||
timed_mutex& operator=(timed_mutex const&);
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
@@ -118,14 +88,14 @@ namespace boost
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
#endif
|
||||
@@ -143,10 +113,6 @@ namespace boost
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
bool timed_lock(boost::xtime const & absolute_time)
|
||||
{
|
||||
return timed_lock(system_time(absolute_time));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
@@ -158,7 +124,7 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
@@ -196,7 +162,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);
|
||||
|
||||
@@ -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,13 +58,10 @@ 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(...)
|
||||
{
|
||||
@@ -72,7 +69,6 @@ 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));
|
||||
}
|
||||
|
||||
@@ -18,25 +18,15 @@ 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_),locked(true)
|
||||
m(m_)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
locked=false;
|
||||
}
|
||||
|
||||
~pthread_mutex_scoped_lock()
|
||||
{
|
||||
if(locked)
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#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>
|
||||
@@ -17,8 +16,8 @@
|
||||
#endif
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <errno.h>
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
@@ -26,76 +25,43 @@
|
||||
#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
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
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)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw 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));
|
||||
@@ -105,77 +71,32 @@ 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
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
recursive_timed_mutex(recursive_timed_mutex const&);
|
||||
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
@@ -184,38 +105,38 @@ namespace boost
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw 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());
|
||||
throw 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());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
count=0;
|
||||
@@ -224,7 +145,7 @@ namespace boost
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
@@ -235,7 +156,7 @@ namespace boost
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
@@ -245,7 +166,7 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
@@ -256,7 +177,7 @@ namespace boost
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
@@ -275,7 +196,7 @@ namespace boost
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
@@ -294,7 +215,7 @@ namespace boost
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -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()
|
||||
@@ -57,19 +57,19 @@ namespace boost
|
||||
void lock_shared()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
shared_cond.wait(lock);
|
||||
}
|
||||
++state.shared_count;
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
return false;
|
||||
@@ -84,11 +84,11 @@ namespace boost
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -105,9 +105,9 @@ namespace boost
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(state.upgrade)
|
||||
@@ -127,12 +127,12 @@ namespace boost
|
||||
void lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
exclusive_cond.wait(lk);
|
||||
exclusive_cond.wait(lock);
|
||||
}
|
||||
state.exclusive=true;
|
||||
}
|
||||
@@ -140,17 +140,17 @@ namespace boost
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
if(!exclusive_cond.timed_wait(lk,timeout))
|
||||
if(!exclusive_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
exclusive_cond.notify_one();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -168,8 +168,8 @@ namespace boost
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
return false;
|
||||
@@ -179,12 +179,12 @@ namespace boost
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
@@ -193,10 +193,10 @@ namespace boost
|
||||
void lock_upgrade()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
shared_cond.wait(lock);
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
@@ -205,10 +205,10 @@ namespace boost
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
@@ -225,12 +225,12 @@ namespace boost
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_upgrade(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_upgrade(get_system_time()+relative_time);
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
@@ -245,10 +245,10 @@ namespace boost
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
@@ -259,11 +259,11 @@ namespace boost
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
--state.shared_count;
|
||||
while(state.shared_count)
|
||||
{
|
||||
upgrade_cond.wait(lk);
|
||||
upgrade_cond.wait(lock);
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
@@ -271,26 +271,26 @@ namespace boost
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
|
||||
@@ -12,34 +12,22 @@
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
#include <map>
|
||||
#include "condition_variable_fwd.hpp"
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread;
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function;
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node
|
||||
{
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
|
||||
tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
|
||||
void* value_):
|
||||
func(func_),value(value_)
|
||||
{}
|
||||
};
|
||||
struct tss_data_node;
|
||||
|
||||
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>
|
||||
{
|
||||
@@ -53,15 +41,14 @@ namespace boost
|
||||
bool join_started;
|
||||
bool joined;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
std::map<void const*,boost::detail::tss_data_node> tss_data;
|
||||
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():
|
||||
done(false),join_started(false),joined(false),
|
||||
thread_exit_callbacks(0),
|
||||
thread_exit_callbacks(0),tss_data(0),
|
||||
interrupt_enabled(true),
|
||||
interrupt_requested(false),
|
||||
current_cond(0)
|
||||
@@ -78,8 +65,6 @@ namespace boost
|
||||
class interruption_checker
|
||||
{
|
||||
thread_data_base* const thread_info;
|
||||
pthread_mutex_t* m;
|
||||
bool set;
|
||||
|
||||
void check_for_interruption()
|
||||
{
|
||||
@@ -89,38 +74,26 @@ namespace boost
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator=(interruption_checker&);
|
||||
public:
|
||||
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)
|
||||
explicit interruption_checker(pthread_cond_t* cond):
|
||||
thread_info(detail::get_current_thread_data())
|
||||
{
|
||||
if(set)
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
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(set)
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
thread_info->cond_mutex=NULL;
|
||||
thread_info->current_cond=NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
check_for_interruption();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -129,26 +102,14 @@ namespace boost
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL yield();
|
||||
|
||||
#ifdef __DECXXX
|
||||
/// Workaround of DECCXX issue of incorrect template substitution
|
||||
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace boost
|
||||
return new T();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#include <boost/thread/detail/thread_group.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// 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>
|
||||
|
||||
@@ -18,11 +17,7 @@ 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
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
|
||||
@@ -62,8 +61,6 @@ 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>())
|
||||
{}
|
||||
@@ -76,7 +73,7 @@ namespace boost
|
||||
}
|
||||
~thread_specific_ptr()
|
||||
{
|
||||
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,true);
|
||||
reset();
|
||||
}
|
||||
|
||||
T* get() const
|
||||
|
||||
@@ -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 <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/basic_timed_mutex.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "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();
|
||||
@@ -64,6 +64,11 @@ namespace boost
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
long get_active_count()
|
||||
{
|
||||
return mutex.get_active_count();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if(!--recursion_count)
|
||||
@@ -73,6 +78,11 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return mutex.locked();
|
||||
}
|
||||
|
||||
private:
|
||||
bool try_recursive_lock(long current_thread_id)
|
||||
{
|
||||
@@ -83,7 +93,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool try_basic_lock(long current_thread_id)
|
||||
{
|
||||
if(mutex.try_lock())
|
||||
@@ -94,7 +104,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 +115,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
|
||||
|
||||
@@ -3,17 +3,16 @@
|
||||
|
||||
// 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 <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
@@ -52,39 +51,24 @@ namespace boost
|
||||
win32::CloseHandle(old_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
|
||||
}
|
||||
|
||||
|
||||
void lock()
|
||||
{
|
||||
if(try_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))
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
@@ -95,33 +79,6 @@ 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)
|
||||
{
|
||||
@@ -135,7 +92,18 @@ namespace boost
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
clear_waiting_and_try_lock(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;
|
||||
}
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
@@ -149,9 +117,9 @@ namespace boost
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
bool timed_lock(boost::xtime const& timeout)
|
||||
long get_active_count()
|
||||
{
|
||||
return timed_lock(system_time(timeout));
|
||||
return ::boost::detail::interlocked_read_acquire(&active_count);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
@@ -167,11 +135,16 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return get_active_count()>=lock_flag_value;
|
||||
}
|
||||
|
||||
private:
|
||||
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);
|
||||
@@ -196,9 +169,9 @@ namespace boost
|
||||
}
|
||||
return current_event;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
#include "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)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/win32/basic_timed_mutex.hpp>
|
||||
#include "basic_timed_mutex.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
@@ -20,11 +20,9 @@ namespace boost
|
||||
}
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::underlying_mutex
|
||||
{
|
||||
private:
|
||||
mutex(mutex const&);
|
||||
mutex& operator=(mutex const&);
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
@@ -42,11 +40,9 @@ 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()
|
||||
{
|
||||
|
||||
@@ -30,90 +30,81 @@ namespace std
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct once_flag
|
||||
{
|
||||
long status;
|
||||
long count;
|
||||
};
|
||||
typedef long once_flag;
|
||||
|
||||
#define BOOST_ONCE_INIT {0,0}
|
||||
#define BOOST_ONCE_INIT 0
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#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;
|
||||
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
|
||||
template <class I>
|
||||
void int_to_string(I p, once_char_type* buf)
|
||||
void int_to_string(I p, wchar_t* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
once_char_type const a=L'A';
|
||||
#else
|
||||
once_char_type const a='A';
|
||||
#endif
|
||||
*buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
|
||||
*buf = L'A' + static_cast<wchar_t>((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";
|
||||
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
|
||||
BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
|
||||
(sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
|
||||
|
||||
// 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";
|
||||
#else
|
||||
typedef char char_type;
|
||||
static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#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];
|
||||
|
||||
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_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(
|
||||
|
||||
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);
|
||||
#else
|
||||
return ::boost::detail::win32::OpenEventA(
|
||||
return win32::CreateMutexA(0, 0, mutex_name);
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -123,79 +114,19 @@ 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;
|
||||
|
||||
while((status=::boost::detail::interlocked_read_acquire(&flag.status))
|
||||
!=function_complete_flag_value)
|
||||
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
|
||||
{
|
||||
status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0);
|
||||
if(!status)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
f();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <boost/thread/win32/basic_recursive_mutex.hpp>
|
||||
#include "basic_recursive_mutex.hpp"
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
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()
|
||||
{
|
||||
@@ -42,11 +40,9 @@ 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()
|
||||
{
|
||||
|
||||
@@ -19,11 +19,9 @@
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
class shared_mutex:
|
||||
private boost::noncopyable
|
||||
{
|
||||
private:
|
||||
shared_mutex(shared_mutex const&);
|
||||
shared_mutex& operator=(shared_mutex const&);
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
@@ -39,7 +37,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)
|
||||
@@ -51,47 +49,34 @@ 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(semaphores[exclusive_sem],1,0)!=0);
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
|
||||
}
|
||||
|
||||
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex()
|
||||
shared_mutex():
|
||||
unlock_sem(semaphores[0]),
|
||||
exclusive_sem(semaphores[1])
|
||||
{
|
||||
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());
|
||||
}
|
||||
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);
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
@@ -99,25 +84,21 @@ namespace boost
|
||||
~shared_mutex()
|
||||
{
|
||||
detail::win32::CloseHandle(upgrade_sem);
|
||||
detail::win32::CloseHandle(semaphores[unlock_sem]);
|
||||
detail::win32::CloseHandle(semaphores[exclusive_sem]);
|
||||
detail::win32::CloseHandle(unlock_sem);
|
||||
detail::win32::CloseHandle(exclusive_sem);
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
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)
|
||||
{
|
||||
@@ -125,6 +106,14 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
@@ -141,27 +130,26 @@ namespace boost
|
||||
|
||||
bool timed_lock_shared(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true)
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
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);
|
||||
@@ -171,16 +159,24 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
@@ -193,10 +189,6 @@ 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);
|
||||
@@ -206,6 +198,14 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
@@ -213,7 +213,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
@@ -221,11 +221,11 @@ namespace boost
|
||||
void unlock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.upgrade)
|
||||
@@ -243,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)
|
||||
{
|
||||
@@ -262,6 +262,14 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
void lock()
|
||||
@@ -275,49 +283,25 @@ namespace boost
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true)
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
{
|
||||
state_data old_state=state;
|
||||
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
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
|
||||
@@ -332,20 +316,23 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#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));
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
@@ -370,6 +357,14 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
@@ -383,7 +378,7 @@ namespace boost
|
||||
void unlock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
@@ -401,32 +396,39 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
for(;;)
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true)
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -437,55 +439,33 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
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)
|
||||
@@ -495,7 +475,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)
|
||||
{
|
||||
@@ -507,22 +487,30 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -534,12 +522,20 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
@@ -559,13 +555,21 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
@@ -584,13 +588,21 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
@@ -608,9 +620,17 @@ namespace boost
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
while(true);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/thread_heap_alloc.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "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 BOOST_SYMBOL_VISIBLE thread_data_base
|
||||
|
||||
struct 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 BOOST_SYMBOL_VISIBLE timeout
|
||||
struct timeout
|
||||
{
|
||||
unsigned long start;
|
||||
uintmax_t milliseconds;
|
||||
@@ -92,7 +92,7 @@ namespace boost
|
||||
abs_time(abs_time_)
|
||||
{}
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE remaining_time
|
||||
struct remaining_time
|
||||
{
|
||||
bool more;
|
||||
unsigned long milliseconds;
|
||||
@@ -130,7 +130,7 @@ namespace boost
|
||||
{
|
||||
return milliseconds==~uintmax_t(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static timeout sentinel()
|
||||
{
|
||||
@@ -139,16 +139,11 @@ 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
|
||||
@@ -156,26 +151,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(uintmax_t milliseconds)
|
||||
inline void interruptible_wait(unsigned long milliseconds)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
|
||||
}
|
||||
inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time)
|
||||
inline void interruptible_wait(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
|
||||
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
|
||||
}
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
|
||||
inline void sleep(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(abs_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
#ifndef THREAD_HEAP_ALLOC_HPP
|
||||
#define THREAD_HEAP_ALLOC_HPP
|
||||
#include <new>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <stdexcept>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
@@ -56,21 +55,21 @@ namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline void* allocate_raw_heap_memory(unsigned size)
|
||||
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
|
||||
{
|
||||
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
|
||||
if(!heap_memory)
|
||||
{
|
||||
boost::throw_exception(std::bad_alloc());
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return heap_memory;
|
||||
}
|
||||
|
||||
inline void free_raw_heap_memory(void* heap_memory)
|
||||
inline BOOST_THREAD_DECL 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()
|
||||
{
|
||||
@@ -87,7 +86,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
@@ -226,7 +225,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)
|
||||
{
|
||||
@@ -372,8 +371,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)
|
||||
{
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
|
||||
// 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>
|
||||
@@ -31,18 +30,14 @@ 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;
|
||||
@@ -69,7 +64,7 @@ namespace boost
|
||||
# ifdef UNDER_CE
|
||||
# ifndef WINAPI
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# define WINAPI __cdecl // Note this doesn't match the desktop definition
|
||||
# define WINAPI __cdecl // Note this doesn't match the desktop definition
|
||||
# else
|
||||
# define WINAPI __stdcall
|
||||
# endif
|
||||
@@ -94,7 +89,7 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
@@ -104,8 +99,6 @@ 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"
|
||||
{
|
||||
@@ -114,12 +107,10 @@ 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*);
|
||||
@@ -170,49 +161,40 @@ 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)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw 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)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw 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)
|
||||
{
|
||||
@@ -222,7 +204,7 @@ namespace boost
|
||||
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
|
||||
if(!success)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return new_handle;
|
||||
}
|
||||
@@ -246,7 +228,7 @@ namespace boost
|
||||
BOOST_VERIFY(CloseHandle(handle_to_manage));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
explicit handle_manager(handle handle_to_manage_):
|
||||
handle_to_manage(handle_to_manage_)
|
||||
@@ -254,7 +236,7 @@ namespace boost
|
||||
handle_manager():
|
||||
handle_to_manage(0)
|
||||
{}
|
||||
|
||||
|
||||
handle_manager& operator=(handle new_handle)
|
||||
{
|
||||
cleanup();
|
||||
@@ -288,18 +270,28 @@ namespace boost
|
||||
{
|
||||
return !handle_to_manage;
|
||||
}
|
||||
|
||||
|
||||
~handle_manager()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
|
||||
#if _MSC_VER==1400
|
||||
extern "C" unsigned char _interlockedbittestandset(long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
|
||||
#else
|
||||
extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_interlockedbittestandset)
|
||||
#pragma intrinsic(_interlockedbittestandreset)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -307,17 +299,6 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
#if _MSC_VER==1400
|
||||
extern "C" unsigned char _interlockedbittestandset(long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
|
||||
#else
|
||||
extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_interlockedbittestandset)
|
||||
#pragma intrinsic(_interlockedbittestandreset)
|
||||
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
return _interlockedbittestandset(x,bit)!=0;
|
||||
@@ -327,7 +308,7 @@ namespace boost
|
||||
{
|
||||
return _interlockedbittestandreset(x,bit)!=0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,7 +327,7 @@ namespace boost
|
||||
mov edx,x;
|
||||
lock bts [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
@@ -356,9 +337,9 @@ namespace boost
|
||||
mov edx,x;
|
||||
lock btr [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
124
src/pthread/exceptions.cpp
Normal file
124
src/pthread/exceptions.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// 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/thread/exceptions.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
|
||||
thread_exception::thread_exception()
|
||||
: m_sys_err(0)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::thread_exception(int sys_err_code)
|
||||
: m_sys_err(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::~thread_exception() throw()
|
||||
{
|
||||
}
|
||||
|
||||
int thread_exception::native_error() const
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
lock_error::lock_error()
|
||||
{
|
||||
}
|
||||
|
||||
lock_error::lock_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
lock_error::~lock_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* lock_error::what() const throw()
|
||||
{
|
||||
return "boost::lock_error";
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error()
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::~thread_resource_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* thread_resource_error::what() const throw()
|
||||
{
|
||||
return "boost::thread_resource_error";
|
||||
}
|
||||
|
||||
unsupported_thread_option::unsupported_thread_option()
|
||||
{
|
||||
}
|
||||
|
||||
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
unsupported_thread_option::~unsupported_thread_option() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* unsupported_thread_option::what() const throw()
|
||||
{
|
||||
return "boost::unsupported_thread_option";
|
||||
}
|
||||
|
||||
invalid_thread_argument::invalid_thread_argument()
|
||||
{
|
||||
}
|
||||
|
||||
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
invalid_thread_argument::~invalid_thread_argument() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* invalid_thread_argument::what() const throw()
|
||||
{
|
||||
return "boost::invalid_thread_argument";
|
||||
}
|
||||
|
||||
thread_permission_error::thread_permission_error()
|
||||
{
|
||||
}
|
||||
|
||||
thread_permission_error::thread_permission_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_permission_error::~thread_permission_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* thread_permission_error::what() const throw()
|
||||
{
|
||||
return "boost::thread_permission_error";
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
@@ -22,18 +22,16 @@ namespace boost
|
||||
pthread_key_t epoch_tss_key;
|
||||
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
|
||||
|
||||
extern "C"
|
||||
extern "C" void delete_epoch_tss_data(void* data)
|
||||
{
|
||||
static void delete_epoch_tss_data(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void create_epoch_tss_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
extern "C" 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()
|
||||
|
||||
@@ -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,13 +13,12 @@
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#ifdef __GLIBC__
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined BOOST_HAS_UNISTD_H
|
||||
#elif defined(__sun) || defined(__CYGWIN__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@@ -43,6 +42,19 @@ namespace boost
|
||||
{}
|
||||
};
|
||||
|
||||
struct tss_data_node
|
||||
{
|
||||
void const* key;
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
tss_data_node* next;
|
||||
|
||||
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
|
||||
tss_data_node* next_):
|
||||
key(key_),func(func_),value(value_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
@@ -50,12 +62,12 @@ namespace boost
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static void tls_destructor(void* data)
|
||||
void tls_destructor(void* data)
|
||||
{
|
||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||
if(thread_info)
|
||||
{
|
||||
while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
|
||||
while(thread_info->tss_data || thread_info->thread_exit_callbacks)
|
||||
{
|
||||
while(thread_info->thread_exit_callbacks)
|
||||
{
|
||||
@@ -68,32 +80,29 @@ namespace boost
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
for(std::map<void const*,tss_data_node>::iterator next=thread_info->tss_data.begin(),
|
||||
current,
|
||||
end=thread_info->tss_data.end();
|
||||
next!=end;)
|
||||
while(thread_info->tss_data)
|
||||
{
|
||||
current=next;
|
||||
++next;
|
||||
if(current->second.func && (current->second.value!=0))
|
||||
detail::tss_data_node* const current_node=thread_info->tss_data;
|
||||
thread_info->tss_data=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current->second.func)(current->second.value);
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
thread_info->tss_data.erase(current);
|
||||
delete current_node;
|
||||
}
|
||||
}
|
||||
thread_info->self.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(¤t_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);
|
||||
@@ -106,12 +115,12 @@ namespace boost
|
||||
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
static void* thread_proxy(void* param)
|
||||
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();
|
||||
@@ -123,12 +132,10 @@ namespace boost
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
// Removed as it stops the debugger identifying the cause of the exception
|
||||
// Unhandled exceptions still cause the application to terminate
|
||||
// catch(...)
|
||||
// {
|
||||
// std::terminate();
|
||||
// }
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
detail::tls_destructor(thread_info.get());
|
||||
detail::set_current_thread_data(0);
|
||||
@@ -146,7 +153,7 @@ namespace boost
|
||||
{
|
||||
interrupt_enabled=false;
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{}
|
||||
|
||||
@@ -187,7 +194,7 @@ namespace boost
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,18 +203,19 @@ namespace boost
|
||||
detach();
|
||||
}
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
detail::thread_data_ptr thread::get_thread_info() 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 +223,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,7 +244,8 @@ 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();
|
||||
@@ -246,11 +255,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)
|
||||
@@ -261,7 +270,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
@@ -282,7 +291,8 @@ 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();
|
||||
@@ -293,15 +303,18 @@ namespace boost
|
||||
|
||||
bool thread::joinable() const
|
||||
{
|
||||
return (get_thread_info)();
|
||||
return get_thread_info();
|
||||
}
|
||||
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
thread_info.swap(local_thread_info);
|
||||
|
||||
{
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
thread_info.swap(local_thread_info);
|
||||
}
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
@@ -316,15 +329,11 @@ 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);
|
||||
@@ -333,7 +342,7 @@ namespace boost
|
||||
else
|
||||
{
|
||||
xtime const xt=get_xtime(st);
|
||||
|
||||
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
@@ -343,7 +352,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);
|
||||
@@ -379,15 +388,15 @@ namespace boost
|
||||
{
|
||||
#if defined(PTW32_VERSION) || defined(__hpux)
|
||||
return pthread_num_processors_np();
|
||||
#elif defined(__linux__)
|
||||
return get_nprocs();
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
|
||||
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
|
||||
#elif defined(__sun) || defined(__CYGWIN__)
|
||||
int const count=sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (count>0)?count:0;
|
||||
#elif defined(__GLIBC__)
|
||||
return get_nprocs();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
@@ -395,7 +404,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);
|
||||
@@ -408,14 +417,13 @@ 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 +431,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 +445,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 +456,8 @@ namespace boost
|
||||
return pthread_t();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
@@ -472,13 +480,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 +509,7 @@ namespace boost
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
@@ -517,7 +525,7 @@ namespace boost
|
||||
detail::get_current_thread_data()->interrupt_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
@@ -542,11 +550,14 @@ namespace boost
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
std::map<void const*,tss_data_node>::iterator current_node=
|
||||
current_thread_data->tss_data.find(key);
|
||||
if(current_node!=current_thread_data->tss_data.end())
|
||||
detail::tss_data_node* current_node=current_thread_data->tss_data;
|
||||
while(current_node)
|
||||
{
|
||||
return ¤t_node->second;
|
||||
if(current_node->key==key)
|
||||
{
|
||||
return current_node;
|
||||
}
|
||||
current_node=current_node->next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -560,47 +571,106 @@ namespace boost
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void add_new_tss_node(void const* key,
|
||||
boost::shared_ptr<tss_cleanup_function> func,
|
||||
void* tss_data)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
|
||||
}
|
||||
|
||||
void erase_tss_node(void const* key)
|
||||
{
|
||||
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)
|
||||
|
||||
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!=0))
|
||||
if(cleanup_existing && current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
if(func || (tss_data!=0))
|
||||
{
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_tss_node(key);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
add_new_tss_node(key,func,tss_data);
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
|
||||
current_thread_data->tss_data=new_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thread_group::thread_group()
|
||||
// {
|
||||
// }
|
||||
|
||||
// thread_group::~thread_group()
|
||||
// {
|
||||
// // We shouldn't have to scoped_lock here, since referencing this object
|
||||
// // from another thread while we're deleting it in the current thread is
|
||||
// // going to lead to undefined behavior any way.
|
||||
// for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
// it != m_threads.end(); ++it)
|
||||
// {
|
||||
// delete (*it);
|
||||
// }
|
||||
// }
|
||||
|
||||
// thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||
// {
|
||||
// // No scoped_lock required here since the only "shared data" that's
|
||||
// // modified here occurs inside add_thread which does scoped_lock.
|
||||
// std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||
// add_thread(thrd.get());
|
||||
// return thrd.release();
|
||||
// }
|
||||
|
||||
// void thread_group::add_thread(thread* thrd)
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// // For now we'll simply ignore requests to add a thread object multiple
|
||||
// // times. Should we consider this an error and either throw or return an
|
||||
// // error value?
|
||||
// std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
// m_threads.end(), thrd);
|
||||
// BOOST_ASSERT(it == m_threads.end());
|
||||
// if (it == m_threads.end())
|
||||
// m_threads.push_back(thrd);
|
||||
// }
|
||||
|
||||
// void thread_group::remove_thread(thread* thrd)
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// // For now we'll simply ignore requests to remove a thread object that's
|
||||
// // not in the group. Should we consider this an error and either throw or
|
||||
// // return an error value?
|
||||
// std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
// m_threads.end(), thrd);
|
||||
// BOOST_ASSERT(it != m_threads.end());
|
||||
// if (it != m_threads.end())
|
||||
// m_threads.erase(it);
|
||||
// }
|
||||
|
||||
// void thread_group::join_all()
|
||||
// {
|
||||
// mutex::scoped_lock scoped_lock(m_mutex);
|
||||
// for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
// it != m_threads.end(); ++it)
|
||||
// {
|
||||
// (*it)->join();
|
||||
// }
|
||||
// }
|
||||
|
||||
// void thread_group::interrupt_all()
|
||||
// {
|
||||
// boost::lock_guard<mutex> guard(m_mutex);
|
||||
|
||||
// for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
|
||||
// it!=end;
|
||||
// ++it)
|
||||
// {
|
||||
// (*it)->interrupt();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// size_t thread_group::size() const
|
||||
// {
|
||||
// return m_threads.size();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
// 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;
|
||||
@@ -21,7 +18,7 @@ inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
@@ -33,6 +30,7 @@ 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)
|
||||
{
|
||||
@@ -57,7 +55,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);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
@@ -88,7 +86,7 @@ inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
@@ -110,7 +108,7 @@ inline void to_microduration(boost::xtime xt, int& microseconds)
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
assert(res == boost::TIME_UTC);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
|
||||
@@ -8,15 +8,13 @@
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
void tss_cleanup_implemented(void)
|
||||
extern "C" void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
@@ -32,7 +30,5 @@ namespace boost
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)
|
||||
|
||||
124
src/win32/exceptions.cpp
Normal file
124
src/win32/exceptions.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// 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/thread/exceptions.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
|
||||
thread_exception::thread_exception()
|
||||
: m_sys_err(0)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::thread_exception(int sys_err_code)
|
||||
: m_sys_err(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_exception::~thread_exception() throw()
|
||||
{
|
||||
}
|
||||
|
||||
int thread_exception::native_error() const
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
lock_error::lock_error()
|
||||
{
|
||||
}
|
||||
|
||||
lock_error::lock_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
lock_error::~lock_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* lock_error::what() const throw()
|
||||
{
|
||||
return "boost::lock_error";
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error()
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::thread_resource_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_resource_error::~thread_resource_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* thread_resource_error::what() const throw()
|
||||
{
|
||||
return "boost::thread_resource_error";
|
||||
}
|
||||
|
||||
unsupported_thread_option::unsupported_thread_option()
|
||||
{
|
||||
}
|
||||
|
||||
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
unsupported_thread_option::~unsupported_thread_option() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* unsupported_thread_option::what() const throw()
|
||||
{
|
||||
return "boost::unsupported_thread_option";
|
||||
}
|
||||
|
||||
invalid_thread_argument::invalid_thread_argument()
|
||||
{
|
||||
}
|
||||
|
||||
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
invalid_thread_argument::~invalid_thread_argument() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* invalid_thread_argument::what() const throw()
|
||||
{
|
||||
return "boost::invalid_thread_argument";
|
||||
}
|
||||
|
||||
thread_permission_error::thread_permission_error()
|
||||
{
|
||||
}
|
||||
|
||||
thread_permission_error::thread_permission_error(int sys_err_code)
|
||||
: thread_exception(sys_err_code)
|
||||
{
|
||||
}
|
||||
|
||||
thread_permission_error::~thread_permission_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* thread_permission_error::what() const throw()
|
||||
{
|
||||
return "boost::thread_permission_error";
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#ifndef UNDER_CE
|
||||
#include <process.h>
|
||||
#endif
|
||||
@@ -16,11 +17,8 @@
|
||||
#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,44 +29,23 @@ namespace boost
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
current_thread_tls_key=TlsAlloc();
|
||||
#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()
|
||||
{
|
||||
if(current_thread_tls_key)
|
||||
{
|
||||
TlsFree(current_thread_tls_key);
|
||||
current_thread_tls_key=0;
|
||||
}
|
||||
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
if(!current_thread_tls_key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
if(current_thread_tls_key)
|
||||
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
|
||||
else
|
||||
boost::throw_exception(thread_resource_error());
|
||||
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
|
||||
}
|
||||
|
||||
#ifndef BOOST_HAS_THREADEX
|
||||
#ifdef BOOST_NO_THREADEX
|
||||
// Windows CE doesn't define _beginthreadex
|
||||
|
||||
struct ThreadProxyData
|
||||
@@ -81,25 +58,22 @@ namespace boost
|
||||
|
||||
DWORD WINAPI ThreadProxy(LPVOID args)
|
||||
{
|
||||
std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
|
||||
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,
|
||||
data,initflag,&threadID);
|
||||
if (hthread==0) {
|
||||
delete data;
|
||||
return 0;
|
||||
}
|
||||
*thrdaddr=threadID;
|
||||
new ThreadProxyData(start_address,arglist),initflag,&threadID);
|
||||
if (hthread!=0)
|
||||
*thrdaddr=threadID;
|
||||
return reinterpret_cast<uintptr_t const>(hthread);
|
||||
}
|
||||
|
||||
@@ -166,11 +140,11 @@ namespace boost
|
||||
boost::detail::heap_delete(current_node);
|
||||
}
|
||||
}
|
||||
|
||||
set_current_thread_data(0);
|
||||
|
||||
}
|
||||
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));
|
||||
@@ -182,12 +156,10 @@ namespace boost
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
// Removed as it stops the debugger identifying the cause of the exception
|
||||
// Unhandled exceptions still cause the application to terminate
|
||||
// catch(...)
|
||||
// {
|
||||
// std::terminate();
|
||||
// }
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
run_thread_exit_callbacks();
|
||||
return 0;
|
||||
}
|
||||
@@ -201,7 +173,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)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
throw thread_resource_error();
|
||||
}
|
||||
intrusive_ptr_add_ref(thread_info.get());
|
||||
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
||||
@@ -222,7 +194,7 @@ namespace boost
|
||||
++count;
|
||||
interruption_enabled=false;
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{}
|
||||
private:
|
||||
@@ -233,15 +205,7 @@ namespace boost
|
||||
void make_external_thread_data()
|
||||
{
|
||||
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
|
||||
try
|
||||
{
|
||||
set_current_thread_data(me);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
detail::heap_delete(me);
|
||||
throw;
|
||||
}
|
||||
set_current_thread_data(me);
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
@@ -254,27 +218,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());
|
||||
@@ -284,7 +248,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)))
|
||||
@@ -295,7 +259,7 @@ namespace boost
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
release_handle();
|
||||
@@ -303,39 +267,41 @@ 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 BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
detail::thread_data_ptr thread::get_thread_info() const
|
||||
{
|
||||
boost::mutex::scoped_lock l(thread_info_mutex);
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
@@ -345,7 +311,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;
|
||||
@@ -374,29 +340,13 @@ namespace boost
|
||||
else
|
||||
{
|
||||
long const hundred_nanoseconds_in_one_second=10000000;
|
||||
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);
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
return due_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
|
||||
{
|
||||
@@ -417,10 +367,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();
|
||||
@@ -431,7 +381,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)
|
||||
{
|
||||
@@ -447,17 +397,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);
|
||||
@@ -504,12 +454,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);
|
||||
@@ -519,7 +469,7 @@ namespace boost
|
||||
{
|
||||
detail::win32::Sleep(0);
|
||||
}
|
||||
|
||||
|
||||
disable_interruption::disable_interruption():
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
@@ -528,7 +478,7 @@ namespace boost
|
||||
get_current_thread_data()->interruption_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
@@ -544,7 +494,7 @@ namespace boost
|
||||
get_current_thread_data()->interruption_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
@@ -560,8 +510,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;
|
||||
}
|
||||
|
||||
@@ -591,43 +541,41 @@ namespace boost
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func.get() && current_node->value)
|
||||
if(cleanup_existing && current_node->func.get())
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else if(func && tss_data)
|
||||
else
|
||||
{
|
||||
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()
|
||||
{}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit()
|
||||
{
|
||||
boost::run_thread_exit_callbacks();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,27 +24,27 @@
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
boost::on_process_enter();
|
||||
boost::on_thread_enter();
|
||||
on_process_enter();
|
||||
on_thread_enter();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
{
|
||||
boost::on_thread_enter();
|
||||
on_thread_enter();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
boost::on_thread_exit();
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
{
|
||||
boost::on_thread_exit();
|
||||
boost::on_process_exit();
|
||||
on_thread_exit();
|
||||
on_process_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -52,9 +52,7 @@
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
void tss_cleanup_implemented()
|
||||
extern "C" void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
@@ -70,7 +68,5 @@ namespace boost
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
|
||||
#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__)
|
||||
#if defined(__MINGW32__) && !defined(_WIN64)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
@@ -19,37 +19,42 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
void tss_cleanup_implemented() {}
|
||||
}
|
||||
extern "C" void tss_cleanup_implemented(void) {}
|
||||
|
||||
namespace {
|
||||
void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
}
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
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 )() __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;
|
||||
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;
|
||||
|
||||
ULONG __tls_index__ = 0;
|
||||
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
|
||||
@@ -57,8 +62,10 @@ 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__,
|
||||
@@ -68,7 +75,6 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
(DWORD) 0,
|
||||
(DWORD) 0
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(UNDER_CE)
|
||||
@@ -83,13 +89,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)();
|
||||
typedef void (__cdecl *_PVFV)(void);
|
||||
#define INIRETSUCCESS
|
||||
#define PVAPI void __cdecl
|
||||
#define PVAPI void
|
||||
#else
|
||||
typedef int (__cdecl *_PVFV)();
|
||||
typedef int (__cdecl *_PVFV)(void);
|
||||
#define INIRETSUCCESS 0
|
||||
#define PVAPI int __cdecl
|
||||
#define PVAPI int
|
||||
#endif
|
||||
|
||||
typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
|
||||
@@ -106,9 +112,9 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
{
|
||||
//Forward declarations
|
||||
|
||||
static PVAPI on_tls_prepare();
|
||||
static PVAPI on_process_init();
|
||||
static PVAPI on_process_term();
|
||||
static PVAPI on_tls_prepare(void);
|
||||
static PVAPI on_process_init(void);
|
||||
static PVAPI on_process_term(void);
|
||||
static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
|
||||
|
||||
//The .CRT$Xxx information is taken from Codeguru:
|
||||
@@ -119,10 +125,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
#pragma section(".CRT$XCU",long,read)
|
||||
#pragma section(".CRT$XTU",long,read)
|
||||
#pragma section(".CRT$XLC",long,read)
|
||||
__declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
|
||||
__declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
|
||||
__declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
|
||||
__declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
|
||||
static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
|
||||
static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
|
||||
static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
|
||||
static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
|
||||
#else
|
||||
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
|
||||
# pragma data_seg(push, old_seg)
|
||||
@@ -162,8 +168,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4189)
|
||||
#endif
|
||||
|
||||
PVAPI on_tls_prepare()
|
||||
PVAPI on_tls_prepare(void)
|
||||
{
|
||||
//The following line has an important side effect:
|
||||
//if the TLS directory is not already there, it will
|
||||
@@ -204,7 +209,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
PVAPI on_process_init()
|
||||
PVAPI on_process_init(void)
|
||||
{
|
||||
//Schedule on_thread_exit() to be called for the main
|
||||
//thread before destructors of global objects have been
|
||||
@@ -215,18 +220,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(boost::on_thread_exit);
|
||||
atexit(on_thread_exit);
|
||||
|
||||
//Call Boost process entry callback here
|
||||
|
||||
boost::on_process_enter();
|
||||
on_process_enter();
|
||||
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
PVAPI on_process_term()
|
||||
PVAPI on_process_term(void)
|
||||
{
|
||||
boost::on_process_exit();
|
||||
on_process_exit();
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
@@ -234,34 +239,16 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
boost::on_process_exit();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} //namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
|
||||
}
|
||||
namespace boost
|
||||
{
|
||||
void tss_cleanup_implemented()
|
||||
extern "C" void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
@@ -277,8 +264,6 @@ namespace boost
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
|
||||
@@ -38,11 +38,8 @@ rule thread-run ( sources )
|
||||
[ thread-run test_thread_id.cpp ]
|
||||
[ thread-run test_hardware_concurrency.cpp ]
|
||||
[ thread-run test_thread_move.cpp ]
|
||||
[ thread-run test_thread_return_local.cpp ]
|
||||
[ 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 ]
|
||||
@@ -58,33 +55,7 @@ rule thread-run ( sources )
|
||||
[ thread-run test_shared_mutex_timed_locks.cpp ]
|
||||
[ thread-run test_lock_concept.cpp ]
|
||||
[ thread-run test_generic_locks.cpp ]
|
||||
[ thread-run test_futures.cpp ]
|
||||
[ 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 ]
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
void run_thread() {
|
||||
return;
|
||||
}
|
||||
|
||||
int main() {
|
||||
boost::thread t(run_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
|
||||
#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
|
||||
@@ -55,9 +55,9 @@ void test_barrier()
|
||||
BOOST_CHECK_EQUAL(global_parameter,5);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: barrier test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_barrier));
|
||||
|
||||
@@ -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::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_waits));
|
||||
|
||||
@@ -211,9 +211,9 @@ void test_condition_notify_all()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||
|
||||
@@ -144,9 +144,9 @@ void test_condition_notify_one()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -16,7 +16,7 @@ bool fake_predicate()
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned const timeout_seconds=2;
|
||||
unsigned const timeout_seconds=5;
|
||||
unsigned const timeout_grace=1;
|
||||
boost::posix_time::milliseconds const timeout_resolution(100);
|
||||
|
||||
@@ -70,101 +70,17 @@ void do_test_relative_timed_wait_with_predicate_times_out()
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_timed_wait_relative_times_out()
|
||||
{
|
||||
boost::condition_variable cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
while(cond.timed_wait(lock,delay));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_timed_wait_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+delay;
|
||||
|
||||
while(cond.timed_wait(lock,timeout));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_timed_wait_with_predicate_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+delay;
|
||||
|
||||
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_relative_timed_wait_with_predicate_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
bool const res=cond.timed_wait(lock,delay,fake_predicate);
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK(!res);
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
void do_test_cv_any_timed_wait_relative_times_out()
|
||||
{
|
||||
boost::condition_variable_any cond;
|
||||
boost::mutex m;
|
||||
|
||||
boost::posix_time::seconds const delay(timeout_seconds);
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
|
||||
while(cond.timed_wait(lock,delay));
|
||||
|
||||
boost::system_time const end=boost::get_system_time();
|
||||
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
|
||||
}
|
||||
|
||||
|
||||
void test_timed_wait_times_out()
|
||||
{
|
||||
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
timed_test(&do_test_cv_any_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -272,16 +272,6 @@ struct dummy_mutex
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<>
|
||||
struct is_mutex_type<dummy_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_lock_five_in_range()
|
||||
{
|
||||
@@ -296,80 +286,10 @@ void test_lock_five_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()
|
||||
void test_lock_ten_in_range()
|
||||
{
|
||||
unsigned const num_mutexes=10;
|
||||
dummy_mutex2 mutexes[num_mutexes];
|
||||
dummy_mutex mutexes[num_mutexes];
|
||||
|
||||
boost::lock(mutexes,mutexes+num_mutexes);
|
||||
|
||||
@@ -568,9 +488,9 @@ void test_try_lock_five()
|
||||
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
|
||||
@@ -580,8 +500,7 @@ boost::unit_test::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_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_in_range));
|
||||
test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
|
||||
test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
|
||||
|
||||
@@ -11,9 +11,9 @@ void test_hardware_concurrency_is_non_zero()
|
||||
BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
// 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>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
@@ -82,122 +82,6 @@ struct test_initially_unlocked_if_other_thread_has_lock
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::try_to_lock);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::unique_lock<Mutex> lock(m);
|
||||
|
||||
typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_locked_if_other_thread_has_shared_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_initially_locked_if_other_thread_has_shared_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::shared_lock<Mutex> lock(m);
|
||||
|
||||
typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_unlocked_with_defer_lock_parameter
|
||||
{
|
||||
@@ -265,64 +149,6 @@ struct test_locked_after_try_lock_called
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_unlocked_after_try_lock_if_other_thread_has_lock
|
||||
{
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_unlocked_after_try_lock_if_other_thread_has_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::defer_lock);
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
typedef test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock> this_type;
|
||||
|
||||
boost::thread t(&this_type::locking_thread,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_lock_called_when_already_locked
|
||||
{
|
||||
@@ -378,8 +204,6 @@ struct test_locks_can_be_swapped
|
||||
{
|
||||
Mutex m1;
|
||||
Mutex m2;
|
||||
Mutex m3;
|
||||
|
||||
Lock l1(m1);
|
||||
Lock l2(m2);
|
||||
|
||||
@@ -395,16 +219,16 @@ struct test_locks_can_be_swapped
|
||||
|
||||
BOOST_CHECK_EQUAL(l1.mutex(),&m1);
|
||||
BOOST_CHECK_EQUAL(l2.mutex(),&m2);
|
||||
|
||||
l1.swap(Lock(m3));
|
||||
|
||||
BOOST_CHECK_EQUAL(l1.mutex(),&m3);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
void test_lock_is_scoped_lock_concept_for_mutex()
|
||||
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
|
||||
{
|
||||
typedef typename Mutex::scoped_lock Lock;
|
||||
|
||||
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
@@ -414,24 +238,6 @@ void test_lock_is_scoped_lock_concept_for_mutex()
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
test_locks_can_be_swapped<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
|
||||
}
|
||||
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
|
||||
{
|
||||
typedef typename Mutex::scoped_lock Lock;
|
||||
|
||||
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
|
||||
}
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex)
|
||||
{
|
||||
typedef boost::unique_lock<Mutex> Lock;
|
||||
|
||||
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
|
||||
}
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
|
||||
@@ -446,125 +252,26 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
test_locks_can_be_swapped<Mutex,Lock>()();
|
||||
}
|
||||
|
||||
struct dummy_shared_mutex
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
bool locked;
|
||||
bool shared_locked;
|
||||
bool shared_unlocked;
|
||||
bool shared_timed_locked_relative;
|
||||
bool shared_timed_locked_absolute;
|
||||
bool timed_locked_relative;
|
||||
bool timed_locked_absolute;
|
||||
|
||||
dummy_shared_mutex():
|
||||
locked(false),shared_locked(false),shared_unlocked(false),
|
||||
shared_timed_locked_relative(false),
|
||||
shared_timed_locked_absolute(false),
|
||||
timed_locked_relative(false),
|
||||
timed_locked_absolute(false)
|
||||
{}
|
||||
|
||||
void lock()
|
||||
{
|
||||
locked=true;
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
shared_locked=true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
shared_unlocked=true;
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time)
|
||||
{
|
||||
shared_timed_locked_absolute=true;
|
||||
return false;
|
||||
}
|
||||
template<typename Duration>
|
||||
bool timed_lock_shared(Duration)
|
||||
{
|
||||
shared_timed_locked_relative=true;
|
||||
return false;
|
||||
}
|
||||
bool timed_lock(boost::system_time)
|
||||
{
|
||||
timed_locked_absolute=true;
|
||||
return false;
|
||||
}
|
||||
template<typename Duration>
|
||||
bool timed_lock(Duration)
|
||||
{
|
||||
timed_locked_relative=true;
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
void test_shared_lock()
|
||||
{
|
||||
typedef boost::shared_mutex Mutex;
|
||||
typedef boost::shared_lock<Mutex> Lock;
|
||||
|
||||
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
|
||||
test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
test_locks_can_be_swapped<Mutex,Lock>()();
|
||||
|
||||
dummy_shared_mutex dummy;
|
||||
boost::shared_lock<dummy_shared_mutex> lk(dummy);
|
||||
BOOST_CHECK(dummy.shared_locked);
|
||||
lk.unlock();
|
||||
BOOST_CHECK(dummy.shared_unlocked);
|
||||
lk.timed_lock(boost::posix_time::milliseconds(5));
|
||||
BOOST_CHECK(dummy.shared_timed_locked_relative);
|
||||
lk.timed_lock(boost::get_system_time());
|
||||
BOOST_CHECK(dummy.shared_timed_locked_absolute);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
|
||||
|
||||
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
|
||||
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types));
|
||||
|
||||
typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
|
||||
boost::recursive_try_mutex,boost::recursive_timed_mutex> try_mutex_types;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
|
||||
|
||||
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
|
||||
test->add(BOOST_TEST_CASE(&test_shared_lock));
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,try_mutex_types));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -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,17 +89,10 @@ 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;
|
||||
@@ -108,30 +101,16 @@ 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::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
@@ -97,86 +96,6 @@ struct test_trylock
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
struct test_lock_times_out_if_other_thread_has_lock
|
||||
{
|
||||
typedef boost::unique_lock<Mutex> Lock;
|
||||
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_lock_times_out_if_other_thread_has_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.timed_lock(boost::posix_time::milliseconds(50));
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
void locking_thread_through_constructor()
|
||||
{
|
||||
Lock lock(m,boost::posix_time::milliseconds(50));
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
typedef test_lock_times_out_if_other_thread_has_lock<Mutex> this_type;
|
||||
|
||||
void do_test(void (this_type::*test_func)())
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
locked=false;
|
||||
done=false;
|
||||
|
||||
boost::thread t(test_func,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
do_test(&this_type::locking_thread);
|
||||
do_test(&this_type::locking_thread_through_constructor);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename M>
|
||||
struct test_timedlock
|
||||
{
|
||||
@@ -190,8 +109,6 @@ struct test_timedlock
|
||||
|
||||
void operator()()
|
||||
{
|
||||
test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
|
||||
|
||||
mutex_type mutex;
|
||||
boost::condition condition;
|
||||
|
||||
@@ -261,7 +178,6 @@ struct test_recursive_lock
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void do_test_mutex()
|
||||
{
|
||||
test_lock<boost::mutex>()();
|
||||
@@ -331,9 +247,9 @@ void test_recursive_timed_mutex()
|
||||
timed_test(&do_test_recursive_timed_mutex, 3);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_mutex));
|
||||
|
||||
@@ -178,9 +178,9 @@ void test_call_once_retried_on_exception()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_call_once));
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
void test_multiple_readers()
|
||||
{
|
||||
unsigned const number_of_threads=10;
|
||||
unsigned const number_of_threads=100;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
@@ -64,7 +64,7 @@ void test_multiple_readers()
|
||||
|
||||
void test_only_one_writer_permitted()
|
||||
{
|
||||
unsigned const number_of_threads=10;
|
||||
unsigned const number_of_threads=100;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
@@ -164,7 +164,7 @@ void test_unlocking_writer_unblocks_all_readers()
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
unsigned const reader_count=10;
|
||||
unsigned const reader_count=100;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -218,8 +218,8 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
|
||||
boost::mutex finish_writing_mutex;
|
||||
boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
|
||||
|
||||
unsigned const reader_count=10;
|
||||
unsigned const writer_count=10;
|
||||
unsigned const reader_count=100;
|
||||
unsigned const writer_count=100;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -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::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_multiple_readers));
|
||||
|
||||
@@ -15,41 +15,10 @@
|
||||
BOOST_CHECK_EQUAL(value,expected_value); \
|
||||
}
|
||||
|
||||
class simple_upgrade_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
void operator=(simple_upgrade_thread&);
|
||||
|
||||
public:
|
||||
simple_upgrade_thread(boost::shared_mutex& rwm_,
|
||||
boost::mutex& finish_mutex_,
|
||||
boost::mutex& unblocked_mutex_,
|
||||
unsigned& unblocked_count_):
|
||||
rwm(rwm_),finish_mutex(finish_mutex_),
|
||||
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::upgrade_lock<boost::shared_mutex> lk(rwm);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock ulk(unblocked_mutex);
|
||||
++unblocked_count;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock flk(finish_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void test_only_one_upgrade_lock_permitted()
|
||||
{
|
||||
unsigned const number_of_threads=10;
|
||||
unsigned const number_of_threads=100;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
@@ -102,7 +71,7 @@ void test_can_lock_upgrade_if_currently_locked_shared()
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
unsigned const reader_count=10;
|
||||
unsigned const reader_count=100;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -138,14 +107,6 @@ 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()
|
||||
{
|
||||
|
||||
@@ -169,29 +130,6 @@ void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(!try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
@@ -203,17 +141,6 @@ void test_if_no_thread_has_lock_try_lock_shared_returns_true()
|
||||
}
|
||||
}
|
||||
|
||||
void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
|
||||
{
|
||||
|
||||
@@ -237,60 +164,13 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_upgrade();
|
||||
BOOST_CHECK(!try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_upgrade();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::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));
|
||||
|
||||
@@ -251,9 +251,9 @@ void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
|
||||
|
||||
@@ -216,9 +216,9 @@ void test_swap()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_sleep));
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// (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;
|
||||
}
|
||||
@@ -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::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::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));
|
||||
|
||||
@@ -209,9 +209,9 @@ void test_thread_member_function_one_argument()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread launching test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_function_no_arguments));
|
||||
|
||||
@@ -45,90 +45,92 @@ struct X
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
X x;
|
||||
|
||||
// 0
|
||||
|
||||
boost::thread( &X::f0, &x ).join();
|
||||
boost::thread( &X::f0, boost::ref(x) ).join();
|
||||
thread( &X::f0, &x ).join();
|
||||
thread( &X::f0, ref(x) ).join();
|
||||
|
||||
boost::thread( &X::g0, &x ).join();
|
||||
boost::thread( &X::g0, x ).join();
|
||||
boost::thread( &X::g0, boost::ref(x) ).join();
|
||||
thread( &X::g0, &x ).join();
|
||||
thread( &X::g0, x ).join();
|
||||
thread( &X::g0, ref(x) ).join();
|
||||
|
||||
// 1
|
||||
|
||||
boost::thread( &X::f1, &x, 1 ).join();
|
||||
boost::thread( &X::f1, boost::ref(x), 1 ).join();
|
||||
thread( &X::f1, &x, 1 ).join();
|
||||
thread( &X::f1, ref(x), 1 ).join();
|
||||
|
||||
boost::thread( &X::g1, &x, 1 ).join();
|
||||
boost::thread( &X::g1, x, 1 ).join();
|
||||
boost::thread( &X::g1, boost::ref(x), 1 ).join();
|
||||
thread( &X::g1, &x, 1 ).join();
|
||||
thread( &X::g1, x, 1 ).join();
|
||||
thread( &X::g1, ref(x), 1 ).join();
|
||||
|
||||
// 2
|
||||
|
||||
boost::thread( &X::f2, &x, 1, 2 ).join();
|
||||
boost::thread( &X::f2, boost::ref(x), 1, 2 ).join();
|
||||
thread( &X::f2, &x, 1, 2 ).join();
|
||||
thread( &X::f2, ref(x), 1, 2 ).join();
|
||||
|
||||
boost::thread( &X::g2, &x, 1, 2 ).join();
|
||||
boost::thread( &X::g2, x, 1, 2 ).join();
|
||||
boost::thread( &X::g2, boost::ref(x), 1, 2 ).join();
|
||||
thread( &X::g2, &x, 1, 2 ).join();
|
||||
thread( &X::g2, x, 1, 2 ).join();
|
||||
thread( &X::g2, ref(x), 1, 2 ).join();
|
||||
|
||||
// 3
|
||||
|
||||
boost::thread( &X::f3, &x, 1, 2, 3 ).join();
|
||||
boost::thread( &X::f3, boost::ref(x), 1, 2, 3 ).join();
|
||||
thread( &X::f3, &x, 1, 2, 3 ).join();
|
||||
thread( &X::f3, ref(x), 1, 2, 3 ).join();
|
||||
|
||||
boost::thread( &X::g3, &x, 1, 2, 3 ).join();
|
||||
boost::thread( &X::g3, x, 1, 2, 3 ).join();
|
||||
boost::thread( &X::g3, boost::ref(x), 1, 2, 3 ).join();
|
||||
thread( &X::g3, &x, 1, 2, 3 ).join();
|
||||
thread( &X::g3, x, 1, 2, 3 ).join();
|
||||
thread( &X::g3, ref(x), 1, 2, 3 ).join();
|
||||
|
||||
// 4
|
||||
|
||||
boost::thread( &X::f4, &x, 1, 2, 3, 4 ).join();
|
||||
boost::thread( &X::f4, boost::ref(x), 1, 2, 3, 4 ).join();
|
||||
thread( &X::f4, &x, 1, 2, 3, 4 ).join();
|
||||
thread( &X::f4, ref(x), 1, 2, 3, 4 ).join();
|
||||
|
||||
boost::thread( &X::g4, &x, 1, 2, 3, 4 ).join();
|
||||
boost::thread( &X::g4, x, 1, 2, 3, 4 ).join();
|
||||
boost::thread( &X::g4, boost::ref(x), 1, 2, 3, 4 ).join();
|
||||
thread( &X::g4, &x, 1, 2, 3, 4 ).join();
|
||||
thread( &X::g4, x, 1, 2, 3, 4 ).join();
|
||||
thread( &X::g4, ref(x), 1, 2, 3, 4 ).join();
|
||||
|
||||
// 5
|
||||
|
||||
boost::thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
|
||||
boost::thread( &X::f5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
|
||||
thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
|
||||
thread( &X::f5, ref(x), 1, 2, 3, 4, 5 ).join();
|
||||
|
||||
boost::thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join();
|
||||
boost::thread( &X::g5, x, 1, 2, 3, 4, 5 ).join();
|
||||
boost::thread( &X::g5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
|
||||
thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join();
|
||||
thread( &X::g5, x, 1, 2, 3, 4, 5 ).join();
|
||||
thread( &X::g5, ref(x), 1, 2, 3, 4, 5 ).join();
|
||||
|
||||
// 6
|
||||
|
||||
boost::thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join();
|
||||
boost::thread( &X::f6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
|
||||
thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join();
|
||||
thread( &X::f6, ref(x), 1, 2, 3, 4, 5, 6 ).join();
|
||||
|
||||
boost::thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join();
|
||||
boost::thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join();
|
||||
boost::thread( &X::g6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
|
||||
thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join();
|
||||
thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join();
|
||||
thread( &X::g6, ref(x), 1, 2, 3, 4, 5, 6 ).join();
|
||||
|
||||
// 7
|
||||
|
||||
boost::thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join();
|
||||
boost::thread( &X::f7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
|
||||
thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join();
|
||||
thread( &X::f7, ref(x), 1, 2, 3, 4, 5, 6, 7).join();
|
||||
|
||||
boost::thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join();
|
||||
boost::thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join();
|
||||
boost::thread( &X::g7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
|
||||
thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join();
|
||||
thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join();
|
||||
thread( &X::g7, ref(x), 1, 2, 3, 4, 5, 6, 7).join();
|
||||
|
||||
// 8
|
||||
|
||||
boost::thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
boost::thread( &X::f8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
thread( &X::f8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
|
||||
boost::thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
boost::thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
boost::thread( &X::g8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
thread( &X::g8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
|
||||
|
||||
BOOST_TEST( x.hash == 23558 );
|
||||
|
||||
return boost::report_errors();
|
||||
return report_errors();
|
||||
}
|
||||
|
||||
@@ -1,56 +1,37 @@
|
||||
// Copyright (C) 2007-9 Anthony Williams
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
void do_nothing(boost::thread::id* my_id)
|
||||
{
|
||||
*my_id=boost::this_thread::get_id();
|
||||
}
|
||||
void do_nothing()
|
||||
{}
|
||||
|
||||
void test_move_on_construction()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=boost::thread(do_nothing,&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
boost::thread x=boost::thread(do_nothing);
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::thread make_thread(boost::thread::id* the_id)
|
||||
boost::thread make_thread()
|
||||
{
|
||||
return boost::thread(do_nothing,the_id);
|
||||
return boost::thread(do_nothing);
|
||||
}
|
||||
|
||||
void test_move_from_function_return()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
boost::thread x=make_thread();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
void test_move_assign()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x(do_nothing,&the_id);
|
||||
boost::thread y;
|
||||
y=boost::move(x);
|
||||
boost::thread::id y_id=y.get_id();
|
||||
y.join();
|
||||
BOOST_CHECK_EQUAL(the_id,y_id);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_move_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_return));
|
||||
test->add(BOOST_TEST_CASE(test_move_assign));
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// 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)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
void do_nothing(boost::thread::id* my_id)
|
||||
{
|
||||
*my_id=boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
boost::thread make_thread_move_return(boost::thread::id* the_id)
|
||||
{
|
||||
boost::thread t(do_nothing,the_id);
|
||||
return boost::move(t);
|
||||
}
|
||||
|
||||
void test_move_from_function_move_return()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread_move_return(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
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));
|
||||
return test;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// 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)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
void do_nothing(boost::thread::id* my_id)
|
||||
{
|
||||
*my_id=boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
boost::thread make_thread_return_local(boost::thread::id* the_id)
|
||||
{
|
||||
boost::thread t(do_nothing,the_id);
|
||||
return t;
|
||||
}
|
||||
|
||||
void test_move_from_function_return_local()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread_return_local(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
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));
|
||||
return test;
|
||||
}
|
||||
@@ -310,50 +310,15 @@ void test_tss_does_no_cleanup_with_null_cleanup_function()
|
||||
timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
|
||||
}
|
||||
|
||||
void thread_with_local_tss_ptr()
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
{
|
||||
boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
|
||||
|
||||
local_tss.reset(new Dummy);
|
||||
}
|
||||
BOOST_CHECK(tss_cleanup_called);
|
||||
tss_cleanup_called=false;
|
||||
}
|
||||
|
||||
|
||||
void test_tss_does_not_call_cleanup_after_ptr_destroyed()
|
||||
{
|
||||
boost::thread t(thread_with_local_tss_ptr);
|
||||
t.join();
|
||||
BOOST_CHECK(!tss_cleanup_called);
|
||||
}
|
||||
|
||||
void test_tss_cleanup_not_called_for_null_pointer()
|
||||
{
|
||||
boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
|
||||
local_tss.reset(new Dummy);
|
||||
tss_cleanup_called=false;
|
||||
local_tss.reset(0);
|
||||
BOOST_CHECK(tss_cleanup_called);
|
||||
tss_cleanup_called=false;
|
||||
local_tss.reset(new Dummy);
|
||||
BOOST_CHECK(!tss_cleanup_called);
|
||||
}
|
||||
|
||||
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_tss));
|
||||
test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup));
|
||||
test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release));
|
||||
test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function));
|
||||
test->add(BOOST_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed));
|
||||
test->add(BOOST_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user