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

Compare commits

..

113 Commits

Author SHA1 Message Date
Beman Dawes
c484c376d3 Branch at revision 46530
[SVN r46531]
2008-06-19 18:57:10 +00:00
Anthony Williams
851d6a987f Correctly remove the reference type when copying the thread function into the thread data area so we don't end up with a dangling reference
[SVN r46295]
2008-06-10 15:29:35 +00:00
Anthony Williams
9bebd7b35f Disable general templated thread constructor for movable types, in order to prevent it trying to act as a thread copy constructor for EDG based compilers
[SVN r46273]
2008-06-09 14:00:03 +00:00
Anthony Williams
309acb9597 Don't try and use _interlockedbittestandset primitives if we don't know they're present
[SVN r46219]
2008-06-07 20:54:19 +00:00
Anthony Williams
a56887167e Added swap for try_lock_wrapper
[SVN r46164]
2008-06-05 12:25:58 +00:00
Anthony Williams
e984dff4e4 Combined TSS header for pthread and win32, #1958 now fixed for pthread too
[SVN r46162]
2008-06-05 11:19:06 +00:00
Anthony Williams
685e4d446b Test and fix for bug #1958 on Win32
[SVN r46161]
2008-06-05 11:16:05 +00:00
Anthony Williams
8af680f307 Added swap for unique_lock
[SVN r46160]
2008-06-05 10:39:08 +00:00
Anthony Williams
6c60cce60d Removed partial initializer for res: both values will be assigned later, so no need to initialize either
[SVN r46124]
2008-06-04 16:05:29 +00:00
Anthony Williams
5882a675bb Added extra initializer to timeout to try and eliminate warnings with some compilers
[SVN r46123]
2008-06-04 16:03:51 +00:00
Anthony Williams
a5e95845b3 Added documentation for swap()
[SVN r46122]
2008-06-04 16:00:13 +00:00
Anthony Williams
5b83d81e40 Added free function swap() for threads
[SVN r46121]
2008-06-04 15:50:34 +00:00
Anthony Williams
c8e5ad564d basic_condition_variable::lock_entry extracted to basic_cv_lock_entry in order to try and eliminate problems on Borland compiler
[SVN r46094]
2008-06-03 20:56:39 +00:00
Anthony Williams
5edfa273ff removed unused header
[SVN r46093]
2008-06-03 20:55:40 +00:00
Anthony Williams
4db57bcb10 Move thread_data to detail namespace rather than have it as a nested type of boost::thread, to try and help compilers that have problems with the partial specializations for reference_wrapper
[SVN r45912]
2008-05-29 15:38:08 +00:00
Anthony Williams
3f13340903 Don't construct function objects directly in boost::thread constructor as some compilers can't handle that.
[SVN r45911]
2008-05-29 15:36:52 +00:00
Anthony Williams
6abb53c9d3 Move definition of constructor and destructor of condition_variable into condition_variable_fwd.hpp, so they are always available
[SVN r45909]
2008-05-29 15:16:55 +00:00
Anthony Williams
fdd20a519e Use wrapper functions in try_lock_wrapper rather than using declarations, as the latter confuse some compilers
[SVN r45908]
2008-05-29 15:16:04 +00:00
Anthony Williams
67cc49f333 More tests for generic locks, and a new range version
[SVN r45897]
2008-05-29 09:02:05 +00:00
Anthony Williams
31a34cd0b5 Added missing "no"
[SVN r45870]
2008-05-28 14:50:25 +00:00
Anthony Williams
ef8c08ba99 Removed surplus "the"
[SVN r45869]
2008-05-28 12:55:30 +00:00
Anthony Williams
2991ca6c6f Added abi prefix and suffix headers
[SVN r45865]
2008-05-28 11:02:06 +00:00
Anthony Williams
52bace18b2 hardware_concurrency works for CYGWIN
[SVN r45860]
2008-05-28 09:38:14 +00:00
Anthony Williams
767d14ae4f Added documentation for time support in the thread library
[SVN r45859]
2008-05-28 09:00:32 +00:00
Anthony Williams
1a5c911e36 Added documentation for time support in the thread library
[SVN r45858]
2008-05-28 09:00:23 +00:00
Anthony Williams
6e42a04e43 Added note about move support
[SVN r45856]
2008-05-28 08:09:07 +00:00
Anthony Williams
28be2cfeef intrusive_ptr_add_ref and intrusive_ptr_release need to be inline if defined in the header
[SVN r45809]
2008-05-27 06:32:05 +00:00
Anthony Williams
8be168fd87 Basic tests for lock() when other thread is acquiring locks in same or opposite order
[SVN r45767]
2008-05-26 08:59:48 +00:00
Anthony Williams
eee95fef57 Initial test for generic lock functions
[SVN r45766]
2008-05-26 08:40:21 +00:00
Anthony Williams
9ea179b052 Initial test for generic lock functions
[SVN r45765]
2008-05-26 08:40:13 +00:00
Anthony Williams
6868280409 Try and avoid compile errors in test_thread_callable_object_one_argument
[SVN r45764]
2008-05-26 07:36:16 +00:00
Anthony Williams
e00b764454 The signature of _interlockedbittestandset changes between MSVC 2005 and MSVC 2008
[SVN r45689]
2008-05-23 19:53:06 +00:00
Anthony Williams
999613c686 Added note about mutex not being recursive
[SVN r45688]
2008-05-23 19:33:18 +00:00
Anthony Williams
c2661d7eb5 define intrusive_ptr_add_ref and intrusive_ptr_release at namespace scope rather than inline as friends in order to try and avoid compiler problems
[SVN r45682]
2008-05-23 15:18:19 +00:00
Anthony Williams
4d21dd1f47 try_lock_wrapper implements operator! in order to try and avoid compiler problems
[SVN r45681]
2008-05-23 15:17:14 +00:00
Anthony Williams
a0a0e57527 Fixed #ifdef to actually use BTS primitives on MSVC 9
[SVN r45676]
2008-05-23 13:16:01 +00:00
Anthony Williams
d8af0d0b4e Reset thread_info on move rather than assigning 0
[SVN r45672]
2008-05-23 10:48:07 +00:00
Anthony Williams
113288e3b0 tidying up move
[SVN r45661]
2008-05-22 16:33:34 +00:00
Anthony Williams
afecfd7c2d Refactored boost::thread code to try and remove duplication
[SVN r45647]
2008-05-22 11:49:48 +00:00
Anthony Williams
94d89aac5f more rvalue reference stuff
[SVN r45626]
2008-05-21 21:11:30 +00:00
Anthony Williams
8831b13efc Use lock_guard<> instead of unique_lock<> internally. Clear out generations after notify_all, as they're all notified
[SVN r45625]
2008-05-21 21:10:45 +00:00
Peter Dimov
01f99da03a Extended boost::thread to 9 arguments, hopefully fixed member function ambiguity.
[SVN r45621]
2008-05-21 20:44:08 +00:00
Anthony Williams
080654e3ef New tests for a normal function with one argument, and a member function with 0 or 1 arguments
[SVN r45607]
2008-05-21 13:38:04 +00:00
Anthony Williams
2ac2eb2a61 try_lock_wrapper has its own operator bool_type to avoid problems with a using declaration
[SVN r45602]
2008-05-21 10:39:47 +00:00
Anthony Williams
61b940b705 Renamed namespace user to user_test_ns to try and avoid a name clash on some platforms
[SVN r45601]
2008-05-21 09:51:53 +00:00
Anthony Williams
4a4f87e017 support for a generic lock() function
[SVN r45481]
2008-05-18 09:10:20 +00:00
Anthony Williams
6d5e7f63a7 Added beginnings of real rvalue-reference support
[SVN r45479]
2008-05-18 08:45:44 +00:00
Anthony Williams
f77285f375 Updated docs to make it explicit that terminate is called if a thread function throws an exception
[SVN r45294]
2008-05-12 09:04:02 +00:00
Anthony Williams
dc5d03a6dc Cleaned up to remove warnings
[SVN r45244]
2008-05-09 07:59:57 +00:00
Anthony Williams
ea0961b7f6 Fixed type truncation warning
[SVN r45243]
2008-05-09 07:49:22 +00:00
Anthony Williams
33d9f9774c Test and fix for bug #1905
[SVN r45242]
2008-05-09 07:48:44 +00:00
Anthony Williams
86097fa038 Use _WIN32 rather than WIN32 to prevent include of <unistd.h>
[SVN r45241]
2008-05-09 07:47:14 +00:00
Anthony Williams
70d9dbc45a Added default constructor to lock types
[SVN r45212]
2008-05-08 14:34:40 +00:00
Anthony Williams
3926fd3a20 Added docs for native_handle
[SVN r45211]
2008-05-08 12:59:59 +00:00
Anthony Williams
7861cf1146 Added native_handle to mutex types where possible
[SVN r45210]
2008-05-08 12:59:10 +00:00
Anthony Williams
0516b86a6e new BTS-based mutex implementation on win32
[SVN r45119]
2008-05-04 22:39:52 +00:00
Anthony Williams
ec735d3e9b Simplified move support
[SVN r45108]
2008-05-04 09:52:54 +00:00
Anthony Williams
1c5c070983 Updated locks.hpp to work with gcc as well as msvc
[SVN r44846]
2008-04-28 12:26:27 +00:00
Anthony Williams
a5c02b73dc Added entry to breaking changes about default-constructed threads and the current thread: issue #1835
[SVN r44840]
2008-04-28 09:10:38 +00:00
Anthony Williams
918b920670 Added detail::try_lock_wrapper for use as scoped_try_lock typedefs, to fix issue #1873
[SVN r44838]
2008-04-28 09:00:58 +00:00
Anthony Williams
de67d2e27e Fixed g++ compile error
[SVN r44773]
2008-04-26 07:34:46 +00:00
Anthony Williams
bc89df04cb Revamped condition variable to try and fix swallowed-notify problems (trac issue #1834)
[SVN r44699]
2008-04-21 16:22:16 +00:00
Anthony Williams
c26a4cf082 added private copy assignment operator and copy constructor to remove warnings
[SVN r44698]
2008-04-21 16:20:31 +00:00
Anthony Williams
6e1a866b13 Fix for issue #1657
[SVN r44424]
2008-04-14 21:04:33 +00:00
Anthony Williams
f91986ad0d Added extended adopt/defer/try constructors to upgrade_lock
[SVN r44370]
2008-04-13 15:50:08 +00:00
Anthony Williams
795cc23f3e Added test and fix for win32 condition_variable broadcast bug similar to #1803
[SVN r44168]
2008-04-11 08:52:09 +00:00
Anthony Williams
a3695bd4a0 Updated thread.hpp as catch-all header
[SVN r44153]
2008-04-10 18:34:42 +00:00
Anthony Williams
08dc521daf Added native_handle to condition_variable on pthreads
[SVN r44152]
2008-04-10 15:52:01 +00:00
Anthony Williams
8b916d21b1 added tests for plain timed_lock on shared_mutex
[SVN r44150]
2008-04-10 14:15:26 +00:00
Anthony Williams
c40f47a78a added overloads of timed_lock_shared with a relative timeout to shared_mutex
[SVN r44149]
2008-04-10 14:07:39 +00:00
Anthony Williams
e9fb470b06 Added native_handle to thread on posix platforms
[SVN r44148]
2008-04-10 13:35:07 +00:00
Anthony Williams
343d049772 fix for trac ticket #1804
[SVN r44147]
2008-04-10 13:27:44 +00:00
Anthony Williams
86f9480da4 fix for notify problem in trac ticket #1803
[SVN r44146]
2008-04-10 13:14:43 +00:00
Anthony Williams
8696b610ca Added test for trac ticket #1803: condition_variable::notify_one may fail to wake a waiting thread on win32
[SVN r44136]
2008-04-09 19:33:06 +00:00
Anthony Williams
6f13227eda Added locked-> owns_lock change to breaking changes
[SVN r44089]
2008-04-07 13:09:36 +00:00
Anthony Williams
58d5110e61 removed forward declaration for undefined type exclusive_lock
[SVN r43847]
2008-03-24 21:44:36 +00:00
Anthony Williams
76e53c7bc5 Removed some warnings: those from issue #1640 and others
[SVN r43730]
2008-03-19 17:25:13 +00:00
Anthony Williams
cfb08be1a8 New documentation for new thread library
[SVN r43671]
2008-03-17 10:29:27 +00:00
Anthony Williams
b5bbb7fb1c Test and fix for bug #1693 to ensure thread_specific_ptr works as desired
[SVN r43666]
2008-03-17 08:36:09 +00:00
Anthony Williams
a76c33f8cc made the callable_no_args function object a named object rather than a temporary, in order to avoid gratuitous breakage on some compilers
[SVN r43528]
2008-03-06 07:59:16 +00:00
Anthony Williams
810306b8f3 thread constructor now accepts up to three additional arguments to pass to thread function
[SVN r43464]
2008-03-03 10:52:44 +00:00
Anthony Williams
6c22bdb3bd Test and fix for issue #1665
[SVN r43461]
2008-03-03 08:44:42 +00:00
Daniel James
6a0d3e98bc Fix broken copyright urls. Fixes #1573.
[SVN r43422]
2008-02-27 18:51:14 +00:00
Anthony Williams
3809321037 added test for duration overloads of timed_lock, and added missing implementation to win32 version
[SVN r43094]
2008-02-04 13:16:32 +00:00
Anthony Williams
eef695bdf0 Provide tss_cleanup_implemented as a dummy function on Windows CE to allow tests to run
[SVN r42818]
2008-01-16 15:23:36 +00:00
Anthony Williams
ab01ab1e4d removed references to NULL
[SVN r42657]
2008-01-10 14:19:36 +00:00
Anthony Williams
c8d8a108a7 Updated thread ID test
[SVN r42228]
2007-12-21 10:54:59 +00:00
Anthony Williams
7afd9efcc5 added hardware_concurrency support for apple, freebsd and sun platforms
[SVN r42195]
2007-12-20 08:37:02 +00:00
Anthony Williams
56ded87ad2 added missing parentheses
[SVN r42194]
2007-12-20 07:46:00 +00:00
Anthony Williams
82e503339b Implement hardware_concurrency for pthread
[SVN r42168]
2007-12-19 10:45:01 +00:00
Anthony Williams
713d0c7ace Updated thread ID, and added tests
[SVN r42166]
2007-12-19 10:39:45 +00:00
Anthony Williams
25ad6e3f8f boost::move support for locks
[SVN r42118]
2007-12-17 12:52:50 +00:00
Anthony Williams
df0197b617 Updated move function test to be fair to Borland
[SVN r42117]
2007-12-17 11:24:13 +00:00
Anthony Williams
a89c4f01ad explicit move functions for threads, with a test
[SVN r42087]
2007-12-15 22:36:43 +00:00
Anthony Williams
ae67099633 added timed_wait overloads that take a duration
[SVN r42086]
2007-12-15 22:34:30 +00:00
Anthony Williams
57542d3a5c fixed order of comparison in timeout check
[SVN r41819]
2007-12-07 08:11:11 +00:00
Anthony Williams
9a1da14116 improved timeout checks
[SVN r41741]
2007-12-05 10:58:45 +00:00
Anthony Williams
ed050d753d added missing include of detail/config.hpp
[SVN r41738]
2007-12-05 08:27:44 +00:00
Anthony Williams
8bec363710 changed order of declaration to eliminate warnings
[SVN r41687]
2007-12-04 14:07:01 +00:00
Anthony Williams
7c68e190a9 Added test for thread move constructor; implemented move on pthreads
[SVN r41686]
2007-12-04 13:02:58 +00:00
Anthony Williams
7ebf5ea3d1 add explicit casts to remove warnings
[SVN r41684]
2007-12-04 12:08:38 +00:00
Anthony Williams
11e0435a4b don't dllexport/dllimport inline functions
[SVN r41683]
2007-12-04 11:44:25 +00:00
Anthony Williams
d15ee57cd1 split shared mutex tests in two to take less time
[SVN r41682]
2007-12-04 10:04:30 +00:00
Anthony Williams
56d660b7fd changed boost::move to boost::detail::thread_move to fix issue #1492
[SVN r41681]
2007-12-04 09:15:37 +00:00
Anthony Williams
792958e693 fixed typo in condition_variable_any::timed_wait
[SVN r41679]
2007-12-04 07:57:23 +00:00
Anthony Williams
914e67dc04 check predicate before returning if we time out on a predicated version of timed_wait
[SVN r41668]
2007-12-03 22:00:26 +00:00
Anthony Williams
b50a7ccb61 interruptible_wait (and hence condition timed_wait) now uses a WaitableTimer where possible, to be robust in the face of clock changes
[SVN r41505]
2007-11-30 18:38:21 +00:00
Anthony Williams
f827709d42 add support for relative timeouts to condition timed_wait
[SVN r41413]
2007-11-27 14:24:29 +00:00
Anthony Williams
36abb42175 reverted accidental checkin of new timed_wait functions on condition_variable
[SVN r41405]
2007-11-26 21:15:04 +00:00
Anthony Williams
40f3b1b4c8 once_flag uses zero-initialization on POSIX as well as windows
[SVN r41401]
2007-11-26 17:01:08 +00:00
Anthony Williams
4f35e25688 fixed import/export declarations so new once code works with pthread-win32
[SVN r41398]
2007-11-26 15:44:07 +00:00
Anthony Williams
270e88edd7 Don't compare native_handle_t against 0 --- do appropriate checks in create_native_thread for platforms where pthread_t is not comparable
[SVN r41396]
2007-11-26 13:29:15 +00:00
Anthony Williams
5ded171247 workaround for Borland compiler
[SVN r41395]
2007-11-26 12:17:45 +00:00
101 changed files with 1647 additions and 8373 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();
{

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
@@ -10,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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,17 +3,17 @@
// once.hpp
//
// (C) Copyright 2007-8 Anthony Williams
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/config.hpp>
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
@@ -34,7 +34,7 @@ namespace boost
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
}
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
@@ -48,7 +48,7 @@ namespace boost
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
boost::uintmax_t const epoch=flag.epoch;
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
if(epoch<this_thread_epoch)
{
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
@@ -58,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));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,14 +3,14 @@
// basic_recursive_mutex.hpp
//
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2006-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <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;

View File

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

View File

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

View File

@@ -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()
{

View File

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

View File

@@ -3,7 +3,7 @@
// recursive_mutex.hpp
//
// (C) Copyright 2006-7 Anthony Williams
// (C) Copyright 2006-7 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -11,7 +11,7 @@
#include <boost/utility.hpp>
#include <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()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@
// William E. Kempf
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
@@ -13,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(&current_thread_tls_key,&tls_destructor));
}
}
boost::detail::thread_data_base* get_current_thread_data()
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
@@ -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 &current_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();
// }
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -178,9 +178,9 @@ void test_condition_wait_is_a_interruption_point()
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
boost::unit_test::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));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
@@ -89,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));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -135,9 +135,9 @@ void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
BOOST_CHECK(id==t_id);
}
boost::unit_test::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));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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