summaryrefslogtreecommitdiff
path: root/libs/thread
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
committerAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
commit1a78a62555be32868418fe52f8e330c9d0f95d5a (patch)
treed3765a80e7d3b9640ec2e930743630cd6b9fce2b /libs/thread
downloadboost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'libs/thread')
-rw-r--r--libs/thread/build/Jamfile.v2207
-rw-r--r--libs/thread/doc/Jamfile.v231
-rw-r--r--libs/thread/doc/acknowledgements.qbk23
-rw-r--r--libs/thread/doc/barrier.qbk72
-rw-r--r--libs/thread/doc/changes.qbk144
-rw-r--r--libs/thread/doc/compliance.qbk100
-rw-r--r--libs/thread/doc/condition_variables.qbk513
-rw-r--r--libs/thread/doc/future_ref.qbk968
-rwxr-xr-xlibs/thread/doc/futures.qbk187
-rw-r--r--libs/thread/doc/index.html12
-rw-r--r--libs/thread/doc/mutex_concepts.qbk1138
-rw-r--r--libs/thread/doc/mutexes.qbk224
-rw-r--r--libs/thread/doc/once.qbk65
-rw-r--r--libs/thread/doc/overview.qbk30
-rw-r--r--libs/thread/doc/shared_mutex_ref.qbk44
-rw-r--r--libs/thread/doc/thread.qbk170
-rw-r--r--libs/thread/doc/thread_ref.qbk1167
-rw-r--r--libs/thread/doc/time.qbk75
-rw-r--r--libs/thread/doc/tss.qbk189
-rw-r--r--libs/thread/example/Jamfile.v223
-rw-r--r--libs/thread/example/condition.cpp89
-rw-r--r--libs/thread/example/monitor.cpp112
-rw-r--r--libs/thread/example/mutex.cpp47
-rw-r--r--libs/thread/example/once.cpp31
-rw-r--r--libs/thread/example/recursive_mutex.cpp49
-rw-r--r--libs/thread/example/starvephil.cpp185
-rw-r--r--libs/thread/example/tennis.cpp135
-rw-r--r--libs/thread/example/thread.cpp35
-rw-r--r--libs/thread/example/thread_group.cpp25
-rw-r--r--libs/thread/example/tss.cpp36
-rw-r--r--libs/thread/example/xtime.cpp16
-rw-r--r--libs/thread/index.html13
-rw-r--r--libs/thread/src/pthread/once.cpp53
-rw-r--r--libs/thread/src/pthread/thread.cpp606
-rw-r--r--libs/thread/src/pthread/timeconv.inl132
-rw-r--r--libs/thread/src/tss_null.cpp38
-rw-r--r--libs/thread/src/win32/thread.cpp633
-rw-r--r--libs/thread/src/win32/timeconv.inl130
-rw-r--r--libs/thread/src/win32/tss_dll.cpp76
-rw-r--r--libs/thread/src/win32/tss_pe.cpp284
-rw-r--r--libs/thread/test/Carbon.r18
-rw-r--r--libs/thread/test/Jamfile.v290
-rw-r--r--libs/thread/test/condition_test_common.hpp97
-rw-r--r--libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp15
-rw-r--r--libs/thread/test/no_implicit_move_from_lvalue_thread.cpp14
-rw-r--r--libs/thread/test/shared_mutex_locking_thread.hpp132
-rw-r--r--libs/thread/test/test.mcpbin0 -> 3675 bytes
-rw-r--r--libs/thread/test/test_2501.cpp10
-rw-r--r--libs/thread/test/test_4521.cpp21
-rw-r--r--libs/thread/test/test_4648.cpp42
-rw-r--r--libs/thread/test/test_4882.cpp50
-rw-r--r--libs/thread/test/test_5351.cpp45
-rw-r--r--libs/thread/test/test_5502.cpp86
-rw-r--r--libs/thread/test/test_5542_1.cpp62
-rw-r--r--libs/thread/test/test_5542_2.cpp11
-rw-r--r--libs/thread/test/test_5542_3.cpp30
-rw-r--r--libs/thread/test/test_6130.cpp22
-rw-r--r--libs/thread/test/test_6170.cpp26
-rw-r--r--libs/thread/test/test_6174.cpp35
-rw-r--r--libs/thread/test/test_barrier.cpp66
-rw-r--r--libs/thread/test/test_condition.cpp190
-rw-r--r--libs/thread/test/test_condition_notify_all.cpp222
-rw-r--r--libs/thread/test/test_condition_notify_one.cpp155
-rw-r--r--libs/thread/test/test_condition_timed_wait_times_out.cpp173
-rw-r--r--libs/thread/test/test_futures.cpp1220
-rw-r--r--libs/thread/test/test_generic_locks.cpp594
-rw-r--r--libs/thread/test/test_hardware_concurrency.cpp21
-rw-r--r--libs/thread/test/test_lock_concept.cpp570
-rw-r--r--libs/thread/test/test_move_function.cpp145
-rw-r--r--libs/thread/test/test_mutex.cpp347
-rw-r--r--libs/thread/test/test_once.cpp191
-rw-r--r--libs/thread/test/test_shared_mutex.cpp285
-rw-r--r--libs/thread/test/test_shared_mutex_part_2.cpp299
-rw-r--r--libs/thread/test/test_shared_mutex_timed_locks.cpp268
-rw-r--r--libs/thread/test/test_thread.cpp234
-rw-r--r--libs/thread/test/test_thread_exit.cpp73
-rw-r--r--libs/thread/test/test_thread_id.cpp149
-rw-r--r--libs/thread/test/test_thread_launching.cpp226
-rw-r--r--libs/thread/test/test_thread_mf.cpp134
-rw-r--r--libs/thread/test/test_thread_move.cpp56
-rw-r--r--libs/thread/test/test_thread_move_return.cpp35
-rw-r--r--libs/thread/test/test_thread_return_local.cpp35
-rw-r--r--libs/thread/test/test_tss.cpp359
-rw-r--r--libs/thread/test/test_xtime.cpp109
-rw-r--r--libs/thread/test/util.inl183
-rw-r--r--libs/thread/tutorial/bounded_buffer.cpp69
-rw-r--r--libs/thread/tutorial/counter.cpp28
-rw-r--r--libs/thread/tutorial/factorial.cpp32
-rw-r--r--libs/thread/tutorial/factorial2.cpp32
-rw-r--r--libs/thread/tutorial/factorial3.cpp36
-rw-r--r--libs/thread/tutorial/helloworld.cpp19
-rw-r--r--libs/thread/tutorial/helloworld2.cpp24
-rw-r--r--libs/thread/tutorial/helloworld3.cpp20
-rw-r--r--libs/thread/tutorial/helloworld4.cpp20
-rw-r--r--libs/thread/tutorial/once.cpp31
-rw-r--r--libs/thread/tutorial/tss.cpp36
96 files changed, 15599 insertions, 0 deletions
diff --git a/libs/thread/build/Jamfile.v2 b/libs/thread/build/Jamfile.v2
new file mode 100644
index 0000000000..af14ccd06e
--- /dev/null
+++ b/libs/thread/build/Jamfile.v2
@@ -0,0 +1,207 @@
+# $Id: Jamfile.v2 66171 2010-10-25 07:52:02Z vladimir_prus $
+# Copyright 2006-2007 Roland Schwarz.
+# Copyright 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)
+
+#########################################################################
+# The boost threading library can be built on top of different API's
+# Currently this is the win32 API and the pthreads API.
+# Pthread is native on unix variants.
+# To get pthread on windows you need the pthread win32 library
+# http://sourceware.org/pthreads-win32 which is available under LGPL.
+#
+# You need to provide the include path and lib path in the variables
+# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
+# paths in site-config.jam, user-config.jam or in the environment.
+# A new feature is provided to request a specific API:
+# <threadapi>win32 and <threadapi)pthread.
+#
+# The naming of the resulting libraries is mostly the same for the
+# variant native to the build platform, i.e.
+# boost_thread and the boost specific tagging.
+# For the library variant that is not native on the build platform
+# an additional tag is applied:
+# boost_thread_pthread for the pthread variant on windows, and
+# boost_thread_win32 for the win32 variant (likely when built on cygwin).
+#
+# To request the pthread variant on windows, from boost root you would
+# say e.g:
+# bjam msvc-8.0 --with-thread install threadapi=pthread
+#########################################################################
+
+import os ;
+import feature ;
+import indirect ;
+import path ;
+
+project boost/thread
+ : source-location ../src
+ : requirements <threading>multi
+ <link>static:<define>BOOST_THREAD_BUILD_LIB=1
+ <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
+ ;
+
+local rule default_threadapi ( )
+{
+ local api = pthread ;
+ if [ os.name ] = "NT" { api = win32 ; }
+ return $(api) ;
+}
+
+feature.feature threadapi : pthread win32 : propagated ;
+feature.set-default threadapi : [ default_threadapi ] ;
+
+rule tag ( name : type ? : property-set )
+{
+ local result = $(name) ;
+
+ if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB
+ {
+ local api = [ $(property-set).get <threadapi> ] ;
+
+ # non native api gets additional tag
+ if $(api) != [ default_threadapi ] {
+ result = $(result)_$(api) ;
+ }
+ }
+
+ # forward to the boost tagging rule
+ return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
+ $(result) : $(type) : $(property-set) ] ;
+}
+
+rule win32_pthread_paths ( properties * )
+{
+ local result ;
+ local PTW32_INCLUDE ;
+ local PTW32_LIB ;
+ PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
+ PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
+ PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
+ PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
+ PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
+ PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
+
+ if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
+ {
+ if ! $(.notified)
+ {
+ echo "************************************************************" ;
+ echo "Trying to build Boost.Thread with pthread support." ;
+ echo "If you need pthread you should specify the paths." ;
+ echo "You can specify them in site-config.jam, user-config.jam" ;
+ echo "or in the environment." ;
+ echo "For example:" ;
+ echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
+ echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
+ echo "************************************************************" ;
+ .notified = true ;
+ }
+ }
+ else
+ {
+ local include_path = [ path.make $(PTW32_INCLUDE) ] ;
+ local lib_path = [ path.make $(PTW32_LIB) ] ;
+ local libname = pthread ;
+ if <toolset>msvc in $(properties)
+ {
+ libname = $(libname)VC2.lib ;
+ }
+ if <toolset>gcc in $(properties)
+ {
+ libname = lib$(libname)GC2.a ;
+ }
+ lib_path = [ path.glob $(lib_path) : $(libname) ] ;
+ if ! $(lib_path)
+ {
+ if ! $(.notified)
+ {
+ echo "************************************************************" ;
+ echo "Trying to build Boost.Thread with pthread support." ;
+ echo "But the library" $(libname) "could not be found in path" ;
+ echo $(PTW32_LIB) ;
+ echo "************************************************************" ;
+ .notified = true ;
+ }
+ }
+ else
+ {
+ result += <include>$(include_path) ;
+ result += <library>$(lib_path) ;
+ }
+ }
+ return $(result) ;
+}
+
+rule usage-requirements ( properties * )
+{
+ local result ;
+ if <threadapi>pthread in $(properties)
+ {
+ result += <define>BOOST_THREAD_POSIX ;
+ if <target-os>windows in $(properties)
+ {
+ result += [ win32_pthread_paths $(properties) ] ;
+ # TODO: What is for static linking? Is the <library> also needed
+ # in that case?
+ }
+ }
+ return $(result) ;
+}
+
+rule requirements ( properties * )
+{
+ local result ;
+
+ if <threadapi>pthread in $(properties)
+ {
+ result += <define>BOOST_THREAD_POSIX ;
+ if <target-os>windows in $(properties)
+ {
+ local paths = [ win32_pthread_paths $(properties) ] ;
+ if $(paths)
+ {
+ result += $(paths) ;
+ }
+ else
+ {
+ result = <build>no ;
+ }
+ }
+ }
+ return $(result) ;
+}
+
+alias thread_sources
+ : ## win32 sources ##
+ win32/thread.cpp
+ win32/tss_dll.cpp
+ win32/tss_pe.cpp
+ : ## requirements ##
+ <threadapi>win32
+ ;
+
+alias thread_sources
+ : ## pthread sources ##
+ pthread/thread.cpp
+ pthread/once.cpp
+ : ## requirements ##
+ <threadapi>pthread
+ ;
+
+explicit thread_sources ;
+
+lib boost_thread
+ : thread_sources
+ : <conditional>@requirements
+ :
+ : <link>shared:<define>BOOST_THREAD_USE_DLL=1
+ <link>static:<define>BOOST_THREAD_USE_LIB=1
+ <conditional>@usage-requirements
+ ;
diff --git a/libs/thread/doc/Jamfile.v2 b/libs/thread/doc/Jamfile.v2
new file mode 100644
index 0000000000..9e5f8e3f5b
--- /dev/null
+++ b/libs/thread/doc/Jamfile.v2
@@ -0,0 +1,31 @@
+# (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)
+
+path-constant boost-images : ../../../doc/src/images ;
+
+xml thread : thread.qbk ;
+
+boostbook standalone
+ :
+ thread
+ :
+ # HTML options first:
+ # Use graphics not text for navigation:
+ <xsl:param>navig.graphics=1
+ # How far down we chunk nested sections, basically all of them:
+ <xsl:param>chunk.section.depth=3
+ # Don't put the first section on the same page as the TOC:
+ <xsl:param>chunk.first.sections=1
+ # How far down sections get TOC's
+ <xsl:param>toc.section.depth=10
+ # Max depth in each TOC:
+ <xsl:param>toc.max.depth=3
+ # How far down we go with TOC's
+ <xsl:param>generate.section.toc.level=10
+ # Path for links to Boost:
+ <xsl:param>boost.root=../../../..
+ ;
+
+
diff --git a/libs/thread/doc/acknowledgements.qbk b/libs/thread/doc/acknowledgements.qbk
new file mode 100644
index 0000000000..1f21921fa4
--- /dev/null
+++ b/libs/thread/doc/acknowledgements.qbk
@@ -0,0 +1,23 @@
+[/
+ (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
+version initially grew out of an attempt to rewrite __boost_thread__ to William Kempf's design with fresh code that could be
+released under the Boost Software License. However, as the C++ Standards committee have been actively discussing standardizing a
+thread library for C++, this library has evolved to reflect the proposals, whilst retaining as much backwards-compatibility as
+possible.
+
+Particular thanks must be given to Roland Schwarz, who contributed a lot of time and code to the original __boost_thread__ library,
+and who has been actively involved with the rewrite. The scheme for dividing the platform-specific implementations into separate
+directories was devised by Roland, and his input has contributed greatly to improving the quality of the current implementation.
+
+Thanks also must go to Peter Dimov, Howard Hinnant, Alexander Terekhov, Chris Thomasson and others for their comments on the
+implementation details of the code.
+
+[endsect]
diff --git a/libs/thread/doc/barrier.qbk b/libs/thread/doc/barrier.qbk
new file mode 100644
index 0000000000..7e7c3e122b
--- /dev/null
+++ b/libs/thread/doc/barrier.qbk
@@ -0,0 +1,72 @@
+[/
+ (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
+configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have
+arrived. Once the `n`-th thread has reached the barrier, all the waiting threads can proceed, and the barrier is reset.
+
+[section:barrier Class `barrier`]
+
+ #include <boost/thread/barrier.hpp>
+
+ class barrier
+ {
+ public:
+ barrier(unsigned int count);
+ ~barrier();
+
+ bool wait();
+ };
+
+Instances of __barrier__ are not copyable or movable.
+
+[heading Constructor]
+
+ barrier(unsigned int count);
+
+[variablelist
+
+[[Effects:] [Construct a barrier for `count` threads.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+[heading Destructor]
+
+ ~barrier();
+
+[variablelist
+
+[[Precondition:] [No threads are waiting on `*this`.]]
+
+[[Effects:] [Destroys `*this`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[heading Member function `wait`]
+
+ bool wait();
+
+[variablelist
+
+[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads
+are unblocked, and the barrier is reset. ]]
+
+[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+[endsect]
+
+[endsect]
diff --git a/libs/thread/doc/changes.qbk b/libs/thread/doc/changes.qbk
new file mode 100644
index 0000000000..809ed89749
--- /dev/null
+++ b/libs/thread/doc/changes.qbk
@@ -0,0 +1,144 @@
+[/
+ (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]
+
+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
+changes are described below.
+
+[heading New Features]
+
+* Instances of __thread__ and of the various lock types are now movable.
+
+* Threads can be interrupted at __interruption_points__.
+
+* Condition variables can now be used with any type that implements the __lockable_concept__, through the use of
+`boost::condition_variable_any` (`boost::condition` is a `typedef` to `boost::condition_variable_any`, provided for backwards
+compatibility). `boost::condition_variable` is provided as an optimization, and will only work with
+`boost::unique_lock<boost::mutex>` (`boost::mutex::scoped_lock`).
+
+* Thread IDs are separated from __thread__, so a thread can obtain it's own ID (using `boost::this_thread::get_id()`), and IDs can
+be used as keys in associative containers, as they have the full set of comparison operators.
+
+* Timeouts are now implemented using the Boost DateTime library, through a typedef `boost::system_time` for absolute timeouts, and
+with support for relative timeouts in many cases. `boost::xtime` is supported for backwards compatibility only.
+
+* Locks are implemented as publicly accessible templates `boost::lock_guard`, `boost::unique_lock`, `boost::shared_lock`, and
+`boost::upgrade_lock`, which are templated on the type of the mutex. The __lockable_concept__ has been extended to include publicly
+available __lock_ref__ and __unlock_ref__ member functions, which are used by the lock types.
+
+[heading Breaking Changes]
+
+The list below should cover all changes to the public interface which break backwards compatibility.
+
+* __try_mutex__ has been removed, and the functionality subsumed into __mutex__. __try_mutex__ is left as a `typedef`,
+but is no longer a separate class.
+
+* __recursive_try_mutex__ has been removed, and the functionality subsumed into
+__recursive_mutex__. __recursive_try_mutex__ is left as a `typedef`, but is no longer a separate class.
+
+* `boost::detail::thread::lock_ops` has been removed. Code that relies on the `lock_ops` implementation detail will no longer work,
+as this has been removed, as it is no longer necessary now that mutex types now have public __lock_ref__ and __unlock_ref__ member
+functions.
+
+* `scoped_lock` constructors with a second parameter of type `bool` are no longer provided. With previous boost releases,
+``boost::mutex::scoped_lock some_lock(some_mutex,false);`` could be used to create a lock object that was associated with a mutex,
+but did not lock it on construction. This facility has now been replaced with the constructor that takes a
+`boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);``
+
+* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__.
+
+* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not
+associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has
+been moved to __thread_id__.
+
+* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__.
+
+* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
+
+* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
+ unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
+
+[endsect]
+
+[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]
+
diff --git a/libs/thread/doc/compliance.qbk b/libs/thread/doc/compliance.qbk
new file mode 100644
index 0000000000..2bf923ebd7
--- /dev/null
+++ b/libs/thread/doc/compliance.qbk
@@ -0,0 +1,100 @@
+[/
+ (C) Copyright 2011 Vicente J. Botet Escriba.
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt).
+]
+
+[section:compliance Compliance with standard]
+
+[section:cpp11 C++11 standard Thread library]
+
+
+[table Compliance C++11 standard
+ [[Section] [Description] [Status] [Comments] [Ticket]]
+ [[30] [Thread support library] [Partial] [-] [-]]
+ [[30.1] [General] [-] [-] [-]]
+ [[30.2] [Requirements] [-] [-] [-]]
+ [[30.2.1] [Template parameter names] [-] [-] [-]]
+ [[30.2.2] [Exceptions] [No] [-] [#12]]
+ [[30.2.3] [Native handles] [Yes] [-] [-]]
+ [[30.2.4] [Timing specifications] [No] [-] [#6195]]
+ [[30.2.5] [Requirements for Lockable types] [Partial] [-] [-]]
+ [[30.2.5.1] [In general] [-] [-] [-]]
+ [[30.2.5.2] [BasicLockable requirements] [No] [-] [#13]]
+ [[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
+ [[30.2.5.4] [TimedLockable requirements] [Partial] [chrono] [#6195]]
+ [[30.2.6] [decay_copy] [-] [-] [-]]
+ [[30.3] [Threads] [Partial] [-] [-]]
+ [[30.3.1] [Class thread] [Partial] [-] [-]]
+ [[30.3.1.1] [Class thread::id] [Partial] [Missing noexcept, template <> struct hash<thread::id>] [#3,#4]]
+ [[30.3.1.2] [thread constructors] [Partial] [Missing noexcept and move semantics] [#3,#6194]]
+ [[30.3.1.3] [thread destructor] [Yes] [-] [-]]
+ [[30.3.1.4] [thread assignment] [Partial] [move semantics] [-]]
+ [[30.3.1.5] [thread members] [Partial] [Missing noexcept, chrono] [#3,#6195]]
+ [[30.3.1.6] [thread static members] [Partial] [Missing noexcept] [#3,#6195]]
+ [[30.3.1.7] [thread specialized algorithms] [Yes] [-] [-]]
+ [[30.3.2] [Namespace this_thread] [Partial] [chrono] [#6195]]
+ [[30.4] [Mutual exclusion] [Partial] [-] [-]]
+ [[30.4.1] [Mutex requirements] [Partial] [-] [-]]
+ [[30.4.1.1] [In general] [Partial] [-] [-]]
+ [[30.4.1.2] [Mutex types] [Partial] [noexcept,delete] [#3,#5]]
+ [[30.4.1.2.1] [Class mutex] [Partial] [noexcept,delete] [#3,#5]]
+ [[30.4.1.2.2] [Class recursive_mutex] [Partial] [noexcept,delete] [#3,#5]]
+ [[30.4.1.3] [Timed mutex types] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
+ [[30.4.1.3.1] [Class timed_mutex] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
+ [[30.4.1.3.1] [Class recursive_timed_mutex] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
+ [[30.4.2] [Locks] [Partial] [noexcept,chrono,move,delete,bool] [#3,#6195,#5,#6]]
+ [[30.4.2.1] [Class template lock_guard] [Partial] [cons/dest delete] [#5]]
+ [[30.4.2.2] [Class template unique_lock] [Partial] [noexcept, chrono, move, delete] [#3,#6195,#5,#6]]
+ [[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Partial] [noexcept, chrono, move, delete] [#3,#6195,#5,#6]]
+ [[30.4.2.2.2] [unique_lock locking] [Partial] [chrono] [,#6195,]]
+ [[30.4.2.2.3] [unique_lock modifiers] [Yes] [-] [-]]
+ [[30.4.2.2.4] [unique_lock observers] [Partial] [explicit operator bool] [#6]]
+ [[30.4.3] [Generic locking algorithms] [Partial] [Variadic,] [#7]]
+ [[30.4.4] [Call once] [Partial] [move,variadic] [#6194,#7]]
+ [[30.4.4.1] [Struct once_flag] [Yes] [-] [-]]
+ [[30.4.4.2] [Function call_once] [Yes] [-] [-]]
+ [[30.5] [Condition variables] [Partial] [chrono,cv_status,notify_all_at_thread_exit] [#6195,#8,#9]]
+ [[30.5 6-10] [Function notify_all_at_thread_exit] [No] [-] [#9]]
+ [[30.5.1] [Class condition_variable] [Partial] [chrono,cv_status] [#6195,#8]]
+ [[30.5.2] [Class condition_variable_any] [Partial] [chrono,cv_status] [#6195,#8]]
+ [[30.6] [Futures] [Partial] [-] [-]]
+ [[30.6.1] [Overview] [Partial] [-] [-]]
+ [[30.6.2] [Error handling] [No] [-] [-]]
+ [[30.6.3] [Class future_error] [No] [-] [-]]
+ [[30.6.4] [Shared state] [No] [-] [-]]
+ [[30.6.5] [Class template promise] [Partial] [allocator,move,delete] [#10,#6194,#5]]
+ [[30.6.6] [Class template future] [No] [unique_future is the closest to future] [#11]]
+ [[30.6.7] [Class template shared_future] [Partial] [allocator,move,delete] [#10,#6194,#5]]
+ [[30.6.8] [Function template async] [No] [async] [#4710]]
+ [[30.6.8] [Class template packaged_task] [Partial] [-] [-]]
+]
+
+
+[table Extension
+ [[Section] [Description] [Comments]]
+ [[30.3.1.5.x] [interrupt] [-]]
+ [[30.3.1.5.y] [operator==,operator!=] [-]]
+ [[30.3.2.x] [Interruprion] [-]]
+ [[30.3.2.y] [at_thread_exit] [-]]
+ [[30.4.3.x] [Generic locking algorithms begin/end] [-]]
+ [[30.x] [Barriers] [-]]
+ [[30.y] [Thread Local Storage] [-]]
+ [[30.z] [Class thread_group] [-]]
+]
+
+[endsect]
+
+[section:shared Shared Mutex library extension]
+
+[table Clock Requirements
+ [[Section] [Description] [Status] [Comments]]
+ [[XXXX] [DDDD] [SSSS] [CCCC]]
+ [[XXXX] [DDDD] [SSSS] [CCCC]]
+]
+
+[endsect]
+
+
+[endsect]
diff --git a/libs/thread/doc/condition_variables.qbk b/libs/thread/doc/condition_variables.qbk
new file mode 100644
index 0000000000..e54dd34cc0
--- /dev/null
+++ b/libs/thread/doc/condition_variables.qbk
@@ -0,0 +1,513 @@
+[/
+ (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]
+
+The classes `condition_variable` and `condition_variable_any` provide a
+mechanism for one thread to wait for notification from another thread that a
+particular condition has become true. The general usage pattern is that one
+thread locks a mutex and then calls `wait` on an instance of
+`condition_variable` or `condition_variable_any`. When the thread is woken from
+the wait, then it checks to see if the appropriate condition is now true, and
+continues if so. If the condition is not true, then the thread then calls `wait`
+again to resume waiting. In the simplest case, this condition is just a boolean
+variable:
+
+ boost::condition_variable cond;
+ boost::mutex mut;
+ bool data_ready;
+
+ void process_data();
+
+ void wait_for_data_to_process()
+ {
+ boost::unique_lock<boost::mutex> lock(mut);
+ while(!data_ready)
+ {
+ cond.wait(lock);
+ }
+ process_data();
+ }
+
+Notice that the `lock` is passed to `wait`: `wait` will atomically add the
+thread to the set of threads waiting on the condition variable, and unlock the
+mutex. When the thread is woken, the mutex will be locked again before the call
+to `wait` returns. This allows other threads to acquire the mutex in order to
+update the shared data, and ensures that the data associated with the condition
+is correctly synchronized.
+
+In the mean time, another thread sets the condition to `true`, and then calls
+either `notify_one` or `notify_all` on the condition variable to wake one
+waiting thread or all the waiting threads respectively.
+
+ void retrieve_data();
+ void prepare_data();
+
+ void prepare_data_for_processing()
+ {
+ retrieve_data();
+ prepare_data();
+ {
+ boost::lock_guard<boost::mutex> lock(mut);
+ data_ready=true;
+ }
+ cond.notify_one();
+ }
+
+Note that the same mutex is locked before the shared data is updated, but that
+the mutex does not have to be locked across the call to `notify_one`.
+
+This example uses an object of type `condition_variable`, but would work just as
+well with an object of type `condition_variable_any`: `condition_variable_any`
+is more general, and will work with any kind of lock or mutex, whereas
+`condition_variable` requires that the lock passed to `wait` is an instance of
+`boost::unique_lock<boost::mutex>`. This enables `condition_variable` to make
+optimizations in some cases, based on the knowledge of the mutex type;
+`condition_variable_any` typically has a more complex implementation than
+`condition_variable`.
+
+[section:condition_variable Class `condition_variable`]
+
+ #include <boost/thread/condition_variable.hpp>
+
+ namespace boost
+ {
+ class condition_variable
+ {
+ public:
+ condition_variable();
+ ~condition_variable();
+
+ void notify_one();
+ void notify_all();
+
+ void wait(boost::unique_lock<boost::mutex>& lock);
+
+ template<typename predicate_type>
+ void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);
+
+ bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
+
+ template<typename duration_type>
+ bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
+
+ template<typename predicate_type>
+ bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
+
+ template<typename duration_type,typename predicate_type>
+ bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
+
+ // backwards compatibility
+
+ bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);
+
+ template<typename predicate_type>
+ bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
+ };
+ }
+
+[section:constructor `condition_variable()`]
+
+[variablelist
+
+[[Effects:] [Constructs an object of class `condition_variable`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+[endsect]
+
+[section:destructor `~condition_variable()`]
+
+[variablelist
+
+[[Precondition:] [All threads waiting on `*this` have been notified by a call to
+`notify_one` or `notify_all` (though the respective calls to `wait` or
+`timed_wait` need not have returned).]]
+
+[[Effects:] [Destroys the object.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:notify_one `void notify_one()`]
+
+[variablelist
+
+[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
+to `wait` or `timed_wait`, unblocks one of those threads.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:notify_all `void notify_all()`]
+
+[variablelist
+
+[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
+to `wait` or `timed_wait`, unblocks all of those threads.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:wait `void wait(boost::unique_lock<boost::mutex>& lock)`]
+
+[variablelist
+
+[[Precondition:] [`lock` is locked by the current thread, and either no other
+thread is currently waiting on `*this`, or the execution of the `mutex()` member
+function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
+in all the threads currently waiting on `*this` would return the same value as
+`lock->mutex()` for this call to `wait`.]]
+
+[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
+thread will unblock when notified by a call to `this->notify_one()` or
+`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
+reason), the lock is reacquired by invoking `lock.lock()` before the call to
+`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
+function exits with an exception.]]
+
+[[Postcondition:] [`lock` is locked by the current thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error
+occurs. __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+
+]
+
+[endsect]
+
+[section:wait_predicate `template<typename predicate_type> void wait(boost::unique_lock<boost::mutex>& lock, predicate_type pred)`]
+
+[variablelist
+
+[[Effects:] [As-if ``
+while(!pred())
+{
+ wait(lock);
+}
+``]]
+
+]
+
+[endsect]
+
+[section:timed_wait `bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time)`]
+
+[variablelist
+
+[[Precondition:] [`lock` is locked by the current thread, and either no other
+thread is currently waiting on `*this`, or the execution of the `mutex()` member
+function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
+in all the threads currently waiting on `*this` would return the same value as
+`lock->mutex()` for this call to `wait`.]]
+
+[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
+thread will unblock when notified by a call to `this->notify_one()` or
+`this->notify_all()`, when the time as reported by `boost::get_system_time()`
+would be equal to or later than the specified `abs_time`, or spuriously. When
+the thread is unblocked (for whatever reason), the lock is reacquired by
+invoking `lock.lock()` before the call to `wait` returns. The lock is also
+reacquired by invoking `lock.lock()` if the function exits with an exception.]]
+
+[[Returns:] [`false` if the call is returning because the time specified by
+`abs_time` was reached, `true` otherwise.]]
+
+[[Postcondition:] [`lock` is locked by the current thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error
+occurs. __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+
+]
+
+[endsect]
+
+[section:timed_wait_rel `template<typename duration_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time)`]
+
+[variablelist
+
+[[Precondition:] [`lock` is locked by the current thread, and either no other
+thread is currently waiting on `*this`, or the execution of the `mutex()` member
+function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
+in all the threads currently waiting on `*this` would return the same value as
+`lock->mutex()` for this call to `wait`.]]
+
+[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
+thread will unblock when notified by a call to `this->notify_one()` or
+`this->notify_all()`, after the period of time indicated by the `rel_time`
+argument has elapsed, or spuriously. When the thread is unblocked (for whatever
+reason), the lock is reacquired by invoking `lock.lock()` before the call to
+`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
+function exits with an exception.]]
+
+[[Returns:] [`false` if the call is returning because the time period specified
+by `rel_time` has elapsed, `true` otherwise.]]
+
+[[Postcondition:] [`lock` is locked by the current thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error
+occurs. __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+
+]
+
+[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
+
+[endsect]
+
+[section:timed_wait_predicate `template<typename predicate_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock, boost::system_time const& abs_time, predicate_type pred)`]
+
+[variablelist
+
+[[Effects:] [As-if ``
+while(!pred())
+{
+ if(!timed_wait(lock,abs_time))
+ {
+ return pred();
+ }
+}
+return true;
+``]]
+
+]
+
+[endsect]
+
+
+[endsect]
+
+[section:condition_variable_any Class `condition_variable_any`]
+
+ #include <boost/thread/condition_variable.hpp>
+
+ namespace boost
+ {
+ class condition_variable_any
+ {
+ public:
+ condition_variable_any();
+ ~condition_variable_any();
+
+ void notify_one();
+ void notify_all();
+
+ template<typename lock_type>
+ void wait(lock_type& lock);
+
+ template<typename lock_type,typename predicate_type>
+ void wait(lock_type& lock,predicate_type predicate);
+
+ template<typename lock_type>
+ bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
+
+ template<typename lock_type,typename duration_type>
+ bool timed_wait(lock_type& lock,duration_type const& rel_time);
+
+ template<typename lock_type,typename predicate_type>
+ bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
+
+ template<typename lock_type,typename duration_type,typename predicate_type>
+ bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
+
+ // backwards compatibility
+
+ template<typename lock_type>
+ bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
+
+ template<typename lock_type,typename predicate_type>
+ bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
+ };
+ }
+
+[section:constructor `condition_variable_any()`]
+
+[variablelist
+
+[[Effects:] [Constructs an object of class `condition_variable_any`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+[endsect]
+
+[section:destructor `~condition_variable_any()`]
+
+[variablelist
+
+[[Precondition:] [All threads waiting on `*this` have been notified by a call to
+`notify_one` or `notify_all` (though the respective calls to `wait` or
+`timed_wait` need not have returned).]]
+
+[[Effects:] [Destroys the object.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:notify_one `void notify_one()`]
+
+[variablelist
+
+[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
+to `wait` or `timed_wait`, unblocks one of those threads.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:notify_all `void notify_all()`]
+
+[variablelist
+
+[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
+to `wait` or `timed_wait`, unblocks all of those threads.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:wait `template<typename lock_type> void wait(lock_type& lock)`]
+
+[variablelist
+
+[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
+thread will unblock when notified by a call to `this->notify_one()` or
+`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
+reason), the lock is reacquired by invoking `lock.lock()` before the call to
+`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
+function exits with an exception.]]
+
+[[Postcondition:] [`lock` is locked by the current thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error
+occurs. __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+
+]
+
+[endsect]
+
+[section:wait_predicate `template<typename lock_type,typename predicate_type> void wait(lock_type& lock, predicate_type pred)`]
+
+[variablelist
+
+[[Effects:] [As-if ``
+while(!pred())
+{
+ wait(lock);
+}
+``]]
+
+]
+
+[endsect]
+
+[section:timed_wait `template<typename lock_type> bool timed_wait(lock_type& lock,boost::system_time const& abs_time)`]
+
+[variablelist
+
+[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
+thread will unblock when notified by a call to `this->notify_one()` or
+`this->notify_all()`, when the time as reported by `boost::get_system_time()`
+would be equal to or later than the specified `abs_time`, or spuriously. When
+the thread is unblocked (for whatever reason), the lock is reacquired by
+invoking `lock.lock()` before the call to `wait` returns. The lock is also
+reacquired by invoking `lock.lock()` if the function exits with an exception.]]
+
+[[Returns:] [`false` if the call is returning because the time specified by
+`abs_time` was reached, `true` otherwise.]]
+
+[[Postcondition:] [`lock` is locked by the current thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error
+occurs. __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+
+]
+
+[endsect]
+
+[section:timed_wait_rel `template<typename lock_type,typename duration_type> bool timed_wait(lock_type& lock,duration_type const& rel_time)`]
+
+[variablelist
+
+[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
+thread will unblock when notified by a call to `this->notify_one()` or
+`this->notify_all()`, after the period of time indicated by the `rel_time`
+argument has elapsed, or spuriously. When the thread is unblocked (for whatever
+reason), the lock is reacquired by invoking `lock.lock()` before the call to
+`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
+function exits with an exception.]]
+
+[[Returns:] [`false` if the call is returning because the time period specified
+by `rel_time` has elapsed, `true` otherwise.]]
+
+[[Postcondition:] [`lock` is locked by the current thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error
+occurs. __thread_interrupted__ if the wait was interrupted by a call to
+__interrupt__ on the __thread__ object associated with the current thread of execution.]]
+
+]
+
+[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
+
+[endsect]
+
+[section:timed_wait_predicate `template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& lock, boost::system_time const& abs_time, predicate_type pred)`]
+
+[variablelist
+
+[[Effects:] [As-if ``
+while(!pred())
+{
+ if(!timed_wait(lock,abs_time))
+ {
+ return pred();
+ }
+}
+return true;
+``]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[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.
+
+[endsect]
+
+[endsect]
diff --git a/libs/thread/doc/future_ref.qbk b/libs/thread/doc/future_ref.qbk
new file mode 100644
index 0000000000..219619ca8e
--- /dev/null
+++ b/libs/thread/doc/future_ref.qbk
@@ -0,0 +1,968 @@
+[/
+ (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]
diff --git a/libs/thread/doc/futures.qbk b/libs/thread/doc/futures.qbk
new file mode 100755
index 0000000000..a4e123f453
--- /dev/null
+++ b/libs/thread/doc/futures.qbk
@@ -0,0 +1,187 @@
+[/
+ (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] \ No newline at end of file
diff --git a/libs/thread/doc/index.html b/libs/thread/doc/index.html
new file mode 100644
index 0000000000..4d1b5db3b2
--- /dev/null
+++ b/libs/thread/doc/index.html
@@ -0,0 +1,12 @@
+<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
+ Subject to the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+-->
+<html>
+<head>
+<meta http-equiv="refresh" content="0; URL=../../../doc/html/thread.html">
+</head>
+<body>
+Automatic redirection failed, please go to <a href="../../../doc/html/thread.html">../../../doc/html/thread.html</a>
+</body>
+</html>
diff --git a/libs/thread/doc/mutex_concepts.qbk b/libs/thread/doc/mutex_concepts.qbk
new file mode 100644
index 0000000000..dd3aba79d4
--- /dev/null
+++ b/libs/thread/doc/mutex_concepts.qbk
@@ -0,0 +1,1138 @@
+[/
+ (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
+obtains ownership of a mutex object by calling one of the lock functions and relinquishes ownership by calling the corresponding
+unlock function. Mutexes may be either recursive or non-recursive, and may grant simultaneous ownership to one or many
+threads. __boost_thread__ supplies recursive and non-recursive mutexes with exclusive ownership semantics, along with a shared
+ownership (multiple-reader / single-writer) mutex.
+
+__boost_thread__ supports four basic concepts for lockable objects: __lockable_concept_type__, __timed_lockable_concept_type__,
+__shared_lockable_concept_type__ and __upgrade_lockable_concept_type__. Each mutex type implements one or more of these concepts, as
+do the various lock types.
+
+[section:lockable `Lockable` Concept]
+
+The __lockable_concept__ models exclusive ownership. A type that implements the __lockable_concept__ shall provide the following
+member functions:
+
+* [lock_ref_link `void lock();`]
+* [try_lock_ref_link `bool try_lock();`]
+* [unlock_ref_link `void unlock();`]
+
+Lock ownership acquired through a call to __lock_ref__ or __try_lock_ref__ must be released through a call to __unlock_ref__.
+
+[section:lock `void lock()`]
+
+[variablelist
+
+[[Effects:] [The current thread blocks until ownership can be obtained for the current thread.]]
+
+[[Postcondition:] [The current thread owns `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+[endsect]
+
+[section:try_lock `bool try_lock()`]
+
+[variablelist
+
+[[Effects:] [Attempt to obtain ownership for the current thread without blocking.]]
+
+[[Returns:] [`true` if ownership was obtained for the current thread, `false` otherwise.]]
+
+[[Postcondition:] [If the call returns `true`, the current thread owns the `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+[endsect]
+
+[section:unlock `void unlock()`]
+
+[variablelist
+
+[[Precondition:] [The current thread owns `*this`.]]
+
+[[Effects:] [Releases ownership by the current thread.]]
+
+[[Postcondition:] [The current thread no longer owns `*this`.]]
+
+[[Throws:] [Nothing]]
+]
+[endsect]
+[endsect]
+
+[section:timed_lockable `TimedLockable` Concept]
+
+The __timed_lockable_concept__ refines the __lockable_concept__ to add support for
+timeouts when trying to acquire the lock.
+
+A type that implements the __timed_lockable_concept__ shall meet the requirements
+of the __lockable_concept__. In addition, the following member functions must be
+provided:
+
+* [timed_lock_ref_link `bool timed_lock(boost::system_time const& abs_time);`]
+* [timed_lock_duration_ref_link `template<typename DurationType> bool timed_lock(DurationType const& rel_time);`]
+
+Lock ownership acquired through a call to __timed_lock_ref__ must be released through a call to __unlock_ref__.
+
+[section:timed_lock `bool timed_lock(boost::system_time const& abs_time)`]
+
+[variablelist
+
+[[Effects:] [Attempt to obtain ownership for the current thread. Blocks until ownership can be obtained, or the specified time is
+reached. If the specified time has already passed, behaves as __try_lock_ref__.]]
+
+[[Returns:] [`true` if ownership was obtained for the current thread, `false` otherwise.]]
+
+[[Postcondition:] [If the call returns `true`, the current thread owns `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+]
+[endsect]
+
+[section:timed_lock_duration `template<typename DurationType> bool
+timed_lock(DurationType const& rel_time)`]
+
+[variablelist
+
+[[Effects:] [As-if [timed_lock_ref_link
+`timed_lock(boost::get_system_time()+rel_time)`].]]
+
+]
+[endsect]
+
+[endsect]
+
+[section:shared_lockable `SharedLockable` Concept]
+
+The __shared_lockable_concept__ is a refinement of the __timed_lockable_concept__ that
+allows for ['shared ownership] as well as ['exclusive ownership]. This is the
+standard multiple-reader / single-write model: at most one thread can have
+exclusive ownership, and if any thread does have exclusive ownership, no other threads
+can have shared or exclusive ownership. Alternatively, many threads may have
+shared ownership.
+
+For a type to implement the __shared_lockable_concept__, as well as meeting the
+requirements of the __timed_lockable_concept__, it must also provide the following
+member functions:
+
+* [lock_shared_ref_link `void lock_shared();`]
+* [try_lock_shared_ref_link `bool try_lock_shared();`]
+* [unlock_shared_ref_link `bool unlock_shared();`]
+* [timed_lock_shared_ref_link `bool timed_lock_shared(boost::system_time const& abs_time);`]
+
+Lock ownership acquired through a call to __lock_shared_ref__, __try_lock_shared_ref__ or __timed_lock_shared_ref__ must be released
+through a call to __unlock_shared_ref__.
+
+[section:lock_shared `void lock_shared()`]
+
+[variablelist
+
+[[Effects:] [The current thread blocks until shared ownership can be obtained for the current thread.]]
+
+[[Postcondition:] [The current thread has shared ownership of `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+[endsect]
+
+[section:try_lock_shared `bool try_lock_shared()`]
+
+[variablelist
+
+[[Effects:] [Attempt to obtain shared ownership for the current thread without blocking.]]
+
+[[Returns:] [`true` if shared ownership was obtained for the current thread, `false` otherwise.]]
+
+[[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+[endsect]
+
+[section:timed_lock_shared `bool timed_lock_shared(boost::system_time const& abs_time)`]
+
+[variablelist
+
+[[Effects:] [Attempt to obtain shared ownership for the current thread. Blocks until shared ownership can be obtained, or the
+specified time is reached. If the specified time has already passed, behaves as __try_lock_shared_ref__.]]
+
+[[Returns:] [`true` if shared ownership was acquired for the current thread, `false` otherwise.]]
+
+[[Postcondition:] [If the call returns `true`, the current thread has shared
+ownership of `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+[endsect]
+
+[section:unlock_shared `void unlock_shared()`]
+
+[variablelist
+
+[[Precondition:] [The current thread has shared ownership of `*this`.]]
+
+[[Effects:] [Releases shared ownership of `*this` by the current thread.]]
+
+[[Postcondition:] [The current thread no longer has shared ownership of `*this`.]]
+
+[[Throws:] [Nothing]]
+
+]
+[endsect]
+
+
+[endsect]
+
+[section:upgrade_lockable `UpgradeLockable` Concept]
+
+The __upgrade_lockable_concept__ is a refinement of the __shared_lockable_concept__ that allows for ['upgradable ownership] as well
+as ['shared ownership] and ['exclusive ownership]. This is an extension to the multiple-reader / single-write model provided by the
+__shared_lockable_concept__: a single thread may have ['upgradable ownership] at the same time as others have ['shared
+ownership]. The thread with ['upgradable ownership] may at any time attempt to upgrade that ownership to ['exclusive ownership]. If
+no other threads have shared ownership, the upgrade is completed immediately, and the thread now has ['exclusive ownership], which
+must be relinquished by a call to __unlock_ref__, just as if it had been acquired by a call to __lock_ref__.
+
+If a thread with ['upgradable ownership] tries to upgrade whilst other threads have ['shared ownership], the attempt will fail and
+the thread will block until ['exclusive ownership] can be acquired.
+
+Ownership can also be ['downgraded] as well as ['upgraded]: exclusive ownership of an implementation of the
+__upgrade_lockable_concept__ can be downgraded to upgradable ownership or shared ownership, and upgradable ownership can be
+downgraded to plain shared ownership.
+
+For a type to implement the __upgrade_lockable_concept__, as well as meeting the
+requirements of the __shared_lockable_concept__, it must also provide the following
+member functions:
+
+* [lock_upgrade_ref_link `void lock_upgrade();`]
+* [unlock_upgrade_ref_link `bool unlock_upgrade();`]
+* [unlock_upgrade_and_lock_ref_link `void unlock_upgrade_and_lock();`]
+* [unlock_and_lock_upgrade_ref_link `void unlock_and_lock_upgrade();`]
+* [unlock_upgrade_and_lock_shared_ref_link `void unlock_upgrade_and_lock_shared();`]
+
+Lock ownership acquired through a call to __lock_upgrade_ref__ must be released through a call to __unlock_upgrade_ref__. If the
+ownership type is changed through a call to one of the `unlock_xxx_and_lock_yyy()` functions, ownership must be released through a
+call to the unlock function corresponding to the new level of ownership.
+
+
+[section:lock_upgrade `void lock_upgrade()`]
+
+[variablelist
+
+[[Effects:] [The current thread blocks until upgrade ownership can be obtained for the current thread.]]
+
+[[Postcondition:] [The current thread has upgrade ownership of `*this`.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+[endsect]
+
+[section:unlock_upgrade `void unlock_upgrade()`]
+
+[variablelist
+
+[[Precondition:] [The current thread has upgrade ownership of `*this`.]]
+
+[[Effects:] [Releases upgrade ownership of `*this` by the current thread.]]
+
+[[Postcondition:] [The current thread no longer has upgrade ownership of `*this`.]]
+
+[[Throws:] [Nothing]]
+
+]
+[endsect]
+
+[section:unlock_upgrade_and_lock `void unlock_upgrade_and_lock()`]
+
+[variablelist
+
+[[Precondition:] [The current thread has upgrade ownership of `*this`.]]
+
+[[Effects:] [Atomically releases upgrade ownership of `*this` by the current thread and acquires exclusive ownership of `*this`. If
+any other threads have shared ownership, blocks until exclusive ownership can be acquired.]]
+
+[[Postcondition:] [The current thread has exclusive ownership of `*this`.]]
+
+[[Throws:] [Nothing]]
+
+]
+[endsect]
+
+[section:unlock_upgrade_and_lock_shared `void unlock_upgrade_and_lock_shared()`]
+
+[variablelist
+
+[[Precondition:] [The current thread has upgrade ownership of `*this`.]]
+
+[[Effects:] [Atomically releases upgrade ownership of `*this` by the current thread and acquires shared ownership of `*this` without
+blocking.]]
+
+[[Postcondition:] [The current thread has shared ownership of `*this`.]]
+
+[[Throws:] [Nothing]]
+
+]
+[endsect]
+
+[section:unlock_and_lock_upgrade `void unlock_and_lock_upgrade()`]
+
+[variablelist
+
+[[Precondition:] [The current thread has exclusive ownership of `*this`.]]
+
+[[Effects:] [Atomically releases exclusive ownership of `*this` by the current thread and acquires upgrade ownership of `*this`
+without blocking.]]
+
+[[Postcondition:] [The current thread has upgrade ownership of `*this`.]]
+
+[[Throws:] [Nothing]]
+
+]
+[endsect]
+
+[endsect]
+
+[endsect]
+
+[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
+ {
+ public:
+ explicit lock_guard(Lockable& m_);
+ lock_guard(Lockable& m_,boost::adopt_lock_t);
+
+ ~lock_guard();
+ };
+
+__lock_guard__ is very simple: on construction it
+acquires ownership of the implementation of the __lockable_concept__ supplied as
+the constructor parameter. On destruction, the ownership is released. This
+provides simple RAII-style locking of a __lockable_concept_type__ object, to facilitate exception-safe
+locking and unlocking. In addition, the [link
+thread.synchronization.locks.lock_guard.constructor_adopt `lock_guard(Lockable &
+m,boost::adopt_lock_t)` constructor] allows the __lock_guard__ object to
+take ownership of a lock already held by the current thread.
+
+[section:constructor `lock_guard(Lockable & m)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]]
+
+[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
+
+]
+
+[endsect]
+
+[section:constructor_adopt `lock_guard(Lockable & m,boost::adopt_lock_t)`]
+
+[variablelist
+
+[[Precondition:] [The current thread owns a lock on `m` equivalent to one
+obtained by a call to [lock_ref_link `m.lock()`].]]
+
+[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of
+`m`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:destructor `~lock_guard()`]
+
+[variablelist
+
+[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__
+object passed to the constructor.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:unique_lock Class template `unique_lock`]
+
+ #include <boost/thread/locks.hpp>
+
+ template<typename Lockable>
+ class unique_lock
+ {
+ public:
+ unique_lock();
+ explicit unique_lock(Lockable& m_);
+ unique_lock(Lockable& m_,adopt_lock_t);
+ unique_lock(Lockable& m_,defer_lock_t);
+ unique_lock(Lockable& m_,try_to_lock_t);
+ unique_lock(Lockable& m_,system_time const& target_time);
+
+ ~unique_lock();
+
+ unique_lock(detail::thread_move_t<unique_lock<Lockable> > other);
+ unique_lock(detail::thread_move_t<upgrade_lock<Lockable> > other);
+
+ operator detail::thread_move_t<unique_lock<Lockable> >();
+ detail::thread_move_t<unique_lock<Lockable> > move();
+ unique_lock& operator=(detail::thread_move_t<unique_lock<Lockable> > other);
+ unique_lock& operator=(detail::thread_move_t<upgrade_lock<Lockable> > other);
+
+ void swap(unique_lock& other);
+ void swap(detail::thread_move_t<unique_lock<Lockable> > other);
+
+ void lock();
+ bool try_lock();
+
+ template<typename TimeDuration>
+ bool timed_lock(TimeDuration const& relative_time);
+ bool timed_lock(::boost::system_time const& absolute_time);
+
+ void unlock();
+
+ bool owns_lock() const;
+ operator ``['unspecified-bool-type]``() const;
+ bool operator!() const;
+
+ Lockable* mutex() const;
+ Lockable* release();
+ };
+
+__unique_lock__ is more complex than __lock_guard__: not only does it provide for RAII-style locking, it also allows for deferring
+acquiring the lock until the __lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking
+fashion, or with a timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the
+__lockable_concept_type__ object, or otherwise adopted a lock on the __lockable_concept_type__ object.
+
+Specializations of __unique_lock__ model the __timed_lockable_concept__ if the supplied __lockable_concept_type__ type itself models
+__timed_lockable_concept__ (e.g. `boost::unique_lock<boost::timed_mutex>`), or the __lockable_concept__ otherwise
+(e.g. `boost::unique_lock<boost::mutex>`).
+
+An instance of __unique_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a
+pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object
+is destroyed, then the destructor will invoke [unlock_ref_link `mutex()->unlock()`].
+
+The member functions of __unique_lock__ are not thread-safe. In particular, __unique_lock__ is intended to model the ownership of a
+__lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock state
+(including the destructor) must be called by the same thread that acquired ownership of the lock state.
+
+[section:defaultconstructor `unique_lock()`]
+
+[variablelist
+
+[[Effects:] [Creates a lock object with no associated mutex.]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor `unique_lock(Lockable & m)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
+
+[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
+
+]
+
+[endsect]
+
+[section:constructor_adopt `unique_lock(Lockable & m,boost::adopt_lock_t)`]
+
+[variablelist
+
+[[Precondition:] [The current thread owns an exclusive lock on `m`.]]
+
+[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of `m`.]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor_defer `unique_lock(Lockable & m,boost::defer_lock_t)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`.]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `&m`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor_try `unique_lock(Lockable & m,boost::try_to_lock_t)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [try_lock_ref_link
+`m.try_lock()`], and takes ownership of the lock state if the call returns
+`true`.]]
+
+[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __try_lock_ref__
+returned `true`, then __owns_lock_ref__ returns `true`, otherwise __owns_lock_ref__
+returns `false`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor_abs_time `unique_lock(Lockable & m,boost::system_time const& abs_time)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [timed_lock_ref_link
+`m.timed_lock(abs_time)`], and takes ownership of the lock state if the call
+returns `true`.]]
+
+[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __timed_lock_ref__
+returned `true`, then __owns_lock_ref__ returns `true`, otherwise __owns_lock_ref__
+returns `false`.]]
+
+[[Throws:] [Any exceptions thrown by the call to [timed_lock_ref_link `m.timed_lock(abs_time)`].]]
+
+]
+
+[endsect]
+
+[section:destructor `~unique_lock()`]
+
+[variablelist
+
+[[Effects:] [Invokes __mutex_func_ref__`->`[unlock_ref_link `unlock()`] if
+__owns_lock_ref__ returns `true`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:owns_lock `bool owns_lock() const`]
+
+[variablelist
+
+[[Returns:] [`true` if the `*this` owns the lock on the __lockable_concept_type__
+object associated with `*this`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:mutex `Lockable* mutex() const`]
+
+[variablelist
+
+[[Returns:] [A pointer to the __lockable_concept_type__ object associated with
+`*this`, or `NULL` if there is no such object.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:bool_conversion `operator unspecified-bool-type() const`]
+
+[variablelist
+
+[[Returns:] [If __owns_lock_ref__ would return `true`, a value that evaluates to
+`true` in boolean contexts, otherwise a value that evaluates to `false` in
+boolean contexts.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:operator_not `bool operator!() const`]
+
+[variablelist
+
+[[Returns:] [`!` __owns_lock_ref__.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:release `Lockable* release()`]
+
+[variablelist
+
+[[Effects:] [The association between `*this` and the __lockable_concept_type__ object is removed, without affecting the lock state
+of the __lockable_concept_type__ object. If __owns_lock_ref__ would have returned `true`, it is the responsibility of the calling
+code to ensure that the __lockable_concept_type__ is correctly unlocked.]]
+
+[[Returns:] [A pointer to the __lockable_concept_type__ object associated with `*this` at the point of the call, or `NULL` if there
+is no such object.]]
+
+[[Throws:] [Nothing.]]
+
+[[Postcondition:] [`*this` is no longer associated with any __lockable_concept_type__ object. __mutex_func_ref__ returns `NULL` and
+__owns_lock_ref__ returns `false`.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:shared_lock Class template `shared_lock`]
+
+ #include <boost/thread/locks.hpp>
+
+ template<typename Lockable>
+ class shared_lock
+ {
+ public:
+ shared_lock();
+ explicit shared_lock(Lockable& m_);
+ shared_lock(Lockable& m_,adopt_lock_t);
+ shared_lock(Lockable& m_,defer_lock_t);
+ shared_lock(Lockable& m_,try_to_lock_t);
+ shared_lock(Lockable& m_,system_time const& target_time);
+ shared_lock(detail::thread_move_t<shared_lock<Lockable> > other);
+ shared_lock(detail::thread_move_t<unique_lock<Lockable> > other);
+ shared_lock(detail::thread_move_t<upgrade_lock<Lockable> > other);
+
+ ~shared_lock();
+
+ operator detail::thread_move_t<shared_lock<Lockable> >();
+ detail::thread_move_t<shared_lock<Lockable> > move();
+
+ shared_lock& operator=(detail::thread_move_t<shared_lock<Lockable> > other);
+ shared_lock& operator=(detail::thread_move_t<unique_lock<Lockable> > other);
+ shared_lock& operator=(detail::thread_move_t<upgrade_lock<Lockable> > other);
+ void swap(shared_lock& other);
+
+ void lock();
+ bool try_lock();
+ bool timed_lock(boost::system_time const& target_time);
+ void unlock();
+
+ operator ``['unspecified-bool-type]``() const;
+ bool operator!() const;
+ bool owns_lock() const;
+ };
+
+Like __unique_lock__, __shared_lock__ models the __lockable_concept__, but rather than acquiring unique ownership of the supplied
+__lockable_concept_type__ object, locking an instance of __shared_lock__ acquires shared ownership.
+
+Like __unique_lock__, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the
+__lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a
+timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the __lockable_concept_type__
+object, or otherwise adopted a lock on the __lockable_concept_type__ object.
+
+An instance of __shared_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a
+pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object
+is destroyed, then the destructor will invoke [unlock_shared_ref_link `mutex()->unlock_shared()`].
+
+The member functions of __shared_lock__ are not thread-safe. In particular, __shared_lock__ is intended to model the shared
+ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock
+state (including the destructor) must be called by the same thread that acquired ownership of the lock state.
+
+[section:defaultconstructor `shared_lock()`]
+
+[variablelist
+
+[[Effects:] [Creates a lock object with no associated mutex.]]
+
+[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor `shared_lock(Lockable & m)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [lock_shared_ref_link `m.lock_shared()`].]]
+
+[[Postcondition:] [__owns_lock_shared_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
+
+[[Throws:] [Any exception thrown by the call to [lock_shared_ref_link `m.lock_shared()`].]]
+
+]
+
+[endsect]
+
+[section:constructor_adopt `shared_lock(Lockable & m,boost::adopt_lock_t)`]
+
+[variablelist
+
+[[Precondition:] [The current thread owns an exclusive lock on `m`.]]
+
+[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of `m`.]]
+
+[[Postcondition:] [__owns_lock_shared_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor_defer `shared_lock(Lockable & m,boost::defer_lock_t)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`.]]
+
+[[Postcondition:] [__owns_lock_shared_ref__ returns `false`. __mutex_func_ref__ returns `&m`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor_try `shared_lock(Lockable & m,boost::try_to_lock_t)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [try_lock_shared_ref_link
+`m.try_lock_shared()`], and takes ownership of the lock state if the call returns
+`true`.]]
+
+[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __try_lock_shared_ref__
+returned `true`, then __owns_lock_shared_ref__ returns `true`, otherwise __owns_lock_shared_ref__
+returns `false`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:constructor_abs_time `shared_lock(Lockable & m,boost::system_time const& abs_time)`]
+
+[variablelist
+
+[[Effects:] [Stores a reference to `m`. Invokes [timed_lock_shared_ref_link
+`m.timed_lock(abs_time)`], and takes ownership of the lock state if the call
+returns `true`.]]
+
+[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __timed_lock_shared_ref__
+returned `true`, then __owns_lock_shared_ref__ returns `true`, otherwise __owns_lock_shared_ref__
+returns `false`.]]
+
+[[Throws:] [Any exceptions thrown by the call to [timed_lock_shared_ref_link `m.timed_lock(abs_time)`].]]
+
+]
+
+[endsect]
+
+[section:destructor `~shared_lock()`]
+
+[variablelist
+
+[[Effects:] [Invokes __mutex_func_ref__`->`[unlock_shared_ref_link `unlock_shared()`] if
+__owns_lock_shared_ref__ returns `true`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:owns_lock `bool owns_lock() const`]
+
+[variablelist
+
+[[Returns:] [`true` if the `*this` owns the lock on the __lockable_concept_type__
+object associated with `*this`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:mutex `Lockable* mutex() const`]
+
+[variablelist
+
+[[Returns:] [A pointer to the __lockable_concept_type__ object associated with
+`*this`, or `NULL` if there is no such object.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:bool_conversion `operator unspecified-bool-type() const`]
+
+[variablelist
+
+[[Returns:] [If __owns_lock_shared_ref__ would return `true`, a value that evaluates to
+`true` in boolean contexts, otherwise a value that evaluates to `false` in
+boolean contexts.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:operator_not `bool operator!() const`]
+
+[variablelist
+
+[[Returns:] [`!` __owns_lock_shared_ref__.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:release `Lockable* release()`]
+
+[variablelist
+
+[[Effects:] [The association between `*this` and the __lockable_concept_type__ object is removed, without affecting the lock state
+of the __lockable_concept_type__ object. If __owns_lock_shared_ref__ would have returned `true`, it is the responsibility of the calling
+code to ensure that the __lockable_concept_type__ is correctly unlocked.]]
+
+[[Returns:] [A pointer to the __lockable_concept_type__ object associated with `*this` at the point of the call, or `NULL` if there
+is no such object.]]
+
+[[Throws:] [Nothing.]]
+
+[[Postcondition:] [`*this` is no longer associated with any __lockable_concept_type__ object. __mutex_func_ref__ returns `NULL` and
+__owns_lock_shared_ref__ returns `false`.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:upgrade_lock Class template `upgrade_lock`]
+
+ #include <boost/thread/locks.hpp>
+
+ template<typename Lockable>
+ class upgrade_lock
+ {
+ public:
+ explicit upgrade_lock(Lockable& m_);
+
+ upgrade_lock(detail::thread_move_t<upgrade_lock<Lockable> > other);
+ upgrade_lock(detail::thread_move_t<unique_lock<Lockable> > other);
+
+ ~upgrade_lock();
+
+ operator detail::thread_move_t<upgrade_lock<Lockable> >();
+ detail::thread_move_t<upgrade_lock<Lockable> > move();
+
+ upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Lockable> > other);
+ upgrade_lock& operator=(detail::thread_move_t<unique_lock<Lockable> > other);
+
+ void swap(upgrade_lock& other);
+
+ void lock();
+ void unlock();
+
+ operator ``['unspecified-bool-type]``() const;
+ bool operator!() const;
+ bool owns_lock() const;
+ };
+
+Like __unique_lock__, __upgrade_lock__ models the __lockable_concept__, but rather than acquiring unique ownership of the supplied
+__lockable_concept_type__ object, locking an instance of __upgrade_lock__ acquires upgrade ownership.
+
+Like __unique_lock__, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the
+__lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a
+timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the __lockable_concept_type__
+object, or otherwise adopted a lock on the __lockable_concept_type__ object.
+
+An instance of __upgrade_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a
+pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object
+is destroyed, then the destructor will invoke [unlock_upgrade_ref_link `mutex()->unlock_upgrade()`].
+
+The member functions of __upgrade_lock__ are not thread-safe. In particular, __upgrade_lock__ is intended to model the upgrade
+ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock
+state (including the destructor) must be called by the same thread that acquired ownership of the lock state.
+
+[endsect]
+
+[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`]
+
+ #include <boost/thread/locks.hpp>
+
+ template <class Lockable>
+ class upgrade_to_unique_lock
+ {
+ public:
+ explicit upgrade_to_unique_lock(upgrade_lock<Lockable>& m_);
+
+ ~upgrade_to_unique_lock();
+
+ upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Lockable> > other);
+ upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Lockable> > other);
+ void swap(upgrade_to_unique_lock& other);
+
+ operator ``['unspecified-bool-type]``() const;
+ bool operator!() const;
+ bool owns_lock() const;
+ };
+
+__upgrade_to_unique_lock__ allows for a temporary upgrade of an __upgrade_lock__ to exclusive ownership. When constructed with a
+reference to an instance of __upgrade_lock__, if that instance has upgrade ownership on some __lockable_concept_type__ object, that
+ownership is upgraded to exclusive ownership. When the __upgrade_to_unique_lock__ instance is destroyed, the ownership of the
+__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]
diff --git a/libs/thread/doc/mutexes.qbk b/libs/thread/doc/mutexes.qbk
new file mode 100644
index 0000000000..ddea86a4bb
--- /dev/null
+++ b/libs/thread/doc/mutexes.qbk
@@ -0,0 +1,224 @@
+[/
+ (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
+ {
+ public:
+ mutex();
+ ~mutex();
+
+ void lock();
+ bool try_lock();
+ void unlock();
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+ typedef unique_lock<mutex> scoped_lock;
+ typedef unspecified-type scoped_try_lock;
+ };
+
+__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given
+instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted.
+
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+
+[endsect]
+
+[section:try_mutex Typedef `try_mutex`]
+
+ #include <boost/thread/mutex.hpp>
+
+ typedef mutex try_mutex;
+
+__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost.
+
+[endsect]
+
+[section:timed_mutex Class `timed_mutex`]
+
+ #include <boost/thread/mutex.hpp>
+
+ class timed_mutex:
+ boost::noncopyable
+ {
+ public:
+ timed_mutex();
+ ~timed_mutex();
+
+ void lock();
+ void unlock();
+ bool try_lock();
+ bool timed_lock(system_time const & abs_time);
+
+ template<typename TimeDuration>
+ bool timed_lock(TimeDuration const & relative_time);
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+ typedef unique_lock<timed_mutex> scoped_timed_lock;
+ typedef unspecified-type scoped_try_lock;
+ typedef scoped_timed_lock scoped_lock;
+ };
+
+__timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the
+lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__,
+__timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted.
+
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:recursive_mutex Class `recursive_mutex`]
+
+ #include <boost/thread/recursive_mutex.hpp>
+
+ class recursive_mutex:
+ boost::noncopyable
+ {
+ public:
+ recursive_mutex();
+ ~recursive_mutex();
+
+ void lock();
+ bool try_lock();
+ void unlock();
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+ typedef unique_lock<recursive_mutex> scoped_lock;
+ typedef unspecified-type scoped_try_lock;
+ };
+
+__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can
+own the lock on a given instance of __recursive_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and
+__unlock_ref__ shall be permitted. A thread that already has exclusive ownership of a given __recursive_mutex__ instance can call
+__lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for
+each level of ownership acquired by a single thread before ownership can be acquired by another thread.
+
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:recursive_try_mutex Typedef `recursive_try_mutex`]
+
+ #include <boost/thread/recursive_mutex.hpp>
+
+ typedef recursive_mutex recursive_try_mutex;
+
+__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost.
+
+[endsect]
+
+[section:recursive_timed_mutex Class `recursive_timed_mutex`]
+
+ #include <boost/thread/recursive_mutex.hpp>
+
+ class recursive_timed_mutex:
+ boost::noncopyable
+ {
+ public:
+ recursive_timed_mutex();
+ ~recursive_timed_mutex();
+
+ void lock();
+ bool try_lock();
+ void unlock();
+
+ bool timed_lock(system_time const & abs_time);
+
+ template<typename TimeDuration>
+ bool timed_lock(TimeDuration const & relative_time);
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+ typedef unique_lock<recursive_timed_mutex> scoped_lock;
+ typedef unspecified-type scoped_try_lock;
+ typedef scoped_lock scoped_timed_lock;
+ };
+
+__recursive_timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one
+thread can own the lock on a given instance of __recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__,
+__try_lock_ref__, __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. A thread that already has
+exclusive ownership of a given __recursive_timed_mutex__ instance can call __lock_ref__, __timed_lock_ref__,
+__timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be
+called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.
+
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[include shared_mutex_ref.qbk]
+
+[endsect]
diff --git a/libs/thread/doc/once.qbk b/libs/thread/doc/once.qbk
new file mode 100644
index 0000000000..ecbdcb2290
--- /dev/null
+++ b/libs/thread/doc/once.qbk
@@ -0,0 +1,65 @@
+[/
+ (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
+
+Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
+
+ boost::once_flag f=BOOST_ONCE_INIT;
+
+[endsect]
+
+[section:call_once Non-member function `call_once`]
+
+ #include <boost/thread/once.hpp>
+
+ template<typename Callable>
+ void call_once(once_flag& flag,Callable func);
+
+[variablelist
+
+[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall
+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
+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`. ]]
+
+[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with
+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);
+
+This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of
+`call_once(flag,func)`.
+
+[endsect]
+[endsect]
diff --git a/libs/thread/doc/overview.qbk b/libs/thread/doc/overview.qbk
new file mode 100644
index 0000000000..c647a6d219
--- /dev/null
+++ b/libs/thread/doc/overview.qbk
@@ -0,0 +1,30 @@
+[/
+ (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
+functions for managing the threads themselves, along with others for synchronizing data between the threads or providing separate
+copies of data specific to individual threads.
+
+The __boost_thread__ library was originally written and designed by William E. Kempf. This version is a major rewrite designed to
+closely follow the proposals presented to the C++ Standards Committee, in particular
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html N2497],
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html N2320],
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2184.html N2184],
+[@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]
diff --git a/libs/thread/doc/shared_mutex_ref.qbk b/libs/thread/doc/shared_mutex_ref.qbk
new file mode 100644
index 0000000000..49cd16737a
--- /dev/null
+++ b/libs/thread/doc/shared_mutex_ref.qbk
@@ -0,0 +1,44 @@
+[/
+ (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:
+ shared_mutex();
+ ~shared_mutex();
+
+ void lock_shared();
+ bool try_lock_shared();
+ bool timed_lock_shared(system_time const& timeout);
+ void unlock_shared();
+
+ void lock();
+ bool try_lock();
+ bool timed_lock(system_time const& timeout);
+ void unlock();
+
+ void lock_upgrade();
+ void unlock_upgrade();
+
+ void unlock_upgrade_and_lock();
+ void unlock_and_lock_upgrade();
+ void unlock_and_lock_shared();
+ void unlock_upgrade_and_lock_shared();
+ };
+
+The class `boost::shared_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
+__upgrade_lockable_concept__.
+
+Multiple concurrent calls to __lock_ref__, __try_lock_ref__, __timed_lock_ref__, __lock_shared_ref__, __try_lock_shared_ref__ and
+__timed_lock_shared_ref__ shall be permitted.
+
+
+[endsect]
diff --git a/libs/thread/doc/thread.qbk b/libs/thread/doc/thread.qbk
new file mode 100644
index 0000000000..c1a236c677
--- /dev/null
+++ b/libs/thread/doc/thread.qbk
@@ -0,0 +1,170 @@
+[/
+ (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]]
+ [copyright 2007-8 Anthony Williams]
+ [purpose C++ Library for launching threads and synchronizing data between them]
+ [category text]
+ [license
+ 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])
+ ]
+]
+
+[template lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.lockable [link_text]]]
+[def __lockable_concept__ [lockable_concept_link `Lockable` concept]]
+[def __lockable_concept_type__ [lockable_concept_link `Lockable`]]
+
+[template timed_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable [link_text]]]
+[def __timed_lockable_concept__ [timed_lockable_concept_link `TimedLockable` concept]]
+[def __timed_lockable_concept_type__ [timed_lockable_concept_link `TimedLockable`]]
+
+[template shared_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable [link_text]]]
+[def __shared_lockable_concept__ [shared_lockable_concept_link `SharedLockable` concept]]
+[def __shared_lockable_concept_type__ [shared_lockable_concept_link `SharedLockable`]]
+
+[template upgrade_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable [link_text]]]
+[def __upgrade_lockable_concept__ [upgrade_lockable_concept_link `UpgradeLockable` concept]]
+[def __upgrade_lockable_concept_type__ [upgrade_lockable_concept_link `UpgradeLockable`]]
+
+
+[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()`]]
+
+[template try_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.try_lock [link_text]]]
+[def __try_lock_ref__ [try_lock_ref_link `try_lock()`]]
+
+[template timed_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock [link_text]]]
+[def __timed_lock_ref__ [timed_lock_ref_link `timed_lock()`]]
+
+[template timed_lock_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration [link_text]]]
+[def __timed_lock_duration_ref__ [timed_lock_duration_ref_link `timed_lock()`]]
+
+[template lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared [link_text]]]
+[def __lock_shared_ref__ [lock_shared_ref_link `lock_shared()`]]
+
+[template unlock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared [link_text]]]
+[def __unlock_shared_ref__ [unlock_shared_ref_link `unlock_shared()`]]
+
+[template try_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared [link_text]]]
+[def __try_lock_shared_ref__ [try_lock_shared_ref_link `try_lock_shared()`]]
+
+[template timed_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared [link_text]]]
+[def __timed_lock_shared_ref__ [timed_lock_shared_ref_link `timed_lock_shared()`]]
+
+[template timed_lock_shared_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared_duration [link_text]]]
+[def __timed_lock_shared_duration_ref__ [timed_lock_shared_duration_ref_link `timed_lock_shared()`]]
+
+[template lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade [link_text]]]
+[def __lock_upgrade_ref__ [lock_upgrade_ref_link `lock_upgrade()`]]
+
+[template unlock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade [link_text]]]
+[def __unlock_upgrade_ref__ [unlock_upgrade_ref_link `unlock_upgrade()`]]
+
+[template unlock_upgrade_and_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock [link_text]]]
+[def __unlock_upgrade_and_lock_ref__ [unlock_upgrade_and_lock_ref_link `unlock_upgrade_and_lock()`]]
+
+[template unlock_and_lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade [link_text]]]
+[def __unlock_and_lock_upgrade_ref__ [unlock_and_lock_upgrade_ref_link `unlock_and_lock_upgrade()`]]
+
+[template unlock_upgrade_and_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared [link_text]]]
+[def __unlock_upgrade_and_lock_shared_ref__ [unlock_upgrade_and_lock_shared_ref_link `unlock_upgrade_and_lock_shared()`]]
+
+[template owns_lock_ref_link[link_text] [link thread.synchronization.locks.unique_lock.owns_lock [link_text]]]
+[def __owns_lock_ref__ [owns_lock_ref_link `owns_lock()`]]
+
+[template owns_lock_shared_ref_link[link_text] [link thread.synchronization.locks.shared_lock.owns_lock [link_text]]]
+[def __owns_lock_shared_ref__ [owns_lock_shared_ref_link `owns_lock()`]]
+
+[template mutex_func_ref_link[link_text] [link thread.synchronization.locks.unique_lock.mutex [link_text]]]
+[def __mutex_func_ref__ [mutex_func_ref_link `mutex()`]]
+
+[def __boost_thread__ [*Boost.Thread]]
+[def __not_a_thread__ ['Not-a-Thread]]
+[def __interruption_points__ [link interruption_points ['interruption points]]]
+
+[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]]
+[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]]
+[def __timed_mutex__ [link thread.synchronization.mutex_types.timed_mutex `boost::timed_mutex`]]
+[def __recursive_mutex__ [link thread.synchronization.mutex_types.recursive_mutex `boost::recursive_mutex`]]
+[def __recursive_try_mutex__ [link thread.synchronization.mutex_types.recursive_try_mutex `boost::recursive_try_mutex`]]
+[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 __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`]]
+
+
+[def __thread__ [link thread.thread_management.thread `boost::thread`]]
+[def __thread_id__ [link thread.thread_management.thread.id `boost::thread::id`]]
+[template join_link[link_text] [link thread.thread_management.thread.join [link_text]]]
+[def __join__ [join_link `join()`]]
+[template timed_join_link[link_text] [link thread.thread_management.thread.timed_join [link_text]]]
+[def __timed_join__ [timed_join_link `timed_join()`]]
+[def __detach__ [link thread.thread_management.thread.detach `detach()`]]
+[def __interrupt__ [link thread.thread_management.thread.interrupt `interrupt()`]]
+[def __sleep__ [link thread.thread_management.this_thread.sleep `boost::this_thread::sleep()`]]
+
+[def __interruption_enabled__ [link thread.thread_management.this_thread.interruption_enabled `boost::this_thread::interruption_enabled()`]]
+[def __interruption_requested__ [link thread.thread_management.this_thread.interruption_requested `boost::this_thread::interruption_requested()`]]
+[def __interruption_point__ [link thread.thread_management.this_thread.interruption_point `boost::this_thread::interruption_point()`]]
+[def __disable_interruption__ [link thread.thread_management.this_thread.disable_interruption `boost::this_thread::disable_interruption`]]
+[def __restore_interruption__ [link thread.thread_management.this_thread.restore_interruption `boost::this_thread::restore_interruption`]]
+
+[def __thread_resource_error__ `boost::thread_resource_error`]
+[def __thread_interrupted__ `boost::thread_interrupted`]
+[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]]
+
+[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]]
+[def __cond_wait__ [cond_wait_link `wait()`]]
+[template cond_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.timed_wait [link_text]]]
+[def __cond_timed_wait__ [cond_timed_wait_link `timed_wait()`]]
+[template cond_any_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.wait [link_text]]]
+[def __cond_any_wait__ [cond_any_wait_link `wait()`]]
+[template cond_any_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.timed_wait [link_text]]]
+[def __cond_any_timed_wait__ [cond_any_timed_wait_link `timed_wait()`]]
+
+[def __blocked__ ['blocked]]
+
+[include overview.qbk]
+[include changes.qbk]
+
+[include thread_ref.qbk]
+
+[section:synchronization Synchronization]
+[include mutex_concepts.qbk]
+[include mutexes.qbk]
+[include condition_variables.qbk]
+[include once.qbk]
+[include barrier.qbk]
+[include futures.qbk]
+[endsect]
+
+[include tss.qbk]
+
+[include time.qbk]
+
+[include acknowledgements.qbk]
+
+[include compliance.qbk]
diff --git a/libs/thread/doc/thread_ref.qbk b/libs/thread/doc/thread_ref.qbk
new file mode 100644
index 0000000000..aa0d5e94f2
--- /dev/null
+++ b/libs/thread/doc/thread_ref.qbk
@@ -0,0 +1,1167 @@
+[/
+ (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]
+
+The __thread__ class is responsible for launching and managing threads. Each __thread__ object represents a single thread of execution,
+or __not_a_thread__, and at most one __thread__ object represents a given thread of execution: objects of type __thread__ are not
+copyable.
+
+Objects of type __thread__ are movable, however, so they can be stored in move-aware containers, and returned from functions. This
+allows the details of thread creation to be wrapped in a function.
+
+ boost::thread make_thread();
+
+ void f()
+ {
+ boost::thread some_thread=make_thread();
+ some_thread.join();
+ }
+
+[Note: On compilers that support rvalue references, __thread__ provides a proper move constructor and move-assignment operator, and
+therefore meets the C++0x ['MoveConstructible] and ['MoveAssignable] concepts. With such compilers, __thread__ can therefore be used
+with containers that support those concepts.
+
+For other compilers, move support is provided with a move emulation layer, so containers must explicitly detect that move emulation
+layer. See <boost/thread/detail/move.hpp> for details.]
+
+[heading Launching threads]
+
+A new thread is launched by passing an object of a callable type that can be invoked with no parameters to the constructor. The
+object is then copied into internal storage, and invoked on the newly-created thread of execution. If the object must not (or
+cannot) be copied, then `boost::ref` can be used to pass in a reference to the function object. In this case, the user of
+__boost_thread__ must ensure that the referred-to object outlives the newly-created thread of execution.
+
+ struct callable
+ {
+ void operator()();
+ };
+
+ boost::thread copies_are_safe()
+ {
+ callable x;
+ return boost::thread(x);
+ } // x is destroyed, but the newly-created thread has a copy, so this is OK
+
+ boost::thread oops()
+ {
+ callable x;
+ return boost::thread(boost::ref(x));
+ } // x is destroyed, but the newly-created thread still has a reference
+ // this leads to undefined behaviour
+
+If you wish to construct an instance of __thread__ with a function or callable object that requires arguments to be supplied,
+this can be done by passing additional arguments to the __thread__ constructor:
+
+ void find_the_question(int the_answer);
+
+ boost::thread deep_thought_2(find_the_question,42);
+
+The arguments are ['copied] into the internal thread structure: if a reference is required, use `boost::ref`, just as for references
+to callable functions.
+
+There is an unspecified limit on the number of additional arguments that can be passed.
+
+[heading Exceptions in thread functions]
+
+If the function or callable object passed to the __thread__ constructor propagates an exception when invoked that is not of type
+__thread_interrupted__, `std::terminate()` is called.
+
+[heading Joining and detaching]
+
+When the __thread__ object that represents a thread of execution is destroyed the thread becomes ['detached]. Once a thread is
+detached, it will continue executing until the invocation of the function or callable object supplied on construction has completed,
+or the program is terminated. A thread can also be detached by explicitly invoking the __detach__ member function on the __thread__
+object. In this case, the __thread__ object ceases to represent the now-detached thread, and instead represents __not_a_thread__.
+
+In order to wait for a thread of execution to finish, the __join__ or __timed_join__ member functions of the __thread__ object must be
+used. __join__ will block the calling thread until the thread represented by the __thread__ object has completed. If the thread of
+execution represented by the __thread__ object has already completed, or the __thread__ object represents __not_a_thread__, then __join__
+returns immediately. __timed_join__ is similar, except that a call to __timed_join__ will also return if the thread being waited for
+does not complete when the specified time has elapsed.
+
+[heading Interruption]
+
+A running thread can be ['interrupted] by invoking the __interrupt__ member function of the corresponding __thread__ object. When the
+interrupted thread next executes one of the specified __interruption_points__ (or if it is currently __blocked__ whilst executing one)
+with interruption enabled, then a __thread_interrupted__ exception will be thrown in the interrupted thread. If not caught,
+this will cause the execution of the interrupted thread to terminate. As with any other exception, the stack will be unwound, and
+destructors for objects of automatic storage duration will be executed.
+
+If a thread wishes to avoid being interrupted, it can create an instance of __disable_interruption__. Objects of this class disable
+interruption for the thread that created them on construction, and restore the interruption state to whatever it was before on
+destruction:
+
+ void f()
+ {
+ // interruption enabled here
+ {
+ boost::this_thread::disable_interruption di;
+ // interruption disabled
+ {
+ boost::this_thread::disable_interruption di2;
+ // interruption still disabled
+ } // di2 destroyed, interruption state restored
+ // interruption still disabled
+ } // di destroyed, interruption state restored
+ // interruption now enabled
+ }
+
+The effects of an instance of __disable_interruption__ can be temporarily reversed by constructing an instance of
+__restore_interruption__, passing in the __disable_interruption__ object in question. This will
+restore the interruption state to what it was when the __disable_interruption__ object was constructed, and then
+disable interruption again when the __restore_interruption__ object is destroyed.
+
+ void g()
+ {
+ // interruption enabled here
+ {
+ boost::this_thread::disable_interruption di;
+ // interruption disabled
+ {
+ boost::this_thread::restore_interruption ri(di);
+ // interruption now enabled
+ } // ri destroyed, interruption disable again
+ } // di destroyed, interruption state restored
+ // interruption now enabled
+ }
+
+At any point, the interruption state for the current thread can be queried by calling __interruption_enabled__.
+
+[#interruption_points]
+
+[heading Predefined Interruption Points]
+
+The following functions are ['interruption points], which will throw __thread_interrupted__ if interruption is enabled for the
+current thread, and interruption is requested for the current thread:
+
+* [join_link `boost::thread::join()`]
+* [timed_join_link `boost::thread::timed_join()`]
+* [cond_wait_link `boost::condition_variable::wait()`]
+* [cond_timed_wait_link `boost::condition_variable::timed_wait()`]
+* [cond_any_wait_link `boost::condition_variable_any::wait()`]
+* [cond_any_timed_wait_link `boost::condition_variable_any::timed_wait()`]
+* [link thread.thread_management.thread.sleep `boost::thread::sleep()`]
+* __sleep__
+* __interruption_point__
+
+[heading Thread IDs]
+
+Objects of class __thread_id__ can be used to identify threads. Each running thread of execution has a unique ID obtainable
+from the corresponding __thread__ by calling the `get_id()` member function, or by calling `boost::this_thread::get_id()` from
+within the thread. Objects of class __thread_id__ can be copied, and used as keys in associative containers: the full range of
+comparison operators is provided. Thread IDs can also be written to an output stream using the stream insertion operator, though the
+output format is unspecified.
+
+Each instance of __thread_id__ either refers to some thread, or __not_a_thread__. Instances that refer to __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:
+ thread();
+ ~thread();
+
+ 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);
+
+ // move support
+ thread(detail::thread_move_t<thread> x);
+ thread& operator=(detail::thread_move_t<thread> x);
+ operator detail::thread_move_t<thread>();
+ detail::thread_move_t<thread> move();
+
+ void swap(thread& x);
+
+ class id;
+ id get_id() const;
+
+ bool joinable() const;
+ void join();
+ bool timed_join(const system_time& wait_until);
+
+ template<typename TimeDuration>
+ bool timed_join(TimeDuration const& rel_time);
+
+ void detach();
+
+ static unsigned hardware_concurrency();
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+ void interrupt();
+ bool interruption_requested() const;
+
+ // backwards compatibility
+ bool operator==(const thread& other) const;
+ bool operator!=(const thread& other) const;
+
+ static void yield();
+ static void sleep(const system_time& xt);
+ };
+
+ void swap(thread& lhs,thread& rhs);
+ detail::thread_move_t<thread> move(detail::thread_move_t<thread> t);
+
+[section:default_constructor Default Constructor]
+
+ thread();
+
+[variablelist
+
+[[Effects:] [Constructs a __thread__ instance that refers to __not_a_thread__.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[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>
+ thread(Callable func);
+
+[variablelist
+
+[[Preconditions:] [`Callable` must by copyable.]]
+
+[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
+thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
+not of type __thread_interrupted__, then `std::terminate()` will be called.]]
+
+[[Postconditions:] [`*this` refers to the newly created thread of execution.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+[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();
+
+[variablelist
+
+[[Effects:] [If `*this` has an associated thread of execution, calls __detach__. Destroys `*this`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:joinable Member function `joinable()`]
+
+ bool joinable() const;
+
+[variablelist
+
+[[Returns:] [`true` if `*this` refers to a thread of execution, `false` otherwise.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+
+[endsect]
+
+[section:join Member function `join()`]
+
+ void join();
+
+[variablelist
+
+[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]]
+
+[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete.]]
+
+[[Postconditions:] [If `*this` refers to a thread of execution on entry, that thread of execution has completed. `*this` no longer refers to any thread of execution.]]
+
+[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
+
+[[Notes:] [`join()` is one of the predefined __interruption_points__.]]
+
+]
+
+[endsect]
+
+[section:timed_join Member function `timed_join()`]
+
+ bool timed_join(const system_time& wait_until);
+
+ template<typename TimeDuration>
+ bool timed_join(TimeDuration const& rel_time);
+
+[variablelist
+
+[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]]
+
+[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `wait_until` has
+been reach or the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]]
+
+[[Returns:] [`true` if `*this` refers to a thread of execution on entry, and that thread of execution has completed before the call
+times out, `false` otherwise.]]
+
+[[Postconditions:] [If `*this` refers to a thread of execution on entry, and `timed_join` returns `true`, that thread of execution
+has completed, and `*this` no longer refers to any thread of execution. If this call to `timed_join` returns `false`, `*this` is
+unchanged.]]
+
+[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
+
+[[Notes:] [`timed_join()` is one of the predefined __interruption_points__.]]
+
+]
+
+[endsect]
+
+[section:detach Member function `detach()`]
+
+ void detach();
+
+[variablelist
+
+[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and no longer has an associated __thread__ object.]]
+
+[[Postconditions:] [`*this` no longer refers to any thread of execution.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+
+[section:get_id Member function `get_id()`]
+
+ thread::id get_id() const;
+
+[variablelist
+
+[[Returns:] [If `*this` refers to a thread of execution, an instance of __thread_id__ that represents that thread. Otherwise returns
+a default-constructed __thread_id__.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:interrupt Member function `interrupt()`]
+
+ void interrupt();
+
+[variablelist
+
+[[Effects:] [If `*this` refers to a thread of execution, request that the thread will be interrupted the next time it enters one of
+the predefined __interruption_points__ with interruption enabled, or if it is currently __blocked__ in a call to one of the
+predefined __interruption_points__ with interruption enabled .]]
+
+[[Throws:] [Nothing]]
+
+]
+
+
+[endsect]
+
+[section:hardware_concurrency Static member function `hardware_concurrency()`]
+
+ unsigned hardware_concurrency();
+
+[variablelist
+
+[[Returns:] [The number of hardware threads available on the current system (e.g. number of CPUs or cores or hyperthreading units),
+or 0 if this information is not available.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:nativehandle Member function `native_handle()`]
+
+ typedef platform-specific-type native_handle_type;
+ native_handle_type native_handle();
+
+[variablelist
+
+[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
+implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:equals `operator==`]
+
+ bool operator==(const thread& other) const;
+
+[variablelist
+
+[[Returns:] [`get_id()==other.get_id()`]]
+
+]
+
+[endsect]
+
+[section:not_equals `operator!=`]
+
+ bool operator!=(const thread& other) const;
+
+[variablelist
+
+[[Returns:] [`get_id()!=other.get_id()`]]
+
+]
+
+[endsect]
+
+[section:sleep Static member function `sleep()`]
+
+ void sleep(system_time const& abs_time);
+
+[variablelist
+
+[[Effects:] [Suspends the current thread until the specified time has been reached.]]
+
+[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
+
+[[Notes:] [`sleep()` is one of the predefined __interruption_points__.]]
+
+]
+
+[endsect]
+
+[section:yield Static member function `yield()`]
+
+ void yield();
+
+[variablelist
+
+[[Effects:] [See [link thread.thread_management.this_thread.yield `boost::this_thread::yield()`].]]
+
+]
+
+[endsect]
+
+[section:swap Member function `swap()`]
+
+ void swap(thread& other);
+
+[variablelist
+
+[[Effects:] [Exchanges the threads of execution associated with `*this` and `other`, so `*this` is associated with the thread of
+execution associated with `other` prior to the call, and vice-versa.]]
+
+[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()` prior to the call. `other.get_id()` returns the same
+value as `this->get_id()` prior to the call.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:non_member_swap Non-member function `swap()`]
+
+ #include <boost/thread/thread.hpp>
+
+ void swap(thread& lhs,thread& rhs);
+
+[variablelist
+
+[[Effects:] [[link thread.thread_management.thread.swap `lhs.swap(rhs)`].]]
+
+]
+
+[endsect]
+
+[section: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:
+ id();
+
+ bool operator==(const id& y) const;
+ bool operator!=(const id& y) const;
+ bool operator<(const id& y) const;
+ bool operator>(const id& y) const;
+ bool operator<=(const id& y) const;
+ bool operator>=(const id& y) const;
+
+ template<class charT, class traits>
+ friend std::basic_ostream<charT, traits>&
+ operator<<(std::basic_ostream<charT, traits>& os, const id& x);
+ };
+
+[section:constructor Default constructor]
+
+ id();
+
+[variablelist
+
+[[Effects:] [Constructs a __thread_id__ instance that represents __not_a_thread__.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:is_equal `operator==`]
+
+ bool operator==(const id& y) const;
+
+[variablelist
+
+[[Returns:] [`true` if `*this` and `y` both represent the same thread of execution, or both represent __not_a_thread__, `false`
+otherwise.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:not_equal `operator!=`]
+
+ bool operator!=(const id& y) const;
+
+[variablelist
+
+[[Returns:] [`true` if `*this` and `y` represent different threads of execution, or one represents a thread of execution, and
+the other represent __not_a_thread__, `false` otherwise.]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:less_than `operator<`]
+
+ bool operator<(const id& y) const;
+
+[variablelist
+
+[[Returns:] [`true` if `*this!=y` is `true` and the implementation-defined total order of __thread_id__ values places `*this` before
+`y`, `false` otherwise.]]
+
+[[Throws:] [Nothing]]
+
+[[Note:] [A __thread_id__ instance representing __not_a_thread__ will always compare less than an instance representing a thread of
+execution.]]
+
+]
+
+[endsect]
+
+
+[section:greater_than `operator>`]
+
+ bool operator>(const id& y) const;
+
+[variablelist
+
+[[Returns:] [`y<*this`]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:less_than_or_equal `operator<=`]
+
+ bool operator<=(const id& y) const;
+
+[variablelist
+
+[[Returns:] [`!(y<*this)`]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:greater_than_or_equal `operator>=`]
+
+ bool operator>=(const id& y) const;
+
+[variablelist
+
+[[Returns:] [`!(*this<y)`]]
+
+[[Throws:] [Nothing]]
+
+]
+
+[endsect]
+
+[section:stream_out Friend `operator<<`]
+
+ template<class charT, class traits>
+ friend std::basic_ostream<charT, traits>&
+ operator<<(std::basic_ostream<charT, traits>& os, const id& x);
+
+[variablelist
+
+[[Effects:] [Writes a representation of the __thread_id__ instance `x` to the stream `os`, such that the representation of two
+instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `a!=b`.]]
+
+[[Returns:] [`os`]]
+
+]
+
+[endsect]
+
+
+[endsect]
+
+[endsect]
+
+[section:this_thread Namespace `this_thread`]
+
+[section:get_id Non-member function `get_id()`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ thread::id get_id();
+ }
+
+[variablelist
+
+[[Returns:] [An instance of __thread_id__ that represents that currently executing thread.]]
+
+[[Throws:] [__thread_resource_error__ if an error occurs.]]
+
+]
+
+[endsect]
+
+[section:interruption_point Non-member function `interruption_point()`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ void interruption_point();
+ }
+
+[variablelist
+
+[[Effects:] [Check to see if the current thread has been interrupted.]]
+
+[[Throws:] [__thread_interrupted__ if __interruption_enabled__ and __interruption_requested__ both return `true`.]]
+
+]
+
+[endsect]
+
+[section:interruption_requested Non-member function `interruption_requested()`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ bool interruption_requested();
+ }
+
+[variablelist
+
+[[Returns:] [`true` if interruption has been requested for the current thread, `false` otherwise.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:interruption_enabled Non-member function `interruption_enabled()`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ bool interruption_enabled();
+ }
+
+[variablelist
+
+[[Returns:] [`true` if interruption has been enabled for the current thread, `false` otherwise.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[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.]]
+
+[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]]
+
+[[Notes:] [`sleep()` is one of the predefined __interruption_points__.]]
+
+]
+
+[endsect]
+
+[section:yield Non-member function `yield()`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ void yield();
+ }
+
+[variablelist
+
+[[Effects:] [Gives up the remainder of the current thread's time slice, to allow other threads to run.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:disable_interruption Class `disable_interruption`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ class disable_interruption
+ {
+ public:
+ disable_interruption();
+ ~disable_interruption();
+ };
+ }
+
+`boost::this_thread::disable_interruption` disables interruption for the current thread on construction, and restores the prior
+interruption state on destruction. Instances of `disable_interruption` cannot be copied or moved.
+
+[section:constructor Constructor]
+
+ disable_interruption();
+
+[variablelist
+
+[[Effects:] [Stores the current state of __interruption_enabled__ and disables interruption for the current thread.]]
+
+[[Postconditions:] [__interruption_enabled__ returns `false` for the current thread.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:destructor Destructor]
+
+ ~disable_interruption();
+
+[variablelist
+
+[[Preconditions:] [Must be called from the same thread from which `*this` was constructed.]]
+
+[[Effects:] [Restores the current state of __interruption_enabled__ for the current thread to that prior to the construction of `*this`.]]
+
+[[Postconditions:] [__interruption_enabled__ for the current thread returns the value stored in the constructor of `*this`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[section:restore_interruption Class `restore_interruption`]
+
+ #include <boost/thread/thread.hpp>
+
+ namespace this_thread
+ {
+ class restore_interruption
+ {
+ public:
+ explicit restore_interruption(disable_interruption& disabler);
+ ~restore_interruption();
+ };
+ }
+
+On construction of an instance of `boost::this_thread::restore_interruption`, the interruption state for the current thread is
+restored to the interruption state stored by the constructor of the supplied instance of __disable_interruption__. When the instance
+is destroyed, interruption is again disabled. Instances of `restore_interruption` cannot be copied or moved.
+
+[section:constructor Constructor]
+
+ explicit restore_interruption(disable_interruption& disabler);
+
+[variablelist
+
+[[Preconditions:] [Must be called from the same thread from which `disabler` was constructed.]]
+
+[[Effects:] [Restores the current state of __interruption_enabled__ for the current thread to that prior to the construction of `disabler`.]]
+
+[[Postconditions:] [__interruption_enabled__ for the current thread returns the value stored in the constructor of `disabler`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:destructor Destructor]
+
+ ~restore_interruption();
+
+[variablelist
+
+[[Preconditions:] [Must be called from the same thread from which `*this` was constructed.]]
+
+[[Effects:] [Disables interruption for the current thread.]]
+
+[[Postconditions:] [__interruption_enabled__ for the current thread returns `false`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[endsect]
+
+[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).]]
+
+[[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]
+
+[endsect]
+
+[section:threadgroup Class `thread_group`]
+
+ #include <boost/thread/thread.hpp>
+
+ class thread_group:
+ private noncopyable
+ {
+ public:
+ thread_group();
+ ~thread_group();
+
+ template<typename F>
+ thread* create_thread(F threadfunc);
+ void add_thread(thread* thrd);
+ void remove_thread(thread* thrd);
+ void join_all();
+ void interrupt_all();
+ int size() const;
+ };
+
+`thread_group` provides for a collection of threads that are related in some fashion. New threads can be added to the group with
+`add_thread` and `create_thread` member functions. `thread_group` is not copyable or movable.
+
+[section:constructor Constructor]
+
+ thread_group();
+
+[variablelist
+
+[[Effects:] [Create a new thread group with no threads.]]
+
+]
+
+[endsect]
+
+[section:destructor Destructor]
+
+ ~thread_group();
+
+[variablelist
+
+[[Effects:] [Destroy `*this` and `delete` all __thread__ objects in the group.]]
+
+]
+
+[endsect]
+
+[section:create_thread Member function `create_thread()`]
+
+ template<typename F>
+ thread* create_thread(F threadfunc);
+
+[variablelist
+
+[[Effects:] [Create a new __thread__ object as-if by `new thread(threadfunc)` and add it to the group.]]
+
+[[Postcondition:] [`this->size()` is increased by one, the new thread is running.]]
+
+[[Returns:] [A pointer to the new __thread__ object.]]
+
+]
+
+[endsect]
+
+[section:add_thread Member function `add_thread()`]
+
+ void add_thread(thread* thrd);
+
+[variablelist
+
+[[Precondition:] [The expression `delete thrd` is well-formed and will not result in undefined behaviour.]]
+
+[[Effects:] [Take ownership of the __thread__ object pointed to by `thrd` and add it to the group.]]
+
+[[Postcondition:] [`this->size()` is increased by one.]]
+
+]
+
+[endsect]
+
+[section:remove_thread Member function `remove_thread()`]
+
+ void remove_thread(thread* thrd);
+
+[variablelist
+
+[[Effects:] [If `thrd` is a member of the group, remove it without calling `delete`.]]
+
+[[Postcondition:] [If `thrd` was a member of the group, `this->size()` is decreased by one.]]
+
+]
+
+[endsect]
+
+[section:join_all Member function `join_all()`]
+
+ void join_all();
+
+[variablelist
+
+[[Effects:] [Call `join()` on each __thread__ object in the group.]]
+
+[[Postcondition:] [Every thread in the group has terminated.]]
+
+[[Note:] [Since __join__ is one of the predefined __interruption_points__, `join_all()` is also an interruption point.]]
+
+]
+
+[endsect]
+
+[section:interrupt_all Member function `interrupt_all()`]
+
+ void interrupt_all();
+
+[variablelist
+
+[[Effects:] [Call `interrupt()` on each __thread__ object in the group.]]
+
+]
+
+[endsect]
+
+[section:size Member function `size()`]
+
+ int size();
+
+[variablelist
+
+[[Returns:] [The number of threads in the group.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+
+[endsect]
+
+[endsect]
diff --git a/libs/thread/doc/time.qbk b/libs/thread/doc/time.qbk
new file mode 100644
index 0000000000..879854279a
--- /dev/null
+++ b/libs/thread/doc/time.qbk
@@ -0,0 +1,75 @@
+[/
+ (C) Copyright 2007-8 Anthony Williams.
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt).
+]
+
+[section:time Date and Time Requirements]
+
+As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a
+time out. These include (but are not limited to):
+
+* __sleep__
+* __timed_join__
+* __cond_timed_wait__
+* __timed_lock_ref__
+
+For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is
+required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link
+thread.time.get_system_time `boost::get_system_time()`]. e.g.
+
+ boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500);
+
+ extern bool done;
+ extern boost::mutex m;
+ extern boost::condition_variable cond;
+
+ boost::unique_lock<boost::mutex> lk(m);
+ while(!done)
+ {
+ if(!cond.timed_wait(lk,timeout))
+ {
+ throw "timed out";
+ }
+ }
+
+For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link
+date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g.
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(25));
+
+ boost::mutex m;
+ if(m.timed_lock(boost::posix_time::nanoseconds(100)))
+ {
+ // ...
+ }
+
+[section:system_time Typedef `system_time`]
+
+ #include <boost/thread/thread_time.hpp>
+
+ typedef boost::posix_time::ptime system_time;
+
+See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library.
+
+[endsect]
+
+[section:get_system_time Non-member function `get_system_time()`]
+
+ #include <boost/thread/thread_time.hpp>
+
+ system_time get_system_time();
+
+[variablelist
+
+[[Returns:] [The current time.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+
+[endsect] \ No newline at end of file
diff --git a/libs/thread/doc/tss.qbk b/libs/thread/doc/tss.qbk
new file mode 100644
index 0000000000..150bc0253f
--- /dev/null
+++ b/libs/thread/doc/tss.qbk
@@ -0,0 +1,189 @@
+[/
+ (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]
+
+Thread local storage allows multi-threaded applications to have a separate instance of a given data item for each thread. Where a
+single-threaded application would use static or global data, this could lead to contention, deadlock or data corruption in a
+multi-threaded application. One example is the C `errno` variable, used for storing the error code related to functions from the
+Standard C library. It is common practice (and required by POSIX) for compilers that support multi-threaded applications to provide
+a separate instance of `errno` for each thread, in order to avoid different threads competing to read or update the value.
+
+Though compilers often provide this facility in the form of extensions to the declaration syntax (such as `__declspec(thread)` or
+`__thread` annotations on `static` or namespace-scope variable declarations), such support is non-portable, and is often limited in
+some way, such as only supporting POD types.
+
+[heading Portable thread-local storage with `boost::thread_specific_ptr`]
+
+`boost::thread_specific_ptr` provides a portable mechanism for thread-local storage that works on all compilers supported by
+__boost_thread__. Each instance of `boost::thread_specific_ptr` represents a pointer to an object (such as `errno`) where each
+thread must have a distinct value. The value for the current thread can be obtained using the `get()` member function, or by using
+the `*` and `->` pointer deference operators. Initially the pointer has a value of `NULL` in each thread, but the value for the
+current thread can be set using the `reset()` member function.
+
+If the value of the pointer for the current thread is changed using `reset()`, then the previous value is destroyed by calling the
+cleanup routine. Alternatively, the stored value can be reset to `NULL` and the prior value returned by calling the `release()`
+member function, allowing the application to take back responsibility for destroying the object.
+
+[heading Cleanup at thread exit]
+
+When a thread exits, the objects associated with each `boost::thread_specific_ptr` instance are destroyed. By default, the object
+pointed to by a pointer `p` is destroyed by invoking `delete p`, but this can be overridden for a specific instance of
+`boost::thread_specific_ptr` by providing a cleanup routine to the constructor. In this case, the object is destroyed by invoking
+`func(p)` where `func` is the cleanup routine supplied to the constructor. The cleanup functions are called in an unspecified
+order. If a cleanup routine sets the value of associated with an instance of `boost::thread_specific_ptr` that has already been
+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
+ {
+ public:
+ thread_specific_ptr();
+ explicit thread_specific_ptr(void (*cleanup_function)(T*));
+ ~thread_specific_ptr();
+
+ T* get() const;
+ T* operator->() const;
+ T& operator*() const;
+
+ T* release();
+ void reset(T* new_value=0);
+ };
+
+[section:default_constructor `thread_specific_ptr();`]
+
+[variablelist
+
+[[Requires:] [`delete this->get()` is well-formed.]]
+
+[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
+default `delete`-based cleanup function will be used to destroy any thread-local objects when `reset()` is called, or the thread
+exits.]]
+
+[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
+
+]
+
+[endsect]
+
+[section:constructor_with_custom_cleanup `explicit thread_specific_ptr(void (*cleanup_function)(T*));`]
+
+[variablelist
+
+[[Requires:] [`cleanup_function(this->get())` does not throw any exceptions.]]
+
+[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
+supplied `cleanup_function` will be used to destroy any thread-local objects when `reset()` is called, or the thread exits.]]
+
+[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
+
+]
+
+[endsect]
+
+[section:destructor `~thread_specific_ptr();`]
+
+[variablelist
+
+[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been
+destroyed do not call any member functions on that instance.]
+
+[endsect]
+
+[section:get `T* get() const;`]
+
+[variablelist
+
+[[Returns:] [The pointer associated with the current thread.]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[note The initial value associated with an instance of `boost::thread_specific_ptr` is `NULL` for each thread.]
+
+[endsect]
+
+[section:operator_arrow `T* operator->() const;`]
+
+[variablelist
+
+[[Returns:] [`this->get()`]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:operator_star `T& operator*() const;`]
+
+[variablelist
+
+[[Requires:] [`this->get` is not `NULL`.]]
+
+[[Returns:] [`*(this->get())`]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+[section:reset `void reset(T* new_value=0);`]
+
+[variablelist
+
+[[Effects:] [If `this->get()!=new_value` and `this->get()` is non-`NULL`, invoke `delete this->get()` or
+`cleanup_function(this->get())` as appropriate. Store `new_value` as the pointer associated with the current thread.]]
+
+[[Postcondition:] [`this->get()==new_value`]]
+
+[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
+
+]
+
+[endsect]
+
+[section:release `T* release();`]
+
+[variablelist
+
+[[Effects:] [Return `this->get()` and store `NULL` as the pointer associated with the current thread without invoking the cleanup
+function.]]
+
+[[Postcondition:] [`this->get()==0`]]
+
+[[Throws:] [Nothing.]]
+
+]
+
+[endsect]
+
+
+[endsect]
+
+[endsect]
diff --git a/libs/thread/example/Jamfile.v2 b/libs/thread/example/Jamfile.v2
new file mode 100644
index 0000000000..bfc8a59b3c
--- /dev/null
+++ b/libs/thread/example/Jamfile.v2
@@ -0,0 +1,23 @@
+# 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)
+
+project boost/thread/example
+ : requirements <library>../build//boost_thread <threading>multi
+ ;
+
+
+exe monitor : monitor.cpp ;
+exe starvephil : starvephil.cpp ;
+exe tennis : tennis.cpp ;
+exe condition : condition.cpp ;
+exe mutex : mutex.cpp ;
+exe once : once.cpp ;
+exe recursive_mutex : recursive_mutex.cpp ;
+exe thread : thread.cpp ;
+exe thread_group : thread_group.cpp ;
+exe tss : tss.cpp ;
+exe xtime : xtime.cpp ;
+
diff --git a/libs/thread/example/condition.cpp b/libs/thread/example/condition.cpp
new file mode 100644
index 0000000000..7430e4621d
--- /dev/null
+++ b/libs/thread/example/condition.cpp
@@ -0,0 +1,89 @@
+// 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 <iostream>
+#include <vector>
+#include <boost/utility.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+class bounded_buffer : private boost::noncopyable
+{
+public:
+ typedef boost::mutex::scoped_lock lock;
+
+ bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
+
+ void send (int m) {
+ lock lk(monitor);
+ while (buffered == circular_buf.size())
+ buffer_not_full.wait(lk);
+ circular_buf[end] = m;
+ end = (end+1) % circular_buf.size();
+ ++buffered;
+ buffer_not_empty.notify_one();
+ }
+ int receive() {
+ lock lk(monitor);
+ while (buffered == 0)
+ buffer_not_empty.wait(lk);
+ int i = circular_buf[begin];
+ begin = (begin+1) % circular_buf.size();
+ --buffered;
+ buffer_not_full.notify_one();
+ return i;
+ }
+
+private:
+ int begin, end, buffered;
+ std::vector<int> circular_buf;
+ boost::condition buffer_not_full, buffer_not_empty;
+ boost::mutex monitor;
+};
+
+bounded_buffer buf(2);
+
+boost::mutex io_mutex;
+
+void sender() {
+ int n = 0;
+ while (n < 1000000) {
+ buf.send(n);
+ if(!(n%10000))
+ {
+ boost::mutex::scoped_lock io_lock(io_mutex);
+ std::cout << "sent: " << n << std::endl;
+ }
+ ++n;
+ }
+ buf.send(-1);
+}
+
+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;
+}
diff --git a/libs/thread/example/monitor.cpp b/libs/thread/example/monitor.cpp
new file mode 100644
index 0000000000..0a7383fb47
--- /dev/null
+++ b/libs/thread/example/monitor.cpp
@@ -0,0 +1,112 @@
+// 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 <vector>
+#include <iostream>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+
+namespace {
+const int ITERS = 100;
+boost::mutex io_mutex;
+} // namespace
+
+template <typename M>
+class buffer_t
+{
+public:
+ typedef typename M::scoped_lock scoped_lock;
+
+ buffer_t(int n)
+ : p(0), c(0), full(0), buf(n)
+ {
+ }
+
+ void send(int m)
+ {
+ scoped_lock lk(mutex);
+ while (full == buf.size())
+ cond.wait(lk);
+ buf[p] = m;
+ p = (p+1) % buf.size();
+ ++full;
+ cond.notify_one();
+ }
+ int receive()
+ {
+ scoped_lock lk(mutex);
+ while (full == 0)
+ cond.wait(lk);
+ int i = buf[c];
+ c = (c+1) % buf.size();
+ --full;
+ cond.notify_one();
+ return i;
+ }
+
+ static buffer_t& get_buffer()
+ {
+ static buffer_t buf(2);
+ return buf;
+ }
+
+ static void do_sender_thread()
+ {
+ for (int n = 0; n < ITERS; ++n)
+ {
+ {
+ boost::mutex::scoped_lock lock(io_mutex);
+ std::cout << "sending: " << n << std::endl;
+ }
+ get_buffer().send(n);
+ }
+ }
+
+ static void do_receiver_thread()
+ {
+ for (int x=0; x < (ITERS/2); ++x)
+ {
+ int n = get_buffer().receive();
+ {
+ boost::mutex::scoped_lock lock(io_mutex);
+ std::cout << "received: " << n << std::endl;
+ }
+ }
+ }
+
+private:
+ M mutex;
+ boost::condition cond;
+ unsigned int p, c, full;
+ std::vector<int> buf;
+};
+
+template <typename M>
+void do_test(M* dummy=0)
+{
+ typedef buffer_t<M> buffer_type;
+ buffer_type::get_buffer();
+ boost::thread thrd1(&buffer_type::do_receiver_thread);
+ boost::thread thrd2(&buffer_type::do_receiver_thread);
+ boost::thread thrd3(&buffer_type::do_sender_thread);
+ thrd1.join();
+ thrd2.join();
+ thrd3.join();
+}
+
+void test_buffer()
+{
+ do_test<boost::mutex>();
+ do_test<boost::recursive_mutex>();
+}
+
+int main()
+{
+ test_buffer();
+ return 0;
+}
diff --git a/libs/thread/example/mutex.cpp b/libs/thread/example/mutex.cpp
new file mode 100644
index 0000000000..b276d54909
--- /dev/null
+++ b/libs/thread/example/mutex.cpp
@@ -0,0 +1,47 @@
+// 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/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
+
+class counter
+{
+public:
+ counter() : count(0) { }
+
+ int increment() {
+ boost::mutex::scoped_lock scoped_lock(mutex);
+ return ++count;
+ }
+
+private:
+ boost::mutex mutex;
+ int count;
+};
+
+counter c;
+
+void change_count()
+{
+ int i = c.increment();
+ boost::mutex::scoped_lock scoped_lock(io_mutex);
+ std::cout << "count == " << i << std::endl;
+}
+
+int main(int, char*[])
+{
+ const int num_threads = 4;
+ boost::thread_group thrds;
+ for (int i=0; i < num_threads; ++i)
+ thrds.create_thread(&change_count);
+
+ thrds.join_all();
+
+ return 0;
+}
diff --git a/libs/thread/example/once.cpp b/libs/thread/example/once.cpp
new file mode 100644
index 0000000000..5a5b6f5589
--- /dev/null
+++ b/libs/thread/example/once.cpp
@@ -0,0 +1,31 @@
+// 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/thread.hpp>
+#include <boost/thread/once.hpp>
+#include <cassert>
+
+int value=0;
+boost::once_flag once = BOOST_ONCE_INIT;
+
+void init()
+{
+ ++value;
+}
+
+void thread_proc()
+{
+ boost::call_once(&init, once);
+}
+
+int main(int argc, char* argv[])
+{
+ boost::thread_group threads;
+ for (int i=0; i<5; ++i)
+ threads.create_thread(&thread_proc);
+ threads.join_all();
+ assert(value == 1);
+}
diff --git a/libs/thread/example/recursive_mutex.cpp b/libs/thread/example/recursive_mutex.cpp
new file mode 100644
index 0000000000..c5199545de
--- /dev/null
+++ b/libs/thread/example/recursive_mutex.cpp
@@ -0,0 +1,49 @@
+// 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/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+class counter
+{
+public:
+ counter() : count(0) { }
+
+ int add(int val) {
+ boost::recursive_mutex::scoped_lock scoped_lock(mutex);
+ count += val;
+ return count;
+ }
+ int increment() {
+ boost::recursive_mutex::scoped_lock scoped_lock(mutex);
+ return add(1);
+ }
+
+private:
+ boost::recursive_mutex mutex;
+ int count;
+};
+
+counter c;
+
+void change_count()
+{
+ std::cout << "count == " << c.increment() << std::endl;
+}
+
+int main(int, char*[])
+{
+ const int num_threads=4;
+
+ boost::thread_group threads;
+ for (int i=0; i < num_threads; ++i)
+ threads.create_thread(&change_count);
+
+ threads.join_all();
+
+ return 0;
+}
diff --git a/libs/thread/example/starvephil.cpp b/libs/thread/example/starvephil.cpp
new file mode 100644
index 0000000000..0ef2e0d32d
--- /dev/null
+++ b/libs/thread/example/starvephil.cpp
@@ -0,0 +1,185 @@
+// 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/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <iostream>
+#include <time.h>
+
+namespace
+{
+boost::mutex iomx;
+} // namespace
+
+class canteen
+{
+public:
+ canteen() : m_chickens(0) { }
+
+ void get(int id)
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+ while (m_chickens == 0)
+ {
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << id <<
+ ": wot, no chickens? I'll WAIT ..." << std::endl;
+ }
+ m_condition.wait(lock);
+ }
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << id <<
+ ": those chickens look good ... one please ..." << std::endl;
+ }
+ m_chickens--;
+ }
+ void put(int value)
+ {
+ boost::mutex::scoped_lock lock(m_mutex);
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock()
+ << ") Chef: ouch ... make room ... this dish is "
+ << "very hot ..." << std::endl;
+ }
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 3;
+ boost::thread::sleep(xt);
+ m_chickens += value;
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() <<
+ ") Chef: more chickens ... " << m_chickens <<
+ " now available ... NOTIFYING ..." << std::endl;
+ }
+ m_condition.notify_all();
+ }
+
+private:
+ boost::mutex m_mutex;
+ boost::condition m_condition;
+ int m_chickens;
+};
+
+canteen g_canteen;
+
+void chef()
+{
+ const int chickens = 4;
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
+ }
+ for (;;)
+ {
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
+ }
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 2;
+ boost::thread::sleep(xt);
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Chef: " << chickens
+ << " chickens, ready-to-go ..." << std::endl;
+ }
+ g_canteen.put(chickens);
+ }
+}
+
+struct phil
+{
+ phil(int id) : m_id(id) { }
+ void run() {
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << m_id
+ << ": starting ..." << std::endl;
+ }
+ for (;;)
+ {
+ if (m_id > 0)
+ {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 3;
+ boost::thread::sleep(xt);
+ }
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << m_id
+ << ": gotta eat ..." << std::endl;
+ }
+ g_canteen.get(m_id);
+ {
+ boost::mutex::scoped_lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << m_id
+ << ": mmm ... that's good ..." << std::endl;
+ }
+ }
+ }
+ static void do_thread(void* param) {
+ static_cast<phil*>(param)->run();
+ }
+
+ int m_id;
+};
+
+struct thread_adapt
+{
+ thread_adapt(void (*func)(void*), void* param)
+ : _func(func), _param(param)
+ {
+ }
+ int operator()() const
+ {
+ _func(_param);
+ return 0;
+ }
+
+ void (*_func)(void*);
+ void* _param;
+};
+
+class thread_adapter
+{
+public:
+ thread_adapter(void (*func)(void*), void* param)
+ : _func(func), _param(param)
+ {
+ }
+ void operator()() const { _func(_param); }
+private:
+ void (*_func)(void*);
+ void* _param;
+};
+
+int main(int argc, char* argv[])
+{
+ boost::thread thrd_chef(&chef);
+ phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
+ boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
+ boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
+ boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
+ boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
+ boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
+
+ thrd_chef.join();
+ thrd_phil0.join();
+ thrd_phil1.join();
+ thrd_phil2.join();
+ thrd_phil3.join();
+ thrd_phil4.join();
+
+ return 0;
+}
diff --git a/libs/thread/example/tennis.cpp b/libs/thread/example/tennis.cpp
new file mode 100644
index 0000000000..798f55e5d8
--- /dev/null
+++ b/libs/thread/example/tennis.cpp
@@ -0,0 +1,135 @@
+// 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/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <iostream>
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include <windows.h>
+# include <process.h>
+#endif
+
+enum game_state
+{
+ START,
+ PLAYER_A,
+ PLAYER_B,
+ GAME_OVER,
+ ONE_PLAYER_GONE,
+ BOTH_PLAYERS_GONE
+};
+
+int state;
+boost::mutex mutex;
+boost::condition cond;
+
+char* player_name(int state)
+{
+ if (state == PLAYER_A)
+ return "PLAYER-A";
+ if (state == PLAYER_B)
+ return "PLAYER-B";
+ throw "bad player";
+ return 0;
+}
+
+void player(void* param)
+{
+ boost::mutex::scoped_lock lock(mutex);
+
+ int active = (int)param;
+ int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
+
+ while (state < GAME_OVER)
+ {
+ std::cout << player_name(active) << ": Play." << std::endl;
+ state = other;
+ cond.notify_all();
+ do
+ {
+ cond.wait(lock);
+ if (state == other)
+ {
+ std::cout << "---" << player_name(active)
+ << ": Spurious wakeup!" << std::endl;
+ }
+ } while (state == other);
+ }
+
+ ++state;
+ std::cout << player_name(active) << ": Gone." << std::endl;
+ cond.notify_all();
+}
+
+struct thread_adapt
+{
+ thread_adapt(void (*func)(void*), void* param)
+ : _func(func), _param(param)
+ {
+ }
+ int operator()() const
+ {
+ _func(_param);
+ return 0;
+ }
+
+ void (*_func)(void*);
+ void* _param;
+};
+
+class thread_adapter
+{
+public:
+ thread_adapter(void (*func)(void*), void* param)
+ : _func(func), _param(param)
+ {
+ }
+ void operator()() const { _func(_param); }
+private:
+ void (*_func)(void*);
+ void* _param;
+};
+
+int main(int argc, char* argv[])
+{
+ state = START;
+
+ boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
+ boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
+
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ std::cout << "---Noise ON..." << std::endl;
+ }
+
+ for (int i = 0; i < 1000000000; ++i)
+ cond.notify_all();
+
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ std::cout << "---Noise OFF..." << std::endl;
+ state = GAME_OVER;
+ cond.notify_all();
+ do
+ {
+ cond.wait(lock);
+ } while (state != BOTH_PLAYERS_GONE);
+ }
+
+ std::cout << "GAME OVER" << std::endl;
+
+ thrda.join();
+ thrdb.join();
+
+ return 0;
+}
diff --git a/libs/thread/example/thread.cpp b/libs/thread/example/thread.cpp
new file mode 100644
index 0000000000..c21a3b5ea8
--- /dev/null
+++ b/libs/thread/example/thread.cpp
@@ -0,0 +1,35 @@
+// 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/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <iostream>
+
+struct thread_alarm
+{
+ thread_alarm(int secs) : m_secs(secs) { }
+ void operator()()
+ {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += m_secs;
+
+ boost::thread::sleep(xt);
+
+ std::cout << "alarm sounded..." << std::endl;
+ }
+
+ int m_secs;
+};
+
+int main(int argc, char* argv[])
+{
+ int secs = 5;
+ std::cout << "setting alarm for 5 seconds..." << std::endl;
+ thread_alarm alarm(secs);
+ boost::thread thrd(alarm);
+ thrd.join();
+}
diff --git a/libs/thread/example/thread_group.cpp b/libs/thread/example/thread_group.cpp
new file mode 100644
index 0000000000..232776dc62
--- /dev/null
+++ b/libs/thread/example/thread_group.cpp
@@ -0,0 +1,25 @@
+// 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/thread.hpp>
+#include <iostream>
+
+int count = 0;
+boost::mutex mutex;
+
+void increment_count()
+{
+ boost::mutex::scoped_lock lock(mutex);
+ std::cout << "count = " << ++count << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ boost::thread_group threads;
+ for (int i = 0; i < 10; ++i)
+ threads.create_thread(&increment_count);
+ threads.join_all();
+}
diff --git a/libs/thread/example/tss.cpp b/libs/thread/example/tss.cpp
new file mode 100644
index 0000000000..f867a9180a
--- /dev/null
+++ b/libs/thread/example/tss.cpp
@@ -0,0 +1,36 @@
+// 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/thread.hpp>
+#include <boost/thread/tss.hpp>
+#include <cassert>
+
+boost::thread_specific_ptr<int> value;
+
+void increment()
+{
+ int* p = value.get();
+ ++*p;
+}
+
+void thread_proc()
+{
+ value.reset(new int(0)); // initialize the thread's storage
+ for (int i=0; i<10; ++i)
+ {
+ increment();
+ int* p = value.get();
+ assert(*p == i+1);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ boost::thread_group threads;
+ for (int i=0; i<5; ++i)
+ threads.create_thread(&thread_proc);
+ threads.join_all();
+}
diff --git a/libs/thread/example/xtime.cpp b/libs/thread/example/xtime.cpp
new file mode 100644
index 0000000000..a9b1933908
--- /dev/null
+++ b/libs/thread/example/xtime.cpp
@@ -0,0 +1,16 @@
+// 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/thread.hpp>
+#include <boost/thread/xtime.hpp>
+
+int main(int argc, char* argv[])
+{
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt); // Sleep for 1 second
+}
diff --git a/libs/thread/index.html b/libs/thread/index.html
new file mode 100644
index 0000000000..f54e21e2fb
--- /dev/null
+++ b/libs/thread/index.html
@@ -0,0 +1,13 @@
+<!-- Copyright (c) 2002-2003 William E. Kempf.
+ Subject to the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+-->
+
+<html>
+<head>
+<meta http-equiv="refresh" content="0; URL=doc/index.html">
+</head>
+<body>
+Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
+</body>
+</html>
diff --git a/libs/thread/src/pthread/once.cpp b/libs/thread/src/pthread/once.cpp
new file mode 100644
index 0000000000..6e0466f17e
--- /dev/null
+++ b/libs/thread/src/pthread/once.cpp
@@ -0,0 +1,53 @@
+// 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)
+
+#define __STDC_CONSTANT_MACROS
+#include <boost/thread/once.hpp>
+#include <boost/assert.hpp>
+#include <pthread.h>
+#include <stdlib.h>
+
+namespace boost
+{
+ namespace detail
+ {
+ BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
+ BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
+ BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
+
+ namespace
+ {
+ pthread_key_t epoch_tss_key;
+ pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
+
+ extern "C"
+ {
+ 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));
+ }
+ }
+ }
+
+ boost::uintmax_t& get_once_per_thread_epoch()
+ {
+ BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
+ void* data=pthread_getspecific(epoch_tss_key);
+ if(!data)
+ {
+ data=malloc(sizeof(boost::uintmax_t));
+ BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
+ *static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
+ }
+ return *static_cast<boost::uintmax_t*>(data);
+ }
+ }
+
+}
diff --git a/libs/thread/src/pthread/thread.cpp b/libs/thread/src/pthread/thread.cpp
new file mode 100644
index 0000000000..07b8458bce
--- /dev/null
+++ b/libs/thread/src/pthread/thread.cpp
@@ -0,0 +1,606 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/once.hpp>
+#include <boost/thread/tss.hpp>
+#include <boost/throw_exception.hpp>
+#ifdef __GLIBC__
+#include <sys/sysinfo.h>
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#elif defined BOOST_HAS_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "timeconv.inl"
+
+namespace boost
+{
+ namespace detail
+ {
+ thread_data_base::~thread_data_base()
+ {}
+
+ struct thread_exit_callback_node
+ {
+ boost::detail::thread_exit_function_base* func;
+ thread_exit_callback_node* next;
+
+ thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
+ thread_exit_callback_node* next_):
+ func(func_),next(next_)
+ {}
+ };
+
+ namespace
+ {
+ boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
+ pthread_key_t current_thread_tls_key;
+
+ extern "C"
+ {
+ static 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->thread_exit_callbacks)
+ {
+ detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
+ thread_info->thread_exit_callbacks=current_node->next;
+ if(current_node->func)
+ {
+ (*current_node->func)();
+ delete current_node->func;
+ }
+ 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;)
+ {
+ current=next;
+ ++next;
+ if(current->second.func && (current->second.value!=0))
+ {
+ (*current->second.func)(current->second.value);
+ }
+ thread_info->tss_data.erase(current);
+ }
+ }
+ 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);
+ return (boost::detail::thread_data_base*)pthread_getspecific(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);
+ BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
+ }
+ }
+
+ namespace
+ {
+ extern "C"
+ {
+ static void* thread_proxy(void* param)
+ {
+ boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
+ thread_info->self.reset();
+ detail::set_current_thread_data(thread_info.get());
+ try
+ {
+ thread_info->run();
+ }
+ catch(thread_interrupted const&)
+ {
+ }
+// Removed as it stops the debugger identifying the cause of the exception
+// Unhandled exceptions still cause the application to terminate
+// catch(...)
+// {
+// std::terminate();
+// }
+
+ detail::tls_destructor(thread_info.get());
+ detail::set_current_thread_data(0);
+ boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
+ thread_info->done=true;
+ thread_info->done_condition.notify_all();
+ return 0;
+ }
+ }
+
+ struct externally_launched_thread:
+ detail::thread_data_base
+ {
+ externally_launched_thread()
+ {
+ interrupt_enabled=false;
+ }
+
+ void run()
+ {}
+
+ private:
+ externally_launched_thread(externally_launched_thread&);
+ void operator=(externally_launched_thread&);
+ };
+
+ detail::thread_data_base* make_external_thread_data()
+ {
+ detail::thread_data_base* const me(new externally_launched_thread());
+ me->self.reset(me);
+ set_current_thread_data(me);
+ return me;
+ }
+
+
+ detail::thread_data_base* get_or_make_current_thread_data()
+ {
+ detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
+ if(!current_thread_data)
+ {
+ current_thread_data=make_external_thread_data();
+ }
+ return current_thread_data;
+ }
+
+ }
+
+
+ thread::thread()
+ {}
+
+ void thread::start_thread()
+ {
+ thread_info->self=thread_info;
+ int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
+ if (res != 0)
+ {
+ thread_info->self.reset();
+ boost::throw_exception(thread_resource_error());
+ }
+ }
+
+ thread::~thread()
+ {
+ detach();
+ }
+
+ detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
+ {
+ return thread_info;
+ }
+
+ void thread::join()
+ {
+ 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)
+ {
+ local_thread_info->done_condition.wait(lock);
+ }
+ do_join=!local_thread_info->join_started;
+
+ if(do_join)
+ {
+ local_thread_info->join_started=true;
+ }
+ else
+ {
+ while(!local_thread_info->joined)
+ {
+ local_thread_info->done_condition.wait(lock);
+ }
+ }
+ }
+ if(do_join)
+ {
+ void* result=0;
+ BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
+ lock_guard<mutex> lock(local_thread_info->data_mutex);
+ local_thread_info->joined=true;
+ local_thread_info->done_condition.notify_all();
+ }
+
+ if(thread_info==local_thread_info)
+ {
+ thread_info.reset();
+ }
+ }
+ }
+
+ bool thread::timed_join(system_time const& wait_until)
+ {
+ 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)
+ {
+ if(!local_thread_info->done_condition.timed_wait(lock,wait_until))
+ {
+ return false;
+ }
+ }
+ do_join=!local_thread_info->join_started;
+
+ if(do_join)
+ {
+ local_thread_info->join_started=true;
+ }
+ else
+ {
+ while(!local_thread_info->joined)
+ {
+ local_thread_info->done_condition.wait(lock);
+ }
+ }
+ }
+ if(do_join)
+ {
+ void* result=0;
+ BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
+ lock_guard<mutex> lock(local_thread_info->data_mutex);
+ local_thread_info->joined=true;
+ local_thread_info->done_condition.notify_all();
+ }
+
+ if(thread_info==local_thread_info)
+ {
+ thread_info.reset();
+ }
+ }
+ return true;
+ }
+
+ bool thread::joinable() const
+ {
+ return (get_thread_info)();
+ }
+
+
+ void thread::detach()
+ {
+ detail::thread_data_ptr local_thread_info;
+ thread_info.swap(local_thread_info);
+
+ if(local_thread_info)
+ {
+ lock_guard<mutex> lock(local_thread_info->data_mutex);
+ if(!local_thread_info->join_started)
+ {
+ BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
+ local_thread_info->join_started=true;
+ local_thread_info->joined=true;
+ }
+ }
+ }
+
+ 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);
+ while(thread_info->sleep_condition.timed_wait(lk,st));
+ }
+ else
+ {
+ xtime const xt=get_xtime(st);
+
+ for (int foo=0; foo < 5; ++foo)
+ {
+# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
+ timespec ts;
+ to_timespec_duration(xt, ts);
+ BOOST_VERIFY(!pthread_delay_np(&ts));
+# 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);
+# else
+ mutex mx;
+ mutex::scoped_lock lock(mx);
+ condition cond;
+ cond.timed_wait(lock, xt);
+# endif
+ xtime cur;
+ xtime_get(&cur, TIME_UTC);
+ if (xtime_cmp(xt, cur) <= 0)
+ return;
+ }
+ }
+ }
+
+ void yield()
+ {
+# if defined(BOOST_HAS_SCHED_YIELD)
+ BOOST_VERIFY(!sched_yield());
+# elif defined(BOOST_HAS_PTHREAD_YIELD)
+ BOOST_VERIFY(!pthread_yield());
+# else
+ xtime xt;
+ xtime_get(&xt, TIME_UTC);
+ sleep(xt);
+# endif
+ }
+ }
+
+ unsigned thread::hardware_concurrency()
+ {
+#if defined(PTW32_VERSION) || defined(__hpux)
+ return pthread_num_processors_np();
+#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)
+ int const count=sysconf(_SC_NPROCESSORS_ONLN);
+ return (count>0)?count:0;
+#elif defined(__GLIBC__)
+ return get_nprocs();
+#else
+ return 0;
+#endif
+ }
+
+ thread::id thread::get_id() const
+ {
+ detail::thread_data_ptr const local_thread_info=(get_thread_info)();
+ if(local_thread_info)
+ {
+ return id(local_thread_info);
+ }
+ else
+ {
+ return id();
+ }
+ }
+
+ void thread::interrupt()
+ {
+ 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));
+ }
+ }
+ }
+
+ bool thread::interruption_requested() const
+ {
+ detail::thread_data_ptr const local_thread_info=(get_thread_info)();
+ if(local_thread_info)
+ {
+ lock_guard<mutex> lk(local_thread_info->data_mutex);
+ return local_thread_info->interrupt_requested;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ thread::native_handle_type thread::native_handle()
+ {
+ detail::thread_data_ptr const local_thread_info=(get_thread_info)();
+ if(local_thread_info)
+ {
+ lock_guard<mutex> lk(local_thread_info->data_mutex);
+ return local_thread_info->thread_handle;
+ }
+ else
+ {
+ return pthread_t();
+ }
+ }
+
+
+
+ namespace this_thread
+ {
+ thread::id get_id()
+ {
+ boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
+ return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr());
+ }
+
+ void interruption_point()
+ {
+ boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
+ if(thread_info && thread_info->interrupt_enabled)
+ {
+ lock_guard<mutex> lg(thread_info->data_mutex);
+ if(thread_info->interrupt_requested)
+ {
+ thread_info->interrupt_requested=false;
+ throw thread_interrupted();
+ }
+ }
+ }
+
+ 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();
+ if(!thread_info)
+ {
+ return false;
+ }
+ else
+ {
+ lock_guard<mutex> lg(thread_info->data_mutex);
+ return thread_info->interrupt_requested;
+ }
+ }
+
+ disable_interruption::disable_interruption():
+ interruption_was_enabled(interruption_enabled())
+ {
+ if(interruption_was_enabled)
+ {
+ detail::get_current_thread_data()->interrupt_enabled=false;
+ }
+ }
+
+ disable_interruption::~disable_interruption()
+ {
+ if(detail::get_current_thread_data())
+ {
+ detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
+ }
+ }
+
+ restore_interruption::restore_interruption(disable_interruption& d)
+ {
+ if(d.interruption_was_enabled)
+ {
+ detail::get_current_thread_data()->interrupt_enabled=true;
+ }
+ }
+
+ restore_interruption::~restore_interruption()
+ {
+ if(detail::get_current_thread_data())
+ {
+ detail::get_current_thread_data()->interrupt_enabled=false;
+ }
+ }
+ }
+
+ namespace detail
+ {
+ void add_thread_exit_function(thread_exit_function_base* func)
+ {
+ detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
+ thread_exit_callback_node* const new_node=
+ new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
+ current_thread_data->thread_exit_callbacks=new_node;
+ }
+
+ tss_data_node* find_tss_data(void const* key)
+ {
+ 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())
+ {
+ return &current_node->second;
+ }
+ }
+ return NULL;
+ }
+
+ void* get_tss_data(void const* key)
+ {
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ return current_node->value;
+ }
+ 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)
+ {
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ if(cleanup_existing && current_node->func && (current_node->value!=0))
+ {
+ (*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);
+ }
+ }
+ else
+ {
+ add_new_tss_node(key,func,tss_data);
+ }
+ }
+ }
+
+
+}
diff --git a/libs/thread/src/pthread/timeconv.inl b/libs/thread/src/pthread/timeconv.inl
new file mode 100644
index 0000000000..1c0a0cdca8
--- /dev/null
+++ b/libs/thread/src/pthread/timeconv.inl
@@ -0,0 +1,132 @@
+// 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;
+const int NANOSECONDS_PER_MILLISECOND = 1000000;
+
+const int MICROSECONDS_PER_SECOND = 1000000;
+const int NANOSECONDS_PER_MICROSECOND = 1000;
+
+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;
+
+ xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
+ xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
+ NANOSECONDS_PER_MILLISECOND);
+
+ if (xt.nsec >= NANOSECONDS_PER_SECOND)
+ {
+ ++xt.sec;
+ xt.nsec -= NANOSECONDS_PER_SECOND;
+ }
+}
+#if defined(BOOST_HAS_PTHREADS)
+inline void to_timespec(const boost::xtime& xt, timespec& ts)
+{
+ ts.tv_sec = static_cast<int>(xt.sec);
+ ts.tv_nsec = static_cast<int>(xt.nsec);
+ if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
+ {
+ ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
+ ts.tv_nsec %= NANOSECONDS_PER_SECOND;
+ }
+}
+
+inline void to_time(int milliseconds, timespec& ts)
+{
+ boost::xtime xt;
+ to_time(milliseconds, xt);
+ to_timespec(xt, ts);
+}
+
+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;
+
+ if (boost::xtime_cmp(xt, cur) <= 0)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ else
+ {
+ ts.tv_sec = xt.sec - cur.sec;
+ ts.tv_nsec = xt.nsec - cur.nsec;
+
+ if( ts.tv_nsec < 0 )
+ {
+ ts.tv_sec -= 1;
+ ts.tv_nsec += NANOSECONDS_PER_SECOND;
+ }
+ if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
+ {
+ ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
+ ts.tv_nsec %= NANOSECONDS_PER_SECOND;
+ }
+ }
+}
+#endif
+
+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;
+
+ if (boost::xtime_cmp(xt, cur) <= 0)
+ milliseconds = 0;
+ else
+ {
+ if (cur.nsec > xt.nsec)
+ {
+ xt.nsec += NANOSECONDS_PER_SECOND;
+ --xt.sec;
+ }
+ milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
+ (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
+ NANOSECONDS_PER_MILLISECOND);
+ }
+}
+
+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;
+
+ if (boost::xtime_cmp(xt, cur) <= 0)
+ microseconds = 0;
+ else
+ {
+ if (cur.nsec > xt.nsec)
+ {
+ xt.nsec += NANOSECONDS_PER_SECOND;
+ --xt.sec;
+ }
+ microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
+ (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
+ NANOSECONDS_PER_MICROSECOND);
+ }
+}
+}
+
+// Change Log:
+// 1 Jun 01 Initial creation.
diff --git a/libs/thread/src/tss_null.cpp b/libs/thread/src/tss_null.cpp
new file mode 100644
index 0000000000..e93ba0ff73
--- /dev/null
+++ b/libs/thread/src/tss_null.cpp
@@ -0,0 +1,38 @@
+// (C) Copyright Michael Glassford 2004.
+// (C) Copyright 2007 Anthony Williams
+// Use, modification and distribution are subject to 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>
+
+#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)
+ {
+ /*
+ This function's sole purpose is to cause a link error in cases where
+ automatic tss cleanup is not implemented by Boost.Threads as a
+ reminder that user code is responsible for calling the necessary
+ functions at the appropriate times (and for implementing an a
+ tss_cleanup_implemented() function to eliminate the linker's
+ missing symbol error).
+
+ If Boost.Threads later implements automatic tss cleanup in cases
+ where it currently doesn't (which is the plan), the duplicate
+ symbol error will warn the user that their custom solution is no
+ longer needed and can be removed.
+ */
+ }
+
+}
+
+#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)
diff --git a/libs/thread/src/win32/thread.cpp b/libs/thread/src/win32/thread.cpp
new file mode 100644
index 0000000000..568eb217b9
--- /dev/null
+++ b/libs/thread/src/win32/thread.cpp
@@ -0,0 +1,633 @@
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+// (C) Copyright 2007 Anthony Williams
+// (C) Copyright 2007 David Deakins
+
+#define _WIN32_WINNT 0x400
+#define WINVER 0x400
+
+#include <boost/thread/thread.hpp>
+#include <algorithm>
+#ifndef UNDER_CE
+#include <process.h>
+#endif
+#include <stdio.h>
+#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
+{
+ namespace
+ {
+ boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
+ DWORD current_thread_tls_key=0;
+
+ 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;
+ }
+ }
+
+ detail::thread_data_base* get_current_thread_data()
+ {
+ if(!current_thread_tls_key)
+ {
+ return 0;
+ }
+ 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());
+ }
+
+#ifndef BOOST_HAS_THREADEX
+// Windows CE doesn't define _beginthreadex
+
+ struct ThreadProxyData
+ {
+ typedef unsigned (__stdcall* func)(void*);
+ func start_address_;
+ void* arglist_;
+ ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
+ };
+
+ DWORD WINAPI ThreadProxy(LPVOID args)
+ {
+ std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
+ DWORD ret=data->start_address_(data->arglist_);
+ 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;
+ return reinterpret_cast<uintptr_t const>(hthread);
+ }
+
+#endif
+
+ }
+
+ namespace detail
+ {
+ struct thread_exit_callback_node
+ {
+ boost::detail::thread_exit_function_base* func;
+ thread_exit_callback_node* next;
+
+ thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
+ thread_exit_callback_node* next_):
+ func(func_),next(next_)
+ {}
+ };
+
+ 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
+ {
+ void run_thread_exit_callbacks()
+ {
+ detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
+ if(current_thread_data)
+ {
+ while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
+ {
+ while(current_thread_data->thread_exit_callbacks)
+ {
+ detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
+ current_thread_data->thread_exit_callbacks=current_node->next;
+ if(current_node->func)
+ {
+ (*current_node->func)();
+ boost::detail::heap_delete(current_node->func);
+ }
+ boost::detail::heap_delete(current_node);
+ }
+ while(current_thread_data->tss_data)
+ {
+ detail::tss_data_node* const current_node=current_thread_data->tss_data;
+ current_thread_data->tss_data=current_node->next;
+ if(current_node->func)
+ {
+ (*current_node->func)(current_node->value);
+ }
+ boost::detail::heap_delete(current_node);
+ }
+ }
+
+ set_current_thread_data(0);
+ }
+ }
+
+ unsigned __stdcall thread_start_function(void* param)
+ {
+ detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
+ set_current_thread_data(thread_info);
+ try
+ {
+ thread_info->run();
+ }
+ catch(thread_interrupted const&)
+ {
+ }
+// Removed as it stops the debugger identifying the cause of the exception
+// Unhandled exceptions still cause the application to terminate
+// catch(...)
+// {
+// std::terminate();
+// }
+ run_thread_exit_callbacks();
+ return 0;
+ }
+ }
+
+ thread::thread()
+ {}
+
+ void thread::start_thread()
+ {
+ 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());
+ }
+ intrusive_ptr_add_ref(thread_info.get());
+ thread_info->thread_handle=(detail::win32::handle)(new_thread);
+ ResumeThread(thread_info->thread_handle);
+ }
+
+ thread::thread(detail::thread_data_ptr data):
+ thread_info(data)
+ {}
+
+ namespace
+ {
+ struct externally_launched_thread:
+ detail::thread_data_base
+ {
+ externally_launched_thread()
+ {
+ ++count;
+ interruption_enabled=false;
+ }
+
+ void run()
+ {}
+ private:
+ externally_launched_thread(externally_launched_thread&);
+ void operator=(externally_launched_thread&);
+ };
+
+ 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;
+ }
+ }
+
+ detail::thread_data_base* get_or_make_current_thread_data()
+ {
+ detail::thread_data_base* current_thread_data(get_current_thread_data());
+ if(!current_thread_data)
+ {
+ make_external_thread_data();
+ current_thread_data=get_current_thread_data();
+ }
+ return current_thread_data;
+ }
+
+ }
+
+ thread::~thread()
+ {
+ detach();
+ }
+
+ thread::id thread::get_id() const
+ {
+ return thread::id((get_thread_info)());
+ }
+
+ bool thread::joinable() const
+ {
+ return (get_thread_info)();
+ }
+
+ void thread::join()
+ {
+ 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());
+ release_handle();
+ }
+ }
+
+ bool thread::timed_join(boost::system_time const& wait_until)
+ {
+ 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)))
+ {
+ return false;
+ }
+ release_handle();
+ }
+ return true;
+ }
+
+ void thread::detach()
+ {
+ release_handle();
+ }
+
+ void thread::release_handle()
+ {
+ thread_info=0;
+ }
+
+ void thread::interrupt()
+ {
+ 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)();
+ return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
+ }
+
+ unsigned thread::hardware_concurrency()
+ {
+ 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)();
+ 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
+ {
+ return thread_info;
+ }
+
+ namespace this_thread
+ {
+ namespace
+ {
+ LARGE_INTEGER get_due_time(detail::timeout const& target_time)
+ {
+ LARGE_INTEGER due_time={{0}};
+ if(target_time.relative)
+ {
+ unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
+ LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
+ LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
+
+ if(remaining_milliseconds>0)
+ {
+ due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
+ }
+ }
+ else
+ {
+ SYSTEMTIME target_system_time={0};
+ target_system_time.wYear=target_time.abs_time.date().year();
+ target_system_time.wMonth=target_time.abs_time.date().month();
+ target_system_time.wDay=target_time.abs_time.date().day();
+ target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
+ target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
+ target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
+
+ if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
+ {
+ due_time.QuadPart=0;
+ }
+ 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);
+ }
+ }
+ }
+ return due_time;
+ }
+ }
+
+
+ bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
+ {
+ detail::win32::handle handles[3]={0};
+ unsigned handle_count=0;
+ unsigned wait_handle_index=~0U;
+ unsigned interruption_index=~0U;
+ unsigned timeout_index=~0U;
+ if(handle_to_wait_for!=detail::win32::invalid_handle_value)
+ {
+ wait_handle_index=handle_count;
+ handles[handle_count++]=handle_to_wait_for;
+ }
+ if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
+ {
+ interruption_index=handle_count;
+ handles[handle_count++]=get_current_thread_data()->interruption_handle;
+ }
+
+ 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();
+ if(time_left.milliseconds > min_timer_wait_period)
+ {
+ // for a long-enough timeout, use a waitable timer (which tracks clock changes)
+ timer_handle=CreateWaitableTimer(NULL,false,NULL);
+ 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)
+ {
+ timeout_index=handle_count;
+ handles[handle_count++]=timer_handle;
+ }
+ }
+ }
+ else if(!target_time.relative)
+ {
+ // convert short absolute-time timeouts into relative ones, so we don't race against clock changes
+ target_time=detail::timeout(time_left.milliseconds);
+ }
+ }
+#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);
+ if(notified_index<handle_count)
+ {
+ if(notified_index==wait_handle_index)
+ {
+ return true;
+ }
+ else if(notified_index==interruption_index)
+ {
+ detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
+ throw thread_interrupted();
+ }
+ else if(notified_index==timeout_index)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ detail::win32::Sleep(time_left.milliseconds);
+ }
+ if(target_time.relative)
+ {
+ target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
+ }
+ }
+ while(time_left.more);
+ return false;
+ }
+
+ thread::id get_id()
+ {
+ return thread::id(get_or_make_current_thread_data());
+ }
+
+ void interruption_point()
+ {
+ if(interruption_enabled() && interruption_requested())
+ {
+ detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
+ 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);
+ }
+
+ void yield()
+ {
+ detail::win32::Sleep(0);
+ }
+
+ disable_interruption::disable_interruption():
+ interruption_was_enabled(interruption_enabled())
+ {
+ if(interruption_was_enabled)
+ {
+ get_current_thread_data()->interruption_enabled=false;
+ }
+ }
+
+ disable_interruption::~disable_interruption()
+ {
+ if(get_current_thread_data())
+ {
+ get_current_thread_data()->interruption_enabled=interruption_was_enabled;
+ }
+ }
+
+ restore_interruption::restore_interruption(disable_interruption& d)
+ {
+ if(d.interruption_was_enabled)
+ {
+ get_current_thread_data()->interruption_enabled=true;
+ }
+ }
+
+ restore_interruption::~restore_interruption()
+ {
+ if(get_current_thread_data())
+ {
+ get_current_thread_data()->interruption_enabled=false;
+ }
+ }
+ }
+
+ namespace detail
+ {
+ void add_thread_exit_function(thread_exit_function_base* func)
+ {
+ 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);
+ current_thread_data->thread_exit_callbacks=new_node;
+ }
+
+ tss_data_node* find_tss_data(void const* key)
+ {
+ detail::thread_data_base* const current_thread_data(get_current_thread_data());
+ if(current_thread_data)
+ {
+ detail::tss_data_node* current_node=current_thread_data->tss_data;
+ while(current_node)
+ {
+ if(current_node->key==key)
+ {
+ return current_node;
+ }
+ current_node=current_node->next;
+ }
+ }
+ return NULL;
+ }
+
+ void* get_tss_data(void const* key)
+ {
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ return current_node->value;
+ }
+ return NULL;
+ }
+
+ void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
+ {
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ if(cleanup_existing && current_node->func.get() && current_node->value)
+ {
+ (*current_node->func)(current_node->value);
+ }
+ current_node->func=func;
+ current_node->value=tss_data;
+ }
+ else if(func && tss_data)
+ {
+ detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
+ tss_data_node* const new_node=
+ heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
+ 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();
+ }
+
+}
+
+
diff --git a/libs/thread/src/win32/timeconv.inl b/libs/thread/src/win32/timeconv.inl
new file mode 100644
index 0000000000..5ec3b1798a
--- /dev/null
+++ b/libs/thread/src/win32/timeconv.inl
@@ -0,0 +1,130 @@
+// 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)
+
+// boostinspect:nounnamed
+
+namespace {
+const int MILLISECONDS_PER_SECOND = 1000;
+const int NANOSECONDS_PER_SECOND = 1000000000;
+const int NANOSECONDS_PER_MILLISECOND = 1000000;
+
+const int MICROSECONDS_PER_SECOND = 1000000;
+const int NANOSECONDS_PER_MICROSECOND = 1000;
+
+inline void to_time(int milliseconds, boost::xtime& xt)
+{
+ int res = 0;
+ res = boost::xtime_get(&xt, boost::TIME_UTC);
+ assert(res == boost::TIME_UTC);
+
+ xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
+ xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
+ NANOSECONDS_PER_MILLISECOND);
+
+ if (xt.nsec >= NANOSECONDS_PER_SECOND)
+ {
+ ++xt.sec;
+ xt.nsec -= NANOSECONDS_PER_SECOND;
+ }
+}
+
+#if defined(BOOST_HAS_PTHREADS)
+inline void to_timespec(const boost::xtime& xt, timespec& ts)
+{
+ ts.tv_sec = static_cast<int>(xt.sec);
+ ts.tv_nsec = static_cast<int>(xt.nsec);
+ if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
+ {
+ ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
+ ts.tv_nsec %= NANOSECONDS_PER_SECOND;
+ }
+}
+
+inline void to_time(int milliseconds, timespec& ts)
+{
+ boost::xtime xt;
+ to_time(milliseconds, xt);
+ to_timespec(xt, ts);
+}
+
+inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
+{
+ boost::xtime cur;
+ int res = 0;
+ res = boost::xtime_get(&cur, boost::TIME_UTC);
+ assert(res == boost::TIME_UTC);
+
+ if (boost::xtime_cmp(xt, cur) <= 0)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ else
+ {
+ ts.tv_sec = xt.sec - cur.sec;
+ ts.tv_nsec = xt.nsec - cur.nsec;
+
+ if( ts.tv_nsec < 0 )
+ {
+ ts.tv_sec -= 1;
+ ts.tv_nsec += NANOSECONDS_PER_SECOND;
+ }
+ if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
+ {
+ ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
+ ts.tv_nsec %= NANOSECONDS_PER_SECOND;
+ }
+ }
+}
+#endif
+
+inline void to_duration(boost::xtime xt, int& milliseconds)
+{
+ boost::xtime cur;
+ int res = 0;
+ res = boost::xtime_get(&cur, boost::TIME_UTC);
+ assert(res == boost::TIME_UTC);
+
+ if (boost::xtime_cmp(xt, cur) <= 0)
+ milliseconds = 0;
+ else
+ {
+ if (cur.nsec > xt.nsec)
+ {
+ xt.nsec += NANOSECONDS_PER_SECOND;
+ --xt.sec;
+ }
+ milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
+ (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
+ NANOSECONDS_PER_MILLISECOND);
+ }
+}
+
+inline void to_microduration(boost::xtime xt, int& microseconds)
+{
+ boost::xtime cur;
+ int res = 0;
+ res = boost::xtime_get(&cur, boost::TIME_UTC);
+ assert(res == boost::TIME_UTC);
+
+ if (boost::xtime_cmp(xt, cur) <= 0)
+ microseconds = 0;
+ else
+ {
+ if (cur.nsec > xt.nsec)
+ {
+ xt.nsec += NANOSECONDS_PER_SECOND;
+ --xt.sec;
+ }
+ microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
+ (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
+ NANOSECONDS_PER_MICROSECOND);
+ }
+}
+}
+
+// Change Log:
+// 1 Jun 01 Initial creation.
diff --git a/libs/thread/src/win32/tss_dll.cpp b/libs/thread/src/win32/tss_dll.cpp
new file mode 100644
index 0000000000..9699a12b82
--- /dev/null
+++ b/libs/thread/src/win32/tss_dll.cpp
@@ -0,0 +1,76 @@
+// (C) Copyright Michael Glassford 2004.
+// Use, modification and distribution are subject to 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>
+
+#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
+
+ #include <boost/thread/detail/tss_hooks.hpp>
+
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+
+ #if defined(__BORLANDC__)
+ extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
+ #elif defined(_WIN32_WCE)
+ extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
+ #else
+ extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
+ #endif
+ {
+ switch(dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ boost::on_process_enter();
+ boost::on_thread_enter();
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ {
+ boost::on_thread_enter();
+ break;
+ }
+
+ case DLL_THREAD_DETACH:
+ {
+ boost::on_thread_exit();
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ boost::on_thread_exit();
+ boost::on_process_exit();
+ break;
+ }
+ }
+
+ return TRUE;
+ }
+
+namespace boost
+{
+ void tss_cleanup_implemented()
+ {
+ /*
+ This function's sole purpose is to cause a link error in cases where
+ automatic tss cleanup is not implemented by Boost.Threads as a
+ reminder that user code is responsible for calling the necessary
+ functions at the appropriate times (and for implementing an a
+ tss_cleanup_implemented() function to eliminate the linker's
+ missing symbol error).
+
+ If Boost.Threads later implements automatic tss cleanup in cases
+ where it currently doesn't (which is the plan), the duplicate
+ symbol error will warn the user that their custom solution is no
+ longer needed and can be removed.
+ */
+ }
+}
+
+
+#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
diff --git a/libs/thread/src/win32/tss_pe.cpp b/libs/thread/src/win32/tss_pe.cpp
new file mode 100644
index 0000000000..1d07d6b42b
--- /dev/null
+++ b/libs/thread/src/win32/tss_pe.cpp
@@ -0,0 +1,284 @@
+// $Id: tss_pe.cpp 72431 2011-06-06 08:28:31Z anthonyw $
+// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
+// (C) Copyright 2007 Roland Schwarz
+// (C) Copyright 2007 Anthony Williams
+// (C) Copyright 2007 David Deakins
+// Use, modification and distribution are subject to 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>
+
+#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
+
+#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__)
+
+#include <boost/thread/detail/tss_hooks.hpp>
+
+#include <windows.h>
+
+#include <cstdlib>
+
+namespace boost
+{
+ void tss_cleanup_implemented() {}
+}
+
+namespace {
+ void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
+ {
+ switch (dwReason)
+ {
+ case DLL_THREAD_DETACH:
+ {
+ boost::on_thread_exit();
+ break;
+ }
+ }
+ }
+}
+
+#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;
+
+ ULONG __tls_index__ = 0;
+ char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
+ char __tls_start__ __attribute__((section(".tls"))) = 0;
+
+
+ PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
+ 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__,
+ (DWORD) &__tls_end__,
+ (DWORD) &__tls_index__,
+ (DWORD) (&__crt_xl_start__+1),
+ (DWORD) 0,
+ (DWORD) 0
+};
+#endif
+
+
+#elif defined(_MSC_VER) && !defined(UNDER_CE)
+
+ #include <boost/thread/detail/tss_hooks.hpp>
+
+ #include <stdlib.h>
+
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+
+ //Definitions required by implementation
+
+ #if (_MSC_VER < 1300) // 1300 == VC++ 7.0
+ typedef void (__cdecl *_PVFV)();
+ #define INIRETSUCCESS
+ #define PVAPI void __cdecl
+ #else
+ typedef int (__cdecl *_PVFV)();
+ #define INIRETSUCCESS 0
+ #define PVAPI int __cdecl
+ #endif
+
+ typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
+
+ //Symbols for connection to the runtime environment
+
+ extern "C"
+ {
+ extern DWORD _tls_used; //the tls directory (located in .rdata segment)
+ extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */
+ }
+
+ namespace
+ {
+ //Forward declarations
+
+ static PVAPI on_tls_prepare();
+ static PVAPI on_process_init();
+ static PVAPI on_process_term();
+ static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
+
+ //The .CRT$Xxx information is taken from Codeguru:
+ //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
+
+#if (_MSC_VER >= 1400)
+#pragma section(".CRT$XIU",long,read)
+#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;
+#else
+ #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+ # pragma data_seg(push, old_seg)
+ #endif
+ //Callback to run tls glue code first.
+ //I don't think it is necessary to run it
+ //at .CRT$XIB level, since we are only
+ //interested in thread detachement. But
+ //this could be changed easily if required.
+
+ #pragma data_seg(".CRT$XIU")
+ static _PVFV p_tls_prepare = on_tls_prepare;
+ #pragma data_seg()
+
+ //Callback after all global ctors.
+
+ #pragma data_seg(".CRT$XCU")
+ static _PVFV p_process_init = on_process_init;
+ #pragma data_seg()
+
+ //Callback for tls notifications.
+
+ #pragma data_seg(".CRT$XLB")
+ _TLSCB p_thread_callback = on_tls_callback;
+ #pragma data_seg()
+ //Callback for termination.
+
+ #pragma data_seg(".CRT$XTU")
+ static _PVFV p_process_term = on_process_term;
+ #pragma data_seg()
+ #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+ # pragma data_seg(pop, old_seg)
+ #endif
+#endif
+
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable:4189)
+#endif
+
+ PVAPI on_tls_prepare()
+ {
+ //The following line has an important side effect:
+ //if the TLS directory is not already there, it will
+ //be created by the linker. In other words, it forces a tls
+ //directory to be generated by the linker even when static tls
+ //(i.e. __declspec(thread)) is not used.
+ //The volatile should prevent the optimizer
+ //from removing the reference.
+
+ DWORD volatile dw = _tls_used;
+
+ #if (_MSC_VER < 1300) // 1300 == VC++ 7.0
+ _TLSCB* pfbegin = __xl_a;
+ _TLSCB* pfend = __xl_z;
+ _TLSCB* pfdst = pfbegin;
+ //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
+
+ //The following loop will merge the address pointers
+ //into a contiguous area, since the tlssup code seems
+ //to require this (at least on MSVC 6)
+
+ while (pfbegin < pfend)
+ {
+ if (*pfbegin != 0)
+ {
+ *pfdst = *pfbegin;
+ ++pfdst;
+ }
+ ++pfbegin;
+ }
+
+ *pfdst = 0;
+ #endif
+
+ return INIRETSUCCESS;
+ }
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+ PVAPI on_process_init()
+ {
+ //Schedule on_thread_exit() to be called for the main
+ //thread before destructors of global objects have been
+ //called.
+
+ //It will not be run when 'quick' exiting the
+ //library; however, this is the standard behaviour
+ //for destructors of global objects, so that
+ //shouldn't be a problem.
+
+ atexit(boost::on_thread_exit);
+
+ //Call Boost process entry callback here
+
+ boost::on_process_enter();
+
+ return INIRETSUCCESS;
+ }
+
+ PVAPI on_process_term()
+ {
+ boost::on_process_exit();
+ return INIRETSUCCESS;
+ }
+
+ void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
+ {
+ switch (dwReason)
+ {
+ case DLL_THREAD_DETACH:
+ boost::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()
+ {
+ /*
+ This function's sole purpose is to cause a link error in cases where
+ automatic tss cleanup is not implemented by Boost.Threads as a
+ reminder that user code is responsible for calling the necessary
+ functions at the appropriate times (and for implementing an a
+ tss_cleanup_implemented() function to eliminate the linker's
+ missing symbol error).
+
+ If Boost.Threads later implements automatic tss cleanup in cases
+ where it currently doesn't (which is the plan), the duplicate
+ symbol error will warn the user that their custom solution is no
+ longer needed and can be removed.
+ */
+ }
+}
+
+#endif //defined(_MSC_VER) && !defined(UNDER_CE)
+
+#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
diff --git a/libs/thread/test/Carbon.r b/libs/thread/test/Carbon.r
new file mode 100644
index 0000000000..e0ac5b449e
--- /dev/null
+++ b/libs/thread/test/Carbon.r
@@ -0,0 +1,18 @@
+/*
+ * Permit this Carbon application to launch on OS X
+ *
+ * © 1997-2000 Metrowerks Corp.
+ *
+ * Questions and comments to:
+ * <mailto:support@metrowerks.com>
+ * <http://www.metrowerks.com/>
+ */
+
+
+/*----------------------------carb ¥ Carbon on OS X launch information --------------------------*/
+type 'carb' {
+};
+
+
+resource 'carb'(0) {
+};
diff --git a/libs/thread/test/Jamfile.v2 b/libs/thread/test/Jamfile.v2
new file mode 100644
index 0000000000..d1d61179cb
--- /dev/null
+++ b/libs/thread/test/Jamfile.v2
@@ -0,0 +1,90 @@
+# (C) Copyright William E. Kempf 2001.
+# (C) Copyright 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)
+#
+# Boost.Threads test Jamfile
+#
+# Additional configuration variables used:
+# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
+# library should be used instead of "native" threads. This feature is
+# mostly used for testing and it's generally recommended you use the
+# native threading libraries instead. PTW32 should be set to be a list
+# of two strings, the first specifying the installation path of the
+# pthreads-win32 library and the second specifying which library
+# variant to link against (see the pthreads-win32 documentation).
+# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
+
+# bring in rules for testing
+import testing ;
+
+project
+ : requirements <library>/boost/test//boost_unit_test_framework/<link>static
+ <threading>multi
+ ;
+
+rule thread-run ( sources )
+{
+ return
+ [ run $(sources) ../build//boost_thread ]
+ [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
+ : : : : $(sources[1]:B)_lib ]
+ ;
+}
+
+{
+ test-suite "threads"
+ : [ thread-run test_thread.cpp ]
+ [ thread-run test_thread_id.cpp ]
+ [ thread-run test_hardware_concurrency.cpp ]
+ [ thread-run test_thread_move.cpp ]
+ [ thread-run test_thread_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 ]
+ [ thread-run test_condition_timed_wait_times_out.cpp ]
+ [ thread-run test_condition_notify_all.cpp ]
+ [ thread-run test_condition.cpp ]
+ [ thread-run test_tss.cpp ]
+ [ thread-run test_once.cpp ]
+ [ thread-run test_xtime.cpp ]
+ [ thread-run test_barrier.cpp ]
+ [ thread-run test_shared_mutex.cpp ]
+ [ thread-run test_shared_mutex_part_2.cpp ]
+ [ thread-run test_shared_mutex_timed_locks.cpp ]
+ [ thread-run test_lock_concept.cpp ]
+ [ thread-run test_generic_locks.cpp ]
+ [ 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 ]
+ ;
+
+}
diff --git a/libs/thread/test/condition_test_common.hpp b/libs/thread/test/condition_test_common.hpp
new file mode 100644
index 0000000000..38f7790989
--- /dev/null
+++ b/libs/thread/test/condition_test_common.hpp
@@ -0,0 +1,97 @@
+#ifndef CONDITION_TEST_COMMON_HPP
+#define CONDITION_TEST_COMMON_HPP
+// 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/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+
+unsigned const timeout_seconds=5;
+
+struct wait_for_flag
+{
+ boost::mutex mutex;
+ boost::condition_variable cond_var;
+ bool flag;
+ unsigned woken;
+
+ wait_for_flag():
+ flag(false),woken(0)
+ {}
+
+ struct check_flag
+ {
+ bool const& flag;
+
+ check_flag(bool const& flag_):
+ flag(flag_)
+ {}
+
+ bool operator()() const
+ {
+ return flag;
+ }
+ private:
+ void operator=(check_flag&);
+ };
+
+
+ void wait_without_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ while(!flag)
+ {
+ cond_var.wait(lock);
+ }
+ ++woken;
+ }
+
+ void wait_with_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ cond_var.wait(lock,check_flag(flag));
+ if(flag)
+ {
+ ++woken;
+ }
+ }
+
+ void timed_wait_without_predicate()
+ {
+ boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
+
+ boost::mutex::scoped_lock lock(mutex);
+ while(!flag)
+ {
+ if(!cond_var.timed_wait(lock,timeout))
+ {
+ return;
+ }
+ }
+ ++woken;
+ }
+
+ void timed_wait_with_predicate()
+ {
+ boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
+ boost::mutex::scoped_lock lock(mutex);
+ if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
+ {
+ ++woken;
+ }
+ }
+ void relative_timed_wait_with_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
+ {
+ ++woken;
+ }
+ }
+};
+
+
+#endif
diff --git a/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp b/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp
new file mode 100644
index 0000000000..02b6893edd
--- /dev/null
+++ b/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <boost/thread/thread.hpp>
+
+void do_nothing()
+{}
+
+void test()
+{
+ boost::thread t1(do_nothing);
+ boost::thread t2;
+ t2=t1;
+}
diff --git a/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp b/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp
new file mode 100644
index 0000000000..5c4600ec26
--- /dev/null
+++ b/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <boost/thread/thread.hpp>
+
+void do_nothing()
+{}
+
+void test()
+{
+ boost::thread t1(do_nothing);
+ boost::thread t2(t1);
+}
diff --git a/libs/thread/test/shared_mutex_locking_thread.hpp b/libs/thread/test/shared_mutex_locking_thread.hpp
new file mode 100644
index 0000000000..98a415b121
--- /dev/null
+++ b/libs/thread/test/shared_mutex_locking_thread.hpp
@@ -0,0 +1,132 @@
+#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
+#define SHARED_MUTEX_LOCKING_THREAD_HPP
+
+// (C) Copyright 2008 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
+template<typename lock_type>
+class locking_thread
+{
+ boost::shared_mutex& rw_mutex;
+ unsigned& unblocked_count;
+ boost::condition_variable& unblocked_condition;
+ unsigned& simultaneous_running_count;
+ unsigned& max_simultaneous_running;
+ boost::mutex& unblocked_count_mutex;
+ boost::mutex& finish_mutex;
+public:
+ locking_thread(boost::shared_mutex& rw_mutex_,
+ unsigned& unblocked_count_,
+ boost::mutex& unblocked_count_mutex_,
+ boost::condition_variable& unblocked_condition_,
+ boost::mutex& finish_mutex_,
+ unsigned& simultaneous_running_count_,
+ unsigned& max_simultaneous_running_):
+ rw_mutex(rw_mutex_),
+ unblocked_count(unblocked_count_),
+ unblocked_condition(unblocked_condition_),
+ simultaneous_running_count(simultaneous_running_count_),
+ max_simultaneous_running(max_simultaneous_running_),
+ unblocked_count_mutex(unblocked_count_mutex_),
+ finish_mutex(finish_mutex_)
+ {}
+
+ void operator()()
+ {
+ // acquire lock
+ lock_type lock(rw_mutex);
+
+ // increment count to show we're unblocked
+ {
+ boost::mutex::scoped_lock ublock(unblocked_count_mutex);
+ ++unblocked_count;
+ unblocked_condition.notify_one();
+ ++simultaneous_running_count;
+ if(simultaneous_running_count>max_simultaneous_running)
+ {
+ max_simultaneous_running=simultaneous_running_count;
+ }
+ }
+
+ // wait to finish
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ {
+ boost::mutex::scoped_lock ublock(unblocked_count_mutex);
+ --simultaneous_running_count;
+ }
+ }
+private:
+ void operator=(locking_thread&);
+};
+
+class simple_writing_thread
+{
+ boost::shared_mutex& rwm;
+ boost::mutex& finish_mutex;
+ boost::mutex& unblocked_mutex;
+ unsigned& unblocked_count;
+
+ void operator=(simple_writing_thread&);
+
+public:
+ simple_writing_thread(boost::shared_mutex& rwm_,
+ boost::mutex& finish_mutex_,
+ boost::mutex& unblocked_mutex_,
+ unsigned& unblocked_count_):
+ rwm(rwm_),finish_mutex(finish_mutex_),
+ unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
+ {}
+
+ void operator()()
+ {
+ boost::unique_lock<boost::shared_mutex> lk(rwm);
+
+ {
+ boost::mutex::scoped_lock ulk(unblocked_mutex);
+ ++unblocked_count;
+ }
+
+ boost::mutex::scoped_lock flk(finish_mutex);
+ }
+};
+
+class simple_reading_thread
+{
+ boost::shared_mutex& rwm;
+ boost::mutex& finish_mutex;
+ boost::mutex& unblocked_mutex;
+ unsigned& unblocked_count;
+
+ void operator=(simple_reading_thread&);
+
+public:
+ simple_reading_thread(boost::shared_mutex& rwm_,
+ boost::mutex& finish_mutex_,
+ boost::mutex& unblocked_mutex_,
+ unsigned& unblocked_count_):
+ rwm(rwm_),finish_mutex(finish_mutex_),
+ unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
+ {}
+
+ void operator()()
+ {
+ boost::shared_lock<boost::shared_mutex> lk(rwm);
+
+ {
+ boost::mutex::scoped_lock ulk(unblocked_mutex);
+ ++unblocked_count;
+ }
+
+ boost::mutex::scoped_lock flk(finish_mutex);
+ }
+};
+
+
+#endif
diff --git a/libs/thread/test/test.mcp b/libs/thread/test/test.mcp
new file mode 100644
index 0000000000..f27f0b97b8
--- /dev/null
+++ b/libs/thread/test/test.mcp
Binary files differ
diff --git a/libs/thread/test/test_2501.cpp b/libs/thread/test/test_2501.cpp
new file mode 100644
index 0000000000..5091338670
--- /dev/null
+++ b/libs/thread/test/test_2501.cpp
@@ -0,0 +1,10 @@
+#include <boost/thread/shared_mutex.hpp>
+
+int main() {
+
+ boost::shared_mutex mtx; boost::upgrade_lock<boost::shared_mutex> lk(mtx);
+
+ boost::upgrade_to_unique_lock<boost::shared_mutex> lk2(lk);
+
+ return 0;
+}
diff --git a/libs/thread/test/test_4521.cpp b/libs/thread/test/test_4521.cpp
new file mode 100644
index 0000000000..24e1b165ef
--- /dev/null
+++ b/libs/thread/test/test_4521.cpp
@@ -0,0 +1,21 @@
+#include <boost/thread.hpp>
+
+int calculate_the_answer_to_life_the_universe_and_everything()
+{
+ return 42;
+}
+
+int main() {
+boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
+boost::unique_future<int> fi=pt.get_future();
+
+boost::thread task(boost::move(pt)); // launch task on a thread
+
+fi.wait(); // wait for it to finish
+
+//assert(fi.is_ready());
+//assert(fi.has_value());
+//assert(!fi.has_exception());
+//assert(fi.get_state()==boost::future_state::ready);
+//assert(fi.get()==42);
+}
diff --git a/libs/thread/test/test_4648.cpp b/libs/thread/test/test_4648.cpp
new file mode 100644
index 0000000000..b0f95f8d14
--- /dev/null
+++ b/libs/thread/test/test_4648.cpp
@@ -0,0 +1,42 @@
+#include <iostream>
+#include <boost/thread.hpp>
+#include <boost/current_function.hpp>
+
+class boostThreadLocksTest
+{
+public:
+ boost::shared_mutex myMutex;
+ //boost::upgrade_lock<boost::shared_mutex> myLock;
+ static int firstFunction(boostThreadLocksTest *pBoostThreadLocksTest);
+ static int secondFunction(boostThreadLocksTest *pBoostThreadLocksTest,
+ boost::upgrade_lock<boost::shared_mutex>& upgr);
+ boostThreadLocksTest()
+ :myMutex()
+ //, myLock(myMutex,boost::defer_lock_t())
+ {};
+};
+
+int boostThreadLocksTest::firstFunction(boostThreadLocksTest *pBoostThreadLocksTest)
+{
+ std::cout<<"Entering "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
+ boost::upgrade_lock<boost::shared_mutex> myLock(pBoostThreadLocksTest->myMutex);
+ pBoostThreadLocksTest->secondFunction(pBoostThreadLocksTest, myLock);
+ std::cout<<"Returned From Call "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
+ std::cout<<"Returning from "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
+ return(0);
+}
+int boostThreadLocksTest::secondFunction(boostThreadLocksTest *pBoostThreadLocksTest, boost::upgrade_lock<boost::shared_mutex>& upgr) {
+ std::cout<<"Before Exclusive Locking "<<boost::this_thread::get_id()<<" "<<"secondFunction"<<std::endl;
+ boost::upgrade_to_unique_lock<boost::shared_mutex> localUniqueLock(upgr);
+ std::cout<<"After Exclusive Locking "<<boost::this_thread::get_id()<<" "<<"secondFunction"<<std::endl;
+ return(0);
+}
+int main() {
+ boostThreadLocksTest myObject;
+ boost::thread_group myThreadGroup;
+ myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
+ myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
+ myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
+ myThreadGroup.join_all();
+ return 0;
+}
diff --git a/libs/thread/test/test_4882.cpp b/libs/thread/test/test_4882.cpp
new file mode 100644
index 0000000000..88dab8d9b6
--- /dev/null
+++ b/libs/thread/test/test_4882.cpp
@@ -0,0 +1,50 @@
+#include <boost/thread/thread.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
+#include <iostream>
+
+boost::shared_mutex mutex;
+
+void thread()
+{
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ try
+ {
+ for (int i =0; i<10; ++i)
+ {
+ boost::system_time timeout = boost::get_system_time() + boost::posix_time::milliseconds(50);
+
+ if (mutex.timed_lock(timeout))
+ {
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+ mutex.unlock();
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ }
+ }
+ }
+ catch (boost::lock_error& le)
+ {
+ std::cerr << "lock_error exception\n";
+ }
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+}
+
+int main()
+{
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ const int nrThreads = 20;
+ boost::thread* threads[nrThreads];
+
+ for (int i = 0; i < nrThreads; ++i)
+ threads[i] = new boost::thread(&thread);
+
+ for (int i = 0; i < nrThreads; ++i)
+ {
+ threads[i]->join();
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ delete threads[i];
+ }
+ std::cout << __FILE__ << ":" << __LINE__ << std::endl;
+ return 0;
+}
diff --git a/libs/thread/test/test_5351.cpp b/libs/thread/test/test_5351.cpp
new file mode 100644
index 0000000000..543bb34c4c
--- /dev/null
+++ b/libs/thread/test/test_5351.cpp
@@ -0,0 +1,45 @@
+#include <iostream>
+#include <boost/thread.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/thread/future.hpp>
+
+using namespace boost::posix_time;
+using namespace boost;
+
+int foo()
+{
+ this_thread::sleep(seconds(10));
+ return 0;
+}
+
+
+int main(int argc, char** argv)
+{
+ boost::packaged_task<int> pt(&foo);
+ boost::unique_future<int> fi = pt.get_future();
+ boost::thread task(boost::move(pt)); // launch task on a thread
+
+ task.interrupt();
+
+ try
+ {
+ int v = fi.get();
+ }
+ catch (boost::thread_interrupted& exc)
+ {
+ std::cout << "OK: " << std::endl;
+ return 0;
+ }
+ catch (boost::exception& exc)
+ {
+ std::cout << __LINE__ << " ERROR: " << boost::diagnostic_information(exc) << std::endl;
+ return 1;
+ }
+ catch (...)
+ {
+ std::cout << __LINE__ << " ERROR: " << std::endl;
+ return 2;
+ }
+ std::cout << __LINE__ << " ERROR: " << std::endl;
+ return 3;
+}
diff --git a/libs/thread/test/test_5502.cpp b/libs/thread/test/test_5502.cpp
new file mode 100644
index 0000000000..3baf9bb4a5
--- /dev/null
+++ b/libs/thread/test/test_5502.cpp
@@ -0,0 +1,86 @@
+// bm.cpp
+
+// g++ test.cpp -lboost_thread-mt && ./a.out
+
+// the ration of XXX and YYY determines
+// if this works or deadlocks
+int XXX = 20;
+int YYY = 10;
+
+#include <boost/thread.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
+#include <unistd.h>
+#include <iostream>
+#include <boost/detail/lightweight_test.hpp>
+
+using namespace std;
+
+void sleepmillis(useconds_t miliis)
+{
+ usleep(miliis * 1000);
+}
+
+void worker1(boost::shared_mutex * lk, int * x)
+{
+ (*x)++; // 1
+ cout << "lock b try " << *x << endl;
+ while (1)
+ {
+ if (lk->timed_lock(boost::posix_time::milliseconds(XXX))) break;
+ sleepmillis(YYY);
+ }
+ cout << "lock b got " << *x << endl;
+ (*x)++; // 2
+ lk->unlock();
+}
+
+void worker2(boost::shared_mutex * lk, int * x)
+{
+ cout << "lock c try" << endl;
+ lk->lock_shared();
+ (*x)++;
+ cout << "lock c got" << endl;
+ lk->unlock_shared();
+ cout << "lock c unlocked" << endl;
+ (*x)++;
+}
+
+int main()
+{
+
+ // create
+ boost::shared_mutex* lk = new boost::shared_mutex();
+
+ // read lock
+ cout << "lock a" << endl;
+ lk->lock_shared();
+
+ int x1 = 0;
+ boost::thread t1(boost::bind(worker1, lk, &x1));
+ while (!x1)
+ ;
+ BOOST_TEST(x1 == 1);
+ sleepmillis(500);
+ BOOST_TEST(x1 == 1);
+
+ int x2 = 0;
+ boost::thread t2(boost::bind(worker2, lk, &x2));
+ t2.join();
+ BOOST_TEST(x2 == 2);
+
+ lk->unlock_shared();
+ cout << "unlock a" << endl;
+
+ for (int i = 0; i < 2000; i++)
+ {
+ if (x1 == 2) break;
+ sleepmillis(10);
+ }
+
+ BOOST_TEST(x1 == 2);
+ t1.join();
+ delete lk;
+
+ return 0;
+}
diff --git a/libs/thread/test/test_5542_1.cpp b/libs/thread/test/test_5542_1.cpp
new file mode 100644
index 0000000000..79dfd60db6
--- /dev/null
+++ b/libs/thread/test/test_5542_1.cpp
@@ -0,0 +1,62 @@
+#include <iostream>
+#include <boost/thread.hpp>
+
+class Worker
+{
+public:
+
+ Worker()
+ {
+ // the thread is not-a-thread until we call start()
+ }
+
+ void start(int N)
+ {
+ std::cout << "start\n";
+ m_Thread = boost::thread(&Worker::processQueue, this, N);
+ std::cout << "started\n";
+ }
+
+ void join()
+ {
+ m_Thread.join();
+ }
+
+ void processQueue(unsigned N)
+ {
+ float ms = N * 1e3;
+ boost::posix_time::milliseconds workTime(ms);
+
+ std::cout << "Worker: started, will work for "
+ << ms << "ms"
+ << std::endl;
+
+ // We're busy, honest!
+ boost::this_thread::sleep(workTime);
+
+ std::cout << "Worker: completed" << std::endl;
+ }
+
+private:
+
+ boost::thread m_Thread;
+};
+
+int main(int argc, char* argv[])
+{
+ std::cout << "main: startup" << std::endl;
+
+ Worker worker;
+
+ std::cout << "main: create worker" << std::endl;
+
+ worker.start(3);
+
+ std::cout << "main: waiting for thread" << std::endl;
+
+ worker.join();
+
+ std::cout << "main: done" << std::endl;
+
+ return 0;
+}
diff --git a/libs/thread/test/test_5542_2.cpp b/libs/thread/test/test_5542_2.cpp
new file mode 100644
index 0000000000..c48ef4eaba
--- /dev/null
+++ b/libs/thread/test/test_5542_2.cpp
@@ -0,0 +1,11 @@
+#include <boost/thread.hpp>
+
+void run_thread() {
+ return;
+}
+
+int main() {
+ boost::thread t(run_thread);
+ return 0;
+}
+
diff --git a/libs/thread/test/test_5542_3.cpp b/libs/thread/test/test_5542_3.cpp
new file mode 100644
index 0000000000..0c1ac40bb2
--- /dev/null
+++ b/libs/thread/test/test_5542_3.cpp
@@ -0,0 +1,30 @@
+#include <iostream>
+#include <boost/thread.hpp>
+#include <boost/date_time.hpp>
+
+void workerFunc()
+{
+ boost::posix_time::seconds workTime(3);
+
+ std::cout << "Worker: running" << std::endl;
+
+ // Pretend to do something useful...
+ boost::this_thread::sleep(workTime);
+
+ std::cout << "Worker: finished" << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ std::cout << "main: startup" << std::endl;
+
+ boost::thread workerThread(workerFunc);
+
+ std::cout << "main: waiting for thread" << std::endl;
+
+ workerThread.join();
+
+ std::cout << "main: done" << std::endl;
+
+ return 0;
+}
diff --git a/libs/thread/test/test_6130.cpp b/libs/thread/test/test_6130.cpp
new file mode 100644
index 0000000000..3ef1f18373
--- /dev/null
+++ b/libs/thread/test/test_6130.cpp
@@ -0,0 +1,22 @@
+#include <boost/thread.hpp>
+#include <assert.h>
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+boost::mutex mtx;
+boost::condition_variable cv;
+
+int main()
+{
+ for (int i=0; i<3; ++i) {
+ const time_t wait_time = ::time(0)+1;
+
+ boost::mutex::scoped_lock lk(mtx);
+ const bool res = cv.timed_wait(lk, boost::posix_time::from_time_t(wait_time));
+ const time_t end_time = ::time(0);
+ assert(end_time >= wait_time);
+ std::cerr << end_time - wait_time << " OK\n";
+ }
+ return 0;
+}
diff --git a/libs/thread/test/test_6170.cpp b/libs/thread/test/test_6170.cpp
new file mode 100644
index 0000000000..6f2f28fd65
--- /dev/null
+++ b/libs/thread/test/test_6170.cpp
@@ -0,0 +1,26 @@
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
+
+// Including this will cause ambiguous errors in boost::move
+#include <boost/unordered_map.hpp>
+
+using namespace boost;
+
+typedef upgrade_lock<shared_mutex> auto_upgrade_lock;
+typedef upgrade_to_unique_lock<shared_mutex> auto_upgrade_unique_lock;
+
+void testUpgrade(void)
+{
+ shared_mutex mtx;
+ auto_upgrade_lock lock(mtx);
+ // Do some read-only stuff
+
+ auto_upgrade_unique_lock writeLock(lock);
+ // Do some write-only stuff with the upgraded lock
+}
+
+int main()
+{
+ testUpgrade();
+ return 0;
+} \ No newline at end of file
diff --git a/libs/thread/test/test_6174.cpp b/libs/thread/test/test_6174.cpp
new file mode 100644
index 0000000000..b3c14ecacf
--- /dev/null
+++ b/libs/thread/test/test_6174.cpp
@@ -0,0 +1,35 @@
+
+
+#include <boost/thread.hpp>
+#include <boost/config.hpp>
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+struct MovableButNonCopyable {
+#ifndef BOOST_NO_DEFAULTED_FUNCTIONS
+ MovableButNonCopyable() = default;
+ MovableButNonCopyable(MovableButNonCopyable const&) = delete;
+ MovableButNonCopyable& operator=(MovableButNonCopyable const&) = delete;
+ MovableButNonCopyable(MovableButNonCopyable&&) = default;
+ MovableButNonCopyable& operator=(MovableButNonCopyable&&) = default;
+#else
+ MovableButNonCopyable() {};
+ MovableButNonCopyable(MovableButNonCopyable&&) {};
+ MovableButNonCopyable& operator=(MovableButNonCopyable&&) {
+ return *this;
+ };
+private:
+ MovableButNonCopyable(MovableButNonCopyable const&);
+ MovableButNonCopyable& operator=(MovableButNonCopyable const&);
+#endif
+};
+int main()
+{
+ boost::packaged_task<MovableButNonCopyable>(MovableButNonCopyable());
+ return 0;
+}
+#else
+int main()
+{
+ return 0;
+}
+#endif
diff --git a/libs/thread/test/test_barrier.cpp b/libs/thread/test/test_barrier.cpp
new file mode 100644
index 0000000000..cd350ba2f7
--- /dev/null
+++ b/libs/thread/test/test_barrier.cpp
@@ -0,0 +1,66 @@
+// 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/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+namespace {
+
+// Shared variables for generation barrier test
+const int N_THREADS=10;
+boost::barrier gen_barrier(N_THREADS);
+boost::mutex mutex;
+long global_parameter;
+
+void barrier_thread()
+{
+ for (int i = 0; i < 5; ++i)
+ {
+ if (gen_barrier.wait())
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ global_parameter++;
+ }
+ }
+}
+
+} // namespace
+
+void test_barrier()
+{
+ boost::thread_group g;
+ global_parameter = 0;
+
+ try
+ {
+ for (int i = 0; i < N_THREADS; ++i)
+ g.create_thread(&barrier_thread);
+ g.join_all();
+ }
+ catch(...)
+ {
+ g.interrupt_all();
+ g.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(global_parameter,5);
+}
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: barrier test suite");
+
+ test->add(BOOST_TEST_CASE(&test_barrier));
+
+ return test;
+}
diff --git a/libs/thread/test/test_condition.cpp b/libs/thread/test/test_condition.cpp
new file mode 100644
index 0000000000..f33b7a2bd7
--- /dev/null
+++ b/libs/thread/test/test_condition.cpp
@@ -0,0 +1,190 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+
+struct condition_test_data
+{
+ condition_test_data() : notified(0), awoken(0) { }
+
+ boost::mutex mutex;
+ boost::condition_variable condition;
+ int notified;
+ int awoken;
+};
+
+void condition_test_thread(condition_test_data* data)
+{
+ boost::mutex::scoped_lock lock(data->mutex);
+ BOOST_CHECK(lock ? true : false);
+ while (!(data->notified > 0))
+ data->condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ data->awoken++;
+}
+
+struct cond_predicate
+{
+ cond_predicate(int& var, int val) : _var(var), _val(val) { }
+
+ bool operator()() { return _var == _val; }
+
+ int& _var;
+ int _val;
+private:
+ void operator=(cond_predicate&);
+
+};
+
+void condition_test_waits(condition_test_data* data)
+{
+ boost::mutex::scoped_lock lock(data->mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Test wait.
+ while (data->notified != 1)
+ data->condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data->notified, 1);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate wait.
+ data->condition.wait(lock, cond_predicate(data->notified, 2));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data->notified, 2);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test timed_wait.
+ boost::xtime xt = delay(10);
+ while (data->notified != 3)
+ data->condition.timed_wait(lock, xt);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data->notified, 3);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate timed_wait.
+ xt = delay(10);
+ cond_predicate pred(data->notified, 4);
+ BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK(pred());
+ BOOST_CHECK_EQUAL(data->notified, 4);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate timed_wait with relative timeout
+ cond_predicate pred_rel(data->notified, 5);
+ BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK(pred_rel());
+ BOOST_CHECK_EQUAL(data->notified, 5);
+ data->awoken++;
+ data->condition.notify_one();
+}
+
+void do_test_condition_waits()
+{
+ condition_test_data data;
+
+ boost::thread thread(bind(&condition_test_waits, &data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 1)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 1);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 2)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 2);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 3)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 3);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 4)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 4);
+
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 5)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 5);
+ }
+
+ thread.join();
+ BOOST_CHECK_EQUAL(data.awoken, 5);
+}
+
+void test_condition_waits()
+{
+ // We should have already tested notify_one here, so
+ // a timed test with the default execution_monitor::use_condition
+ // should be OK, and gives the fastest performance
+ timed_test(&do_test_condition_waits, 12);
+}
+
+void do_test_condition_wait_is_a_interruption_point()
+{
+ condition_test_data data;
+
+ boost::thread thread(bind(&condition_test_thread, &data));
+
+ thread.interrupt();
+ thread.join();
+ BOOST_CHECK_EQUAL(data.awoken,0);
+}
+
+
+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::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_waits));
+ test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));
+
+ return test;
+}
diff --git a/libs/thread/test/test_condition_notify_all.cpp b/libs/thread/test/test_condition_notify_all.cpp
new file mode 100644
index 0000000000..83165c999b
--- /dev/null
+++ b/libs/thread/test/test_condition_notify_all.cpp
@@ -0,0 +1,222 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+#include "condition_test_common.hpp"
+
+unsigned const number_of_test_threads=5;
+
+void do_test_condition_notify_all_wakes_from_wait()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_timed_wait()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+namespace
+{
+ boost::mutex multiple_wake_mutex;
+ boost::condition_variable multiple_wake_cond;
+ unsigned multiple_wake_count=0;
+
+ void wait_for_condvar_and_increase_count()
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ multiple_wake_cond.wait(lk);
+ ++multiple_wake_count;
+ }
+
+}
+
+
+void do_test_notify_all_following_notify_one_wakes_all_threads()
+{
+ boost::thread thread1(wait_for_condvar_and_increase_count);
+ boost::thread thread2(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+
+ boost::thread thread3(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+ multiple_wake_cond.notify_all();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ BOOST_CHECK(multiple_wake_count==3);
+ }
+
+ thread1.join();
+ thread2.join();
+ thread3.join();
+}
+
+void test_condition_notify_all()
+{
+ timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_notify_all));
+
+ return test;
+}
diff --git a/libs/thread/test/test_condition_notify_one.cpp b/libs/thread/test/test_condition_notify_one.cpp
new file mode 100644
index 0000000000..1e489da60c
--- /dev/null
+++ b/libs/thread/test/test_condition_notify_one.cpp
@@ -0,0 +1,155 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+#include "condition_test_common.hpp"
+
+void do_test_condition_notify_one_wakes_from_wait()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_timed_wait()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+namespace
+{
+ boost::mutex multiple_wake_mutex;
+ boost::condition_variable multiple_wake_cond;
+ unsigned multiple_wake_count=0;
+
+ void wait_for_condvar_and_increase_count()
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ multiple_wake_cond.wait(lk);
+ ++multiple_wake_count;
+ }
+
+}
+
+
+void do_test_multiple_notify_one_calls_wakes_multiple_threads()
+{
+ boost::thread thread1(wait_for_condvar_and_increase_count);
+ boost::thread thread2(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+
+ boost::thread thread3(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+ multiple_wake_cond.notify_one();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ BOOST_CHECK(multiple_wake_count==3);
+ }
+
+ thread1.join();
+ thread2.join();
+ thread3.join();
+}
+
+void test_condition_notify_one()
+{
+ timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex);
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_notify_one));
+
+ return test;
+}
diff --git a/libs/thread/test/test_condition_timed_wait_times_out.cpp b/libs/thread/test/test_condition_timed_wait_times_out.cpp
new file mode 100644
index 0000000000..c731b5b68d
--- /dev/null
+++ b/libs/thread/test/test_condition_timed_wait_times_out.cpp
@@ -0,0 +1,173 @@
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include "util.inl"
+
+bool fake_predicate()
+{
+ return false;
+}
+
+unsigned const timeout_seconds=2;
+unsigned const timeout_grace=1;
+boost::posix_time::milliseconds const timeout_resolution(100);
+
+
+void do_test_timed_wait_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();
+ 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_timed_wait_with_predicate_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();
+ 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_relative_timed_wait_with_predicate_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();
+
+ 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_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::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
+
+ return test;
+}
diff --git a/libs/thread/test/test_futures.cpp b/libs/thread/test/test_futures.cpp
new file mode 100644
index 0000000000..4d89e5a9fa
--- /dev/null
+++ b/libs/thread/test/test_futures.cpp
@@ -0,0 +1,1220 @@
+// (C) Copyright 2008-10 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// 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>
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ template<typename T>
+ typename boost::remove_reference<T>::type&& cast_to_rval(T&& t)
+ {
+ return static_cast<typename boost::remove_reference<T>::type&&>(t);
+ }
+#else
+ template<typename T>
+ boost::detail::thread_move_t<T> cast_to_rval(T& t)
+ {
+ return boost::move(t);
+ }
+#endif
+
+struct X
+{
+private:
+
+ X(X& other);
+
+public:
+
+ int i;
+
+ X():
+ i(42)
+ {}
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ X(X&& other):
+ i(other.i)
+ {
+ other.i=0;
+ }
+#else
+ X(boost::detail::thread_move_t<X> other):
+ i(other->i)
+ {
+ other->i=0;
+ }
+ operator boost::detail::thread_move_t<X>()
+ {
+ return boost::detail::thread_move_t<X>(*this);
+ }
+#endif
+ ~X()
+ {}
+};
+
+int make_int()
+{
+ return 42;
+}
+
+int throw_runtime_error()
+{
+ throw std::runtime_error("42");
+}
+
+void set_promise_thread(boost::promise<int>* p)
+{
+ p->set_value(42);
+}
+
+struct my_exception
+{};
+
+void set_promise_exception_thread(boost::promise<int>* p)
+{
+ p->set_exception(boost::copy_exception(my_exception()));
+}
+
+
+void test_store_value_from_thread()
+{
+ boost::promise<int> pi2;
+ boost::unique_future<int> fi2(pi2.get_future());
+ boost::thread(set_promise_thread,&pi2);
+ int j=fi2.get();
+ BOOST_CHECK(j==42);
+ BOOST_CHECK(fi2.is_ready());
+ BOOST_CHECK(fi2.has_value());
+ BOOST_CHECK(!fi2.has_exception());
+ BOOST_CHECK(fi2.get_state()==boost::future_state::ready);
+}
+
+
+void test_store_exception()
+{
+ boost::promise<int> pi3;
+ boost::unique_future<int> fi3=pi3.get_future();
+ boost::thread(set_promise_exception_thread,&pi3);
+ try
+ {
+ fi3.get();
+ BOOST_CHECK(false);
+ }
+ catch(my_exception)
+ {
+ BOOST_CHECK(true);
+ }
+
+ BOOST_CHECK(fi3.is_ready());
+ BOOST_CHECK(!fi3.has_value());
+ BOOST_CHECK(fi3.has_exception());
+ BOOST_CHECK(fi3.get_state()==boost::future_state::ready);
+}
+
+void test_initial_state()
+{
+ boost::unique_future<int> fi;
+ BOOST_CHECK(!fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+ int i;
+ try
+ {
+ i=fi.get();
+ BOOST_CHECK(false);
+ }
+ catch(boost::future_uninitialized)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+void test_waiting_future()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi;
+ fi=pi.get_future();
+
+ int i=0;
+ BOOST_CHECK(!fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(i==0);
+}
+
+void test_cannot_get_future_twice()
+{
+ boost::promise<int> pi;
+ pi.get_future();
+
+ try
+ {
+ pi.get_future();
+ BOOST_CHECK(false);
+ }
+ catch(boost::future_already_retrieved&)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+void test_set_value_updates_future_state()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi;
+ fi=pi.get_future();
+
+ pi.set_value(42);
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+void test_set_value_can_be_retrieved()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi;
+ fi=pi.get_future();
+
+ pi.set_value(42);
+
+ int i=0;
+ BOOST_CHECK(i=fi.get());
+ BOOST_CHECK(i==42);
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+void test_set_value_can_be_moved()
+{
+// boost::promise<int> pi;
+// boost::unique_future<int> fi;
+// fi=pi.get_future();
+
+// pi.set_value(42);
+
+// int i=0;
+// BOOST_CHECK(i=fi.get());
+// BOOST_CHECK(i==42);
+// BOOST_CHECK(fi.is_ready());
+// BOOST_CHECK(fi.has_value());
+// BOOST_CHECK(!fi.has_exception());
+// BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+void test_future_from_packaged_task_is_waiting()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+ int i=0;
+ BOOST_CHECK(!fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(i==0);
+}
+
+void test_invoking_a_packaged_task_populates_future()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ pt();
+
+ int i=0;
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=fi.get());
+ BOOST_CHECK(i==42);
+}
+
+void test_invoking_a_packaged_task_twice_throws()
+{
+ boost::packaged_task<int> pt(make_int);
+
+ pt();
+ try
+ {
+ pt();
+ BOOST_CHECK(false);
+ }
+ catch(boost::task_already_started)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+
+void test_cannot_get_future_twice_from_task()
+{
+ boost::packaged_task<int> pt(make_int);
+ pt.get_future();
+ try
+ {
+ pt.get_future();
+ BOOST_CHECK(false);
+ }
+ catch(boost::future_already_retrieved)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+void test_task_stores_exception_if_function_throws()
+{
+ boost::packaged_task<int> pt(throw_runtime_error);
+ boost::unique_future<int> fi=pt.get_future();
+
+ pt();
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+ try
+ {
+ fi.get();
+ BOOST_CHECK(false);
+ }
+ catch(std::exception&)
+ {
+ BOOST_CHECK(true);
+ }
+ catch(...)
+ {
+ BOOST_CHECK(!"Unknown exception thrown");
+ }
+
+}
+
+void test_void_promise()
+{
+ boost::promise<void> p;
+ boost::unique_future<void> f=p.get_future();
+ p.set_value();
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_value());
+ BOOST_CHECK(!f.has_exception());
+ BOOST_CHECK(f.get_state()==boost::future_state::ready);
+ f.get();
+}
+
+void test_reference_promise()
+{
+ boost::promise<int&> p;
+ boost::unique_future<int&> f=p.get_future();
+ int i=42;
+ p.set_value(i);
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_value());
+ BOOST_CHECK(!f.has_exception());
+ BOOST_CHECK(f.get_state()==boost::future_state::ready);
+ BOOST_CHECK(&f.get()==&i);
+}
+
+void do_nothing()
+{}
+
+void test_task_returning_void()
+{
+ boost::packaged_task<void> pt(do_nothing);
+ boost::unique_future<void> fi=pt.get_future();
+
+ pt();
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+int global_ref_target=0;
+
+int& return_ref()
+{
+ return global_ref_target;
+}
+
+void test_task_returning_reference()
+{
+ boost::packaged_task<int&> pt(return_ref);
+ boost::unique_future<int&> fi=pt.get_future();
+
+ pt();
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+ int& i=fi.get();
+ BOOST_CHECK(&i==&global_ref_target);
+}
+
+void test_shared_future()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ boost::shared_future<int> sf(::cast_to_rval(fi));
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+
+ pt();
+
+ int i=0;
+ BOOST_CHECK(sf.is_ready());
+ BOOST_CHECK(sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf.get());
+ BOOST_CHECK(i==42);
+}
+
+void test_copies_of_shared_future_become_ready_together()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ boost::shared_future<int> sf(::cast_to_rval(fi));
+ boost::shared_future<int> sf2(sf);
+ boost::shared_future<int> sf3;
+ sf3=sf;
+ BOOST_CHECK(sf.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(sf2.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(sf3.get_state()==boost::future_state::waiting);
+
+ pt();
+
+ int i=0;
+ BOOST_CHECK(sf.is_ready());
+ BOOST_CHECK(sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf.get());
+ BOOST_CHECK(i==42);
+ i=0;
+ BOOST_CHECK(sf2.is_ready());
+ BOOST_CHECK(sf2.has_value());
+ BOOST_CHECK(!sf2.has_exception());
+ BOOST_CHECK(sf2.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf2.get());
+ BOOST_CHECK(i==42);
+ i=0;
+ BOOST_CHECK(sf3.is_ready());
+ BOOST_CHECK(sf3.has_value());
+ BOOST_CHECK(!sf3.has_exception());
+ BOOST_CHECK(sf3.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf3.get());
+ BOOST_CHECK(i==42);
+}
+
+void test_shared_future_can_be_move_assigned_from_unique_future()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ boost::shared_future<int> sf;
+ sf=::cast_to_rval(fi);
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+
+ BOOST_CHECK(!sf.is_ready());
+ BOOST_CHECK(!sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::waiting);
+}
+
+void test_shared_future_void()
+{
+ boost::packaged_task<void> pt(do_nothing);
+ boost::unique_future<void> fi=pt.get_future();
+
+ boost::shared_future<void> sf(::cast_to_rval(fi));
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+
+ pt();
+
+ BOOST_CHECK(sf.is_ready());
+ BOOST_CHECK(sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::ready);
+ sf.get();
+}
+
+void test_shared_future_ref()
+{
+ boost::promise<int&> p;
+ boost::shared_future<int&> f(p.get_future());
+ int i=42;
+ p.set_value(i);
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_value());
+ BOOST_CHECK(!f.has_exception());
+ BOOST_CHECK(f.get_state()==boost::future_state::ready);
+ BOOST_CHECK(&f.get()==&i);
+}
+
+void test_can_get_a_second_future_from_a_moved_promise()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi=pi.get_future();
+
+ boost::promise<int> pi2(::cast_to_rval(pi));
+ boost::unique_future<int> fi2=pi.get_future();
+
+ pi2.set_value(3);
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(!fi2.is_ready());
+ BOOST_CHECK(fi.get()==3);
+ pi.set_value(42);
+ BOOST_CHECK(fi2.is_ready());
+ BOOST_CHECK(fi2.get()==42);
+}
+
+void test_can_get_a_second_future_from_a_moved_void_promise()
+{
+ boost::promise<void> pi;
+ boost::unique_future<void> fi=pi.get_future();
+
+ boost::promise<void> pi2(::cast_to_rval(pi));
+ boost::unique_future<void> fi2=pi.get_future();
+
+ pi2.set_value();
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(!fi2.is_ready());
+ pi.set_value();
+ BOOST_CHECK(fi2.is_ready());
+}
+
+void test_unique_future_for_move_only_udt()
+{
+ boost::promise<X> pt;
+ boost::unique_future<X> fi=pt.get_future();
+
+ pt.set_value(X());
+ X res(fi.get());
+ BOOST_CHECK(res.i==42);
+}
+
+void test_unique_future_for_string()
+{
+ boost::promise<std::string> pt;
+ boost::unique_future<std::string> fi=pt.get_future();
+
+ pt.set_value(std::string("hello"));
+ std::string res(fi.get());
+ BOOST_CHECK(res=="hello");
+
+ boost::promise<std::string> pt2;
+ fi=pt2.get_future();
+
+ std::string const s="goodbye";
+
+ pt2.set_value(s);
+ res=fi.get();
+ BOOST_CHECK(res=="goodbye");
+
+ boost::promise<std::string> pt3;
+ fi=pt3.get_future();
+
+ std::string s2="foo";
+
+ pt3.set_value(s2);
+ res=fi.get();
+ BOOST_CHECK(res=="foo");
+}
+
+boost::mutex callback_mutex;
+unsigned callback_called=0;
+
+void wait_callback(boost::promise<int>& pi)
+{
+ boost::lock_guard<boost::mutex> lk(callback_mutex);
+ ++callback_called;
+ try
+ {
+ pi.set_value(42);
+ }
+ catch(...)
+ {
+ }
+}
+
+void do_nothing_callback(boost::promise<int>& /*pi*/)
+{
+ boost::lock_guard<boost::mutex> lk(callback_mutex);
+ ++callback_called;
+}
+
+void test_wait_callback()
+{
+ callback_called=0;
+ boost::promise<int> pi;
+ boost::unique_future<int> fi=pi.get_future();
+ pi.set_wait_callback(wait_callback);
+ fi.wait();
+ BOOST_CHECK(callback_called);
+ BOOST_CHECK(fi.get()==42);
+ fi.wait();
+ fi.wait();
+ BOOST_CHECK(callback_called==1);
+}
+
+void test_wait_callback_with_timed_wait()
+{
+ callback_called=0;
+ boost::promise<int> pi;
+ boost::unique_future<int> fi=pi.get_future();
+ pi.set_wait_callback(do_nothing_callback);
+ bool success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(callback_called);
+ BOOST_CHECK(!success);
+ success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(!success);
+ success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(!success);
+ BOOST_CHECK(callback_called==3);
+ pi.set_value(42);
+ success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(success);
+ BOOST_CHECK(callback_called==3);
+ BOOST_CHECK(fi.get()==42);
+ BOOST_CHECK(callback_called==3);
+}
+
+
+void wait_callback_for_task(boost::packaged_task<int>& pt)
+{
+ boost::lock_guard<boost::mutex> lk(callback_mutex);
+ ++callback_called;
+ try
+ {
+ pt();
+ }
+ catch(...)
+ {
+ }
+}
+
+
+void test_wait_callback_for_packaged_task()
+{
+ callback_called=0;
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+ pt.set_wait_callback(wait_callback_for_task);
+ fi.wait();
+ BOOST_CHECK(callback_called);
+ BOOST_CHECK(fi.get()==42);
+ fi.wait();
+ fi.wait();
+ BOOST_CHECK(callback_called==1);
+}
+
+void test_packaged_task_can_be_moved()
+{
+ boost::packaged_task<int> pt(make_int);
+
+ boost::unique_future<int> fi=pt.get_future();
+
+ BOOST_CHECK(!fi.is_ready());
+
+ boost::packaged_task<int> pt2(::cast_to_rval(pt));
+
+ BOOST_CHECK(!fi.is_ready());
+ try
+ {
+ pt();
+ BOOST_CHECK(!"Can invoke moved task!");
+ }
+ catch(boost::task_moved&)
+ {
+ }
+
+ BOOST_CHECK(!fi.is_ready());
+
+ pt2();
+
+ BOOST_CHECK(fi.is_ready());
+}
+
+void test_destroying_a_promise_stores_broken_promise()
+{
+ boost::unique_future<int> f;
+
+ {
+ boost::promise<int> p;
+ f=p.get_future();
+ }
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_exception());
+ try
+ {
+ f.get();
+ }
+ catch(boost::broken_promise&)
+ {
+ }
+}
+
+void test_destroying_a_packaged_task_stores_broken_promise()
+{
+ boost::unique_future<int> f;
+
+ {
+ boost::packaged_task<int> p(make_int);
+ f=p.get_future();
+ }
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_exception());
+ try
+ {
+ f.get();
+ }
+ catch(boost::broken_promise&)
+ {
+ }
+}
+
+int make_int_slowly()
+{
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ return 42;
+}
+
+void test_wait_for_either_of_two_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_two_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+
+void test_wait_for_either_of_three_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_three_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+
+void test_wait_for_either_of_three_futures_3()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+
+ boost::thread(::cast_to_rval(pt3));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3);
+
+ BOOST_CHECK(future==2);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f3.is_ready());
+ BOOST_CHECK(f3.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_3()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt3));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==2);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f3.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_4()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt4));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==3);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f4.is_ready());
+ BOOST_CHECK(f4.get()==42);
+}
+
+void test_wait_for_either_of_five_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_five_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+void test_wait_for_either_of_five_futures_3()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt3));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==2);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f3.get()==42);
+}
+void test_wait_for_either_of_five_futures_4()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt4));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==3);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f4.get()==42);
+}
+void test_wait_for_either_of_five_futures_5()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt5));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==4);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f5.is_ready());
+ BOOST_CHECK(f5.get()==42);
+}
+
+void test_wait_for_either_invokes_callbacks()
+{
+ callback_called=0;
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> fi=pt.get_future();
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> fi2=pt2.get_future();
+ pt.set_wait_callback(wait_callback_for_task);
+
+ boost::thread(::cast_to_rval(pt));
+
+ boost::wait_for_any(fi,fi2);
+ BOOST_CHECK(callback_called==1);
+ BOOST_CHECK(fi.get()==42);
+}
+
+void test_wait_for_any_from_range()
+{
+ unsigned const count=10;
+ for(unsigned i=0;i<count;++i)
+ {
+ boost::packaged_task<int> tasks[count];
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ tasks[j]=boost::packaged_task<int>(make_int_slowly);
+ futures[j]=tasks[j].get_future();
+ }
+ boost::thread(::cast_to_rval(tasks[i]));
+
+ BOOST_CHECK(boost::wait_for_any(futures,futures)==futures);
+
+ boost::unique_future<int>* const future=boost::wait_for_any(futures,futures+count);
+
+ BOOST_CHECK(future==(futures+i));
+ for(unsigned j=0;j<count;++j)
+ {
+ if(j!=i)
+ {
+ BOOST_CHECK(!futures[j].is_ready());
+ }
+ else
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+ }
+ BOOST_CHECK(futures[i].get()==42);
+ }
+}
+
+void test_wait_for_all_from_range()
+{
+ unsigned const count=10;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures,futures+count);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_two_futures()
+{
+ unsigned const count=2;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_three_futures()
+{
+ unsigned const count=3;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1],futures[2]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_four_futures()
+{
+ unsigned const count=4;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1],futures[2],futures[3]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_five_futures()
+{
+ unsigned const count=5;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1],futures[2],futures[3],futures[4]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+
+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_initial_state));
+ test->add(BOOST_TEST_CASE(test_waiting_future));
+ test->add(BOOST_TEST_CASE(test_cannot_get_future_twice));
+ test->add(BOOST_TEST_CASE(test_set_value_updates_future_state));
+ test->add(BOOST_TEST_CASE(test_set_value_can_be_retrieved));
+ test->add(BOOST_TEST_CASE(test_set_value_can_be_moved));
+ test->add(BOOST_TEST_CASE(test_store_value_from_thread));
+ test->add(BOOST_TEST_CASE(test_store_exception));
+ test->add(BOOST_TEST_CASE(test_future_from_packaged_task_is_waiting));
+ test->add(BOOST_TEST_CASE(test_invoking_a_packaged_task_populates_future));
+ test->add(BOOST_TEST_CASE(test_invoking_a_packaged_task_twice_throws));
+ test->add(BOOST_TEST_CASE(test_cannot_get_future_twice_from_task));
+ test->add(BOOST_TEST_CASE(test_task_stores_exception_if_function_throws));
+ test->add(BOOST_TEST_CASE(test_void_promise));
+ test->add(BOOST_TEST_CASE(test_reference_promise));
+ test->add(BOOST_TEST_CASE(test_task_returning_void));
+ test->add(BOOST_TEST_CASE(test_task_returning_reference));
+ test->add(BOOST_TEST_CASE(test_shared_future));
+ test->add(BOOST_TEST_CASE(test_copies_of_shared_future_become_ready_together));
+ test->add(BOOST_TEST_CASE(test_shared_future_can_be_move_assigned_from_unique_future));
+ test->add(BOOST_TEST_CASE(test_shared_future_void));
+ test->add(BOOST_TEST_CASE(test_shared_future_ref));
+ test->add(BOOST_TEST_CASE(test_can_get_a_second_future_from_a_moved_promise));
+ test->add(BOOST_TEST_CASE(test_can_get_a_second_future_from_a_moved_void_promise));
+ test->add(BOOST_TEST_CASE(test_unique_future_for_move_only_udt));
+ test->add(BOOST_TEST_CASE(test_unique_future_for_string));
+ test->add(BOOST_TEST_CASE(test_wait_callback));
+ test->add(BOOST_TEST_CASE(test_wait_callback_with_timed_wait));
+ test->add(BOOST_TEST_CASE(test_wait_callback_for_packaged_task));
+ test->add(BOOST_TEST_CASE(test_packaged_task_can_be_moved));
+ test->add(BOOST_TEST_CASE(test_destroying_a_promise_stores_broken_promise));
+ test->add(BOOST_TEST_CASE(test_destroying_a_packaged_task_stores_broken_promise));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_two_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_two_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_3));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_3));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_4));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_3));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_4));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_5));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_invokes_callbacks));
+ test->add(BOOST_TEST_CASE(test_wait_for_any_from_range));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_from_range));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_two_futures));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_three_futures));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_four_futures));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_five_futures));
+
+ return test;
+}
diff --git a/libs/thread/test/test_generic_locks.cpp b/libs/thread/test/test_generic_locks.cpp
new file mode 100644
index 0000000000..8e66fad459
--- /dev/null
+++ b/libs/thread/test/test_generic_locks.cpp
@@ -0,0 +1,594 @@
+// (C) Copyright 2008 Anthony Williams
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+void test_lock_two_uncontended()
+{
+ boost::mutex m1,m2;
+
+ boost::mutex::scoped_lock l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+
+ boost::lock(l1,l2);
+
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+}
+
+struct wait_data
+{
+ boost::mutex m;
+ bool flag;
+ boost::condition_variable cond;
+
+ wait_data():
+ flag(false)
+ {}
+
+ void wait()
+ {
+ boost::mutex::scoped_lock l(m);
+ while(!flag)
+ {
+ cond.wait(l);
+ }
+ }
+
+ template<typename Duration>
+ bool timed_wait(Duration d)
+ {
+ boost::system_time const target=boost::get_system_time()+d;
+
+ boost::mutex::scoped_lock l(m);
+ while(!flag)
+ {
+ if(!cond.timed_wait(l,target))
+ {
+ return flag;
+ }
+ }
+ return true;
+ }
+
+ void signal()
+ {
+ boost::mutex::scoped_lock l(m);
+ flag=true;
+ cond.notify_all();
+ }
+};
+
+
+void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
+{
+ boost::lock_guard<boost::mutex> l1(*m1);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l2(*m2);
+ locked->signal();
+ quit->wait();
+}
+
+void lock_pair(boost::mutex* m1,boost::mutex* m2)
+{
+ boost::lock(*m1,*m2);
+ boost::mutex::scoped_lock l1(*m1,boost::adopt_lock),
+ l2(*m2,boost::adopt_lock);
+}
+
+void test_lock_two_other_thread_locks_in_order()
+{
+ boost::mutex m1,m2;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_pair,&m1,&m2);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
+
+ t.join();
+}
+
+void test_lock_two_other_thread_locks_in_opposite_order()
+{
+ boost::mutex m1,m2;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_pair,&m2,&m1);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
+
+ t.join();
+}
+
+void test_lock_five_uncontended()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+
+ boost::mutex::scoped_lock l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock),
+ l3(m3,boost::defer_lock),
+ l4(m4,boost::defer_lock),
+ l5(m5,boost::defer_lock);
+
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ BOOST_CHECK(!l5.owns_lock());
+
+ boost::lock(l1,l2,l3,l4,l5);
+
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ BOOST_CHECK(l5.owns_lock());
+}
+
+void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
+ wait_data* locked,wait_data* quit)
+{
+ boost::lock_guard<boost::mutex> l1(*m1);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l2(*m2);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l3(*m3);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l4(*m4);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l5(*m5);
+ locked->signal();
+ quit->wait();
+}
+
+void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
+{
+ boost::lock(*m1,*m2,*m3,*m4,*m5);
+ m1->unlock();
+ m2->unlock();
+ m3->unlock();
+ m4->unlock();
+ m5->unlock();
+}
+
+void test_lock_five_other_thread_locks_in_order()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+void test_lock_five_other_thread_locks_in_different_order()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+void lock_n(boost::mutex* mutexes,unsigned count)
+{
+ boost::lock(mutexes,mutexes+count);
+ for(unsigned i=0;i<count;++i)
+ {
+ mutexes[i].unlock();
+ }
+}
+
+
+void test_lock_ten_other_thread_locks_in_different_order()
+{
+ unsigned const num_mutexes=10;
+
+ boost::mutex mutexes[num_mutexes];
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_n,mutexes,num_mutexes);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+struct dummy_mutex
+{
+ bool is_locked;
+
+ dummy_mutex():
+ is_locked(false)
+ {}
+
+ void lock()
+ {
+ is_locked=true;
+ }
+
+ bool try_lock()
+ {
+ if(is_locked)
+ {
+ return false;
+ }
+ is_locked=true;
+ return true;
+ }
+
+ void unlock()
+ {
+ is_locked=false;
+ }
+};
+
+namespace boost
+{
+ template<>
+ struct is_mutex_type<dummy_mutex>
+ {
+ BOOST_STATIC_CONSTANT(bool, value = true);
+ };
+}
+
+
+
+void test_lock_five_in_range()
+{
+ unsigned const num_mutexes=5;
+ dummy_mutex mutexes[num_mutexes];
+
+ boost::lock(mutexes,mutexes+num_mutexes);
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+class dummy_iterator:
+ public std::iterator<std::forward_iterator_tag,
+ dummy_mutex>
+{
+private:
+ dummy_mutex* p;
+public:
+ explicit dummy_iterator(dummy_mutex* p_):
+ p(p_)
+ {}
+
+ bool operator==(dummy_iterator const& other) const
+ {
+ return p==other.p;
+ }
+
+ bool operator!=(dummy_iterator const& other) const
+ {
+ return p!=other.p;
+ }
+
+ bool operator<(dummy_iterator const& other) const
+ {
+ return p<other.p;
+ }
+
+ dummy_mutex& operator*() const
+ {
+ return *p;
+ }
+
+ dummy_mutex* operator->() const
+ {
+ return p;
+ }
+
+ dummy_iterator operator++(int)
+ {
+ dummy_iterator temp(*this);
+ ++p;
+ return temp;
+ }
+
+ dummy_iterator& operator++()
+ {
+ ++p;
+ return *this;
+ }
+
+};
+
+
+void test_lock_five_in_range_custom_iterator()
+{
+ unsigned const num_mutexes=5;
+ dummy_mutex mutexes[num_mutexes];
+
+ boost::lock(dummy_iterator(mutexes),dummy_iterator(mutexes+num_mutexes));
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+class dummy_mutex2:
+ public dummy_mutex
+{};
+
+
+void test_lock_ten_in_range_inherited_mutex()
+{
+ unsigned const num_mutexes=10;
+ dummy_mutex2 mutexes[num_mutexes];
+
+ boost::lock(mutexes,mutexes+num_mutexes);
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+void test_try_lock_two_uncontended()
+{
+ dummy_mutex m1,m2;
+
+ int const res=boost::try_lock(m1,m2);
+
+ BOOST_CHECK(res==-1);
+ BOOST_CHECK(m1.is_locked);
+ BOOST_CHECK(m2.is_locked);
+}
+void test_try_lock_two_first_locked()
+{
+ dummy_mutex m1,m2;
+ m1.lock();
+
+ boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2);
+
+ BOOST_CHECK(res==0);
+ BOOST_CHECK(m1.is_locked);
+ BOOST_CHECK(!m2.is_locked);
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+}
+void test_try_lock_two_second_locked()
+{
+ dummy_mutex m1,m2;
+ m2.lock();
+
+ boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2);
+
+ BOOST_CHECK(res==1);
+ BOOST_CHECK(!m1.is_locked);
+ BOOST_CHECK(m2.is_locked);
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+}
+
+void test_try_lock_three()
+{
+ int const num_mutexes=3;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ }
+ }
+}
+
+void test_try_lock_four()
+{
+ int const num_mutexes=4;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock),
+ l4(mutexes[3],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3,l4);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ }
+ }
+}
+
+void test_try_lock_five()
+{
+ int const num_mutexes=5;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock),
+ l4(mutexes[3],boost::defer_lock),
+ l5(mutexes[4],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3,l4,l5);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ BOOST_CHECK(l5.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ BOOST_CHECK(!l5.owns_lock());
+ }
+ }
+}
+
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
+
+ test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
+ test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order));
+ test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_uncontended));
+ test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
+ test->add(BOOST_TEST_CASE(&test_lock_five_in_range_custom_iterator));
+ test->add(BOOST_TEST_CASE(&test_lock_ten_in_range_inherited_mutex));
+ test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked));
+ test->add(BOOST_TEST_CASE(&test_try_lock_three));
+ test->add(BOOST_TEST_CASE(&test_try_lock_four));
+ test->add(BOOST_TEST_CASE(&test_try_lock_five));
+
+ return test;
+}
diff --git a/libs/thread/test/test_hardware_concurrency.cpp b/libs/thread/test/test_hardware_concurrency.cpp
new file mode 100644
index 0000000000..39f2fd6ad2
--- /dev/null
+++ b/libs/thread/test/test_hardware_concurrency.cpp
@@ -0,0 +1,21 @@
+// 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>
+#include <boost/thread/mutex.hpp>
+
+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::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
+
+ test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
+ return test;
+}
diff --git a/libs/thread/test/test_lock_concept.cpp b/libs/thread/test/test_lock_concept.cpp
new file mode 100644
index 0000000000..bd0a22ad89
--- /dev/null
+++ b/libs/thread/test/test_lock_concept.cpp
@@ -0,0 +1,570 @@
+// (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/test/unit_test.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+template<typename Mutex,typename Lock>
+struct test_initially_locked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_unlocked_if_other_thread_has_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_unlocked_if_other_thread_has_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m);
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ bool is_done() const
+ {
+ return done;
+ }
+
+
+ void operator()()
+ {
+ Lock lock(m);
+
+ typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m,boost::try_to_lock);
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ bool is_done() const
+ {
+ return done;
+ }
+
+
+ void operator()()
+ {
+ boost::unique_lock<Mutex> lock(m);
+
+ typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_locked_if_other_thread_has_shared_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_locked_if_other_thread_has_shared_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m);
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ bool is_done() const
+ {
+ return done;
+ }
+
+
+ void operator()()
+ {
+ boost::shared_lock<Mutex> lock(m);
+
+ typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_unlocked_with_defer_lock_parameter
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m,boost::defer_lock);
+
+ BOOST_CHECK(!lock);
+ BOOST_CHECK(!lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_locked_with_adopt_lock_parameter
+{
+ void operator()() const
+ {
+ Mutex m;
+ m.lock();
+ Lock lock(m,boost::adopt_lock);
+
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+
+template<typename Mutex,typename Lock>
+struct test_unlocked_after_unlock_called
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ BOOST_CHECK(!lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_locked_after_lock_called
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m,boost::defer_lock);
+ lock.lock();
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_locked_after_try_lock_called
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m,boost::defer_lock);
+ lock.try_lock();
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+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
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+
+ BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_throws_if_try_lock_called_when_already_locked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+
+ BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_throws_if_unlock_called_when_already_unlocked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+ lock.unlock();
+
+ BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
+ }
+};
+template<typename Lock>
+struct test_default_constructed_has_no_mutex_and_unlocked
+{
+ void operator()() const
+ {
+ Lock l;
+ BOOST_CHECK(!l.mutex());
+ BOOST_CHECK(!l.owns_lock());
+ };
+};
+
+
+template<typename Mutex,typename Lock>
+struct test_locks_can_be_swapped
+{
+ void operator()() const
+ {
+ Mutex m1;
+ Mutex m2;
+ Mutex m3;
+
+ Lock l1(m1);
+ Lock l2(m2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m1);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m2);
+
+ l1.swap(l2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m2);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m1);
+
+ swap(l1,l2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m1);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m2);
+
+ l1.swap(Lock(m3));
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m3);
+ }
+};
+
+template<typename Mutex,typename Lock>
+void test_lock_is_scoped_lock_concept_for_mutex()
+{
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
+ test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
+ test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
+ test_unlocked_after_unlock_called<Mutex,Lock>()();
+ test_locked_after_lock_called<Mutex,Lock>()();
+ test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
+ test_locked_after_try_lock_called<Mutex,Lock>()();
+ test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
+ test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
+}
+
+
+BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
+{
+ typedef typename Mutex::scoped_lock Lock;
+
+ test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
+}
+
+BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex)
+{
+ typedef boost::unique_lock<Mutex> Lock;
+
+ test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
+}
+
+BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
+{
+ typedef typename Mutex::scoped_try_lock Lock;
+
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
+ test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
+ test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
+ test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
+ test_unlocked_after_unlock_called<Mutex,Lock>()();
+ test_locked_after_lock_called<Mutex,Lock>()();
+ test_locked_after_try_lock_called<Mutex,Lock>()();
+ test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
+ test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
+}
+
+struct dummy_shared_mutex
+{
+ bool locked;
+ bool shared_locked;
+ bool shared_unlocked;
+ bool shared_timed_locked_relative;
+ bool shared_timed_locked_absolute;
+ bool timed_locked_relative;
+ bool timed_locked_absolute;
+
+ dummy_shared_mutex():
+ locked(false),shared_locked(false),shared_unlocked(false),
+ shared_timed_locked_relative(false),
+ shared_timed_locked_absolute(false),
+ timed_locked_relative(false),
+ timed_locked_absolute(false)
+ {}
+
+ void lock()
+ {
+ locked=true;
+ }
+
+ void lock_shared()
+ {
+ shared_locked=true;
+ }
+
+ void unlock()
+ {}
+
+ void unlock_shared()
+ {
+ shared_unlocked=true;
+ }
+
+ bool timed_lock_shared(boost::system_time)
+ {
+ shared_timed_locked_absolute=true;
+ return false;
+ }
+ template<typename Duration>
+ bool timed_lock_shared(Duration)
+ {
+ shared_timed_locked_relative=true;
+ return false;
+ }
+ bool timed_lock(boost::system_time)
+ {
+ timed_locked_absolute=true;
+ return false;
+ }
+ template<typename Duration>
+ bool timed_lock(Duration)
+ {
+ timed_locked_relative=true;
+ return false;
+ }
+
+};
+
+
+void test_shared_lock()
+{
+ typedef boost::shared_mutex Mutex;
+ typedef boost::shared_lock<Mutex> Lock;
+
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
+ test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
+ test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
+ test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
+ test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
+ test_unlocked_after_unlock_called<Mutex,Lock>()();
+ 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_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;
+
+ test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
+
+ typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
+ boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
+
+ test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
+
+ typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
+ boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
+
+ test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
+ test->add(BOOST_TEST_CASE(&test_shared_lock));
+
+ return test;
+}
diff --git a/libs/thread/test/test_move_function.cpp b/libs/thread/test/test_move_function.cpp
new file mode 100644
index 0000000000..fa139e8863
--- /dev/null
+++ b/libs/thread/test/test_move_function.cpp
@@ -0,0 +1,145 @@
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/shared_ptr.hpp>
+
+void do_nothing()
+{}
+
+void test_thread_move_from_lvalue_on_construction()
+{
+ boost::thread src(do_nothing);
+ boost::thread::id src_id=src.get_id();
+ boost::thread dest(boost::move(src));
+ boost::thread::id dest_id=dest.get_id();
+ BOOST_CHECK(src_id==dest_id);
+ BOOST_CHECK(src.get_id()==boost::thread::id());
+ dest.join();
+}
+
+void test_thread_move_from_lvalue_on_assignment()
+{
+ boost::thread src(do_nothing);
+ boost::thread::id src_id=src.get_id();
+ boost::thread dest;
+ dest=boost::move(src);
+ boost::thread::id dest_id=dest.get_id();
+ BOOST_CHECK(src_id==dest_id);
+ BOOST_CHECK(src.get_id()==boost::thread::id());
+ dest.join();
+}
+
+boost::thread start_thread()
+{
+ return boost::thread(do_nothing);
+}
+
+void test_thread_move_from_rvalue_on_construction()
+{
+ boost::thread x(start_thread());
+ BOOST_CHECK(x.get_id()!=boost::thread::id());
+ x.join();
+}
+
+void test_thread_move_from_rvalue_using_explicit_move()
+{
+ boost::thread x(boost::move(start_thread()));
+ BOOST_CHECK(x.get_id()!=boost::thread::id());
+ x.join();
+}
+
+void test_unique_lock_move_from_lvalue_on_construction()
+{
+ boost::mutex m;
+ boost::unique_lock<boost::mutex> l(m);
+ BOOST_CHECK(l.owns_lock());
+ BOOST_CHECK(l.mutex()==&m);
+
+ boost::unique_lock<boost::mutex> l2(boost::move(l));
+ BOOST_CHECK(!l.owns_lock());
+ BOOST_CHECK(!l.mutex());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l2.mutex()==&m);
+}
+
+boost::unique_lock<boost::mutex> get_lock(boost::mutex& m)
+{
+ return boost::unique_lock<boost::mutex>(m);
+}
+
+
+void test_unique_lock_move_from_rvalue_on_construction()
+{
+ boost::mutex m;
+ boost::unique_lock<boost::mutex> l(get_lock(m));
+ BOOST_CHECK(l.owns_lock());
+ BOOST_CHECK(l.mutex()==&m);
+}
+
+namespace user_test_ns
+{
+ template<typename T>
+ T move(T& t)
+ {
+ return t.move();
+ }
+
+ bool move_called=false;
+
+ struct nc:
+ public boost::shared_ptr<int>
+ {
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ nc() {}
+ nc(nc&&)
+ {
+ move_called=true;
+ }
+#endif
+ nc move()
+ {
+ move_called=true;
+ return nc();
+ }
+ };
+}
+
+#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::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_using_explicit_move));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment));
+ test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected));
+ return test;
+}
diff --git a/libs/thread/test/test_mutex.cpp b/libs/thread/test/test_mutex.cpp
new file mode 100644
index 0000000000..0350898e8b
--- /dev/null
+++ b/libs/thread/test/test_mutex.cpp
@@ -0,0 +1,347 @@
+// 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/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <boost/thread/condition.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
+#include <libs/thread/test/util.inl>
+
+template <typename M>
+struct test_lock
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_lock lock_type;
+
+ void operator()()
+ {
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ lock_type lock(mutex, boost::defer_lock);
+ BOOST_CHECK(!lock);
+ }
+ lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt = delay(0, 100);
+
+ // Test the lock and the mutex with condition variables.
+ // No one is going to notify this condition variable. We expect to
+ // time out.
+ BOOST_CHECK(!condition.timed_wait(lock, xt));
+ BOOST_CHECK(lock ? true : false);
+
+ // Test the lock and unlock methods.
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ lock.lock();
+ BOOST_CHECK(lock ? true : false);
+ }
+};
+
+template <typename M>
+struct test_trylock
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_try_lock try_lock_type;
+
+ void operator()()
+ {
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ try_lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+ }
+ {
+ try_lock_type lock(mutex, boost::defer_lock);
+ BOOST_CHECK(!lock);
+ }
+ try_lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt = delay(0, 100);
+
+ // Test the lock and the mutex with condition variables.
+ // No one is going to notify this condition variable. We expect to
+ // time out.
+ BOOST_CHECK(!condition.timed_wait(lock, xt));
+ BOOST_CHECK(lock ? true : false);
+
+ // Test the lock, unlock and trylock methods.
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ lock.lock();
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ BOOST_CHECK(lock.try_lock());
+ BOOST_CHECK(lock ? true : false);
+ }
+};
+
+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
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_timed_lock timed_lock_type;
+
+ static bool fake_predicate()
+ {
+ return false;
+ }
+
+ void operator()()
+ {
+ test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
+
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ // Construct and initialize an xtime for a fast time out.
+ boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
+
+ timed_lock_type lock(mutex, xt);
+ BOOST_CHECK(lock ? true : false);
+ }
+ {
+ timed_lock_type lock(mutex, boost::defer_lock);
+ BOOST_CHECK(!lock);
+ }
+ timed_lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100);
+
+ // Test the lock and the mutex with condition variables.
+ // No one is going to notify this condition variable. We expect to
+ // time out.
+ BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate));
+ BOOST_CHECK(lock ? true : false);
+
+ boost::system_time now=boost::get_system_time();
+ boost::posix_time::milliseconds const timeout_resolution(20);
+ BOOST_CHECK((timeout-timeout_resolution)<now);
+
+ // Test the lock, unlock and timedlock methods.
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ lock.lock();
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
+ BOOST_CHECK(lock.timed_lock(target));
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+
+ BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
+ mutex.unlock();
+
+ BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+
+ }
+};
+
+template <typename M>
+struct test_recursive_lock
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_lock lock_type;
+
+ void operator()()
+ {
+ mutex_type mx;
+ lock_type lock1(mx);
+ lock_type lock2(mx);
+ }
+};
+
+
+void do_test_mutex()
+{
+ test_lock<boost::mutex>()();
+}
+
+void test_mutex()
+{
+ timed_test(&do_test_mutex, 3);
+}
+
+void do_test_try_mutex()
+{
+ test_lock<boost::try_mutex>()();
+ test_trylock<boost::try_mutex>()();
+}
+
+void test_try_mutex()
+{
+ timed_test(&do_test_try_mutex, 3);
+}
+
+void do_test_timed_mutex()
+{
+ test_lock<boost::timed_mutex>()();
+ test_trylock<boost::timed_mutex>()();
+ test_timedlock<boost::timed_mutex>()();
+}
+
+void test_timed_mutex()
+{
+ timed_test(&do_test_timed_mutex, 3);
+}
+
+void do_test_recursive_mutex()
+{
+ test_lock<boost::recursive_mutex>()();
+ test_recursive_lock<boost::recursive_mutex>()();
+}
+
+void test_recursive_mutex()
+{
+ timed_test(&do_test_recursive_mutex, 3);
+}
+
+void do_test_recursive_try_mutex()
+{
+ test_lock<boost::recursive_try_mutex>()();
+ test_trylock<boost::recursive_try_mutex>()();
+ test_recursive_lock<boost::recursive_try_mutex>()();
+}
+
+void test_recursive_try_mutex()
+{
+ timed_test(&do_test_recursive_try_mutex, 3);
+}
+
+void do_test_recursive_timed_mutex()
+{
+ test_lock<boost::recursive_timed_mutex>()();
+ test_trylock<boost::recursive_timed_mutex>()();
+ test_timedlock<boost::recursive_timed_mutex>()();
+ test_recursive_lock<boost::recursive_timed_mutex>()();
+}
+
+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::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_mutex));
+ test->add(BOOST_TEST_CASE(&test_try_mutex));
+ test->add(BOOST_TEST_CASE(&test_timed_mutex));
+ test->add(BOOST_TEST_CASE(&test_recursive_mutex));
+ test->add(BOOST_TEST_CASE(&test_recursive_try_mutex));
+ test->add(BOOST_TEST_CASE(&test_recursive_timed_mutex));
+
+ return test;
+}
diff --git a/libs/thread/test/test_once.cpp b/libs/thread/test/test_once.cpp
new file mode 100644
index 0000000000..340bef7e3c
--- /dev/null
+++ b/libs/thread/test/test_once.cpp
@@ -0,0 +1,191 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/once.hpp>
+
+boost::once_flag flag=BOOST_ONCE_INIT;
+int var_to_init=0;
+boost::mutex m;
+
+void initialize_variable()
+{
+ // ensure that if multiple threads get in here, they are serialized, so we can see the effect
+ boost::mutex::scoped_lock lock(m);
+ ++var_to_init;
+}
+
+
+void call_once_thread()
+{
+ unsigned const loop_count=100;
+ int my_once_value=0;
+ for(unsigned i=0;i<loop_count;++i)
+ {
+ boost::call_once(flag, initialize_variable);
+ my_once_value=var_to_init;
+ if(my_once_value!=1)
+ {
+ break;
+ }
+ }
+ boost::mutex::scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+void test_call_once()
+{
+ unsigned const num_threads=20;
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_thread);
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init,1);
+}
+
+int var_to_init_with_functor=0;
+
+struct increment_value
+{
+ int* value;
+ explicit increment_value(int* value_):
+ value(value_)
+ {}
+
+ void operator()() const
+ {
+ boost::mutex::scoped_lock lock(m);
+ ++(*value);
+ }
+};
+
+void call_once_with_functor()
+{
+ unsigned const loop_count=100;
+ int my_once_value=0;
+ static boost::once_flag functor_flag=BOOST_ONCE_INIT;
+ for(unsigned i=0;i<loop_count;++i)
+ {
+ boost::call_once(functor_flag, increment_value(&var_to_init_with_functor));
+ my_once_value=var_to_init_with_functor;
+ if(my_once_value!=1)
+ {
+ break;
+ }
+ }
+ boost::mutex::scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+void test_call_once_arbitrary_functor()
+{
+ unsigned const num_threads=20;
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_with_functor);
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
+}
+
+
+struct throw_before_third_pass
+{
+ struct my_exception
+ {};
+
+ static unsigned pass_counter;
+
+ void operator()() const
+ {
+ boost::mutex::scoped_lock lock(m);
+ ++pass_counter;
+ if(pass_counter<3)
+ {
+ throw my_exception();
+ }
+ }
+};
+
+unsigned throw_before_third_pass::pass_counter=0;
+unsigned exception_counter=0;
+
+void call_once_with_exception()
+{
+ static boost::once_flag functor_flag=BOOST_ONCE_INIT;
+ try
+ {
+ boost::call_once(functor_flag, throw_before_third_pass());
+ }
+ catch(throw_before_third_pass::my_exception)
+ {
+ boost::mutex::scoped_lock lock(m);
+ ++exception_counter;
+ }
+}
+
+void test_call_once_retried_on_exception()
+{
+ unsigned const num_threads=20;
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_with_exception);
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
+ BOOST_CHECK_EQUAL(exception_counter,2u);
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
+
+ test->add(BOOST_TEST_CASE(test_call_once));
+ test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor));
+ test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception));
+
+ return test;
+}
diff --git a/libs/thread/test/test_shared_mutex.cpp b/libs/thread/test/test_shared_mutex.cpp
new file mode 100644
index 0000000000..6085bd1211
--- /dev/null
+++ b/libs/thread/test/test_shared_mutex.cpp
@@ -0,0 +1,285 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include "util.inl"
+#include "shared_mutex_locking_thread.hpp"
+
+#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
+ { \
+ boost::mutex::scoped_lock lock(mutex_name); \
+ BOOST_CHECK_EQUAL(value,expected_value); \
+ }
+
+void test_multiple_readers()
+{
+ unsigned const number_of_threads=10;
+
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+ for(unsigned i=0;i<number_of_threads;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<number_of_threads)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
+}
+
+void test_only_one_writer_permitted()
+{
+ unsigned const number_of_threads=10;
+
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+ for(unsigned i=0;i<number_of_threads;++i)
+ {
+ pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+
+ boost::thread::sleep(delay(2));
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
+}
+
+void test_reader_blocks_writer()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<1)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+ pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
+}
+
+void test_unlocking_writer_unblocks_all_readers()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex);
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ unsigned const reader_count=10;
+
+ try
+ {
+ for(unsigned i=0;i<reader_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
+
+ write_lock.unlock();
+
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<reader_count)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
+
+ finish_lock.unlock();
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
+}
+
+void test_unlocking_last_reader_only_unblocks_one_writer()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_readers=0;
+ unsigned max_simultaneous_readers=0;
+ unsigned simultaneous_running_writers=0;
+ unsigned max_simultaneous_writers=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_reading_mutex;
+ boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
+ 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;
+
+ try
+ {
+ for(unsigned i=0;i<reader_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
+ }
+ boost::thread::sleep(delay(1));
+ for(unsigned i=0;i<writer_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
+ }
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<reader_count)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
+
+ finish_reading_lock.unlock();
+
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<(reader_count+1))
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
+
+ finish_writing_lock.unlock();
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
+ 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::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_multiple_readers));
+ test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted));
+ test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
+ test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
+ test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
+
+ return test;
+}
diff --git a/libs/thread/test/test_shared_mutex_part_2.cpp b/libs/thread/test/test_shared_mutex_part_2.cpp
new file mode 100644
index 0000000000..eb9c05ee21
--- /dev/null
+++ b/libs/thread/test/test_shared_mutex_part_2.cpp
@@ -0,0 +1,299 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include "util.inl"
+#include "shared_mutex_locking_thread.hpp"
+
+#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
+ { \
+ boost::mutex::scoped_lock lock(mutex_name); \
+ BOOST_CHECK_EQUAL(value,expected_value); \
+ }
+
+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;
+
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+ for(unsigned i=0;i<number_of_threads;++i)
+ {
+ pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+
+ boost::thread::sleep(delay(1));
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
+}
+
+void test_can_lock_upgrade_if_currently_locked_shared()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ unsigned const reader_count=10;
+
+ try
+ {
+ for(unsigned i=0;i<reader_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+ boost::thread::sleep(delay(1));
+ pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<(reader_count+1))
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
+
+ finish_lock.unlock();
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
+ 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()
+{
+
+ 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_shared();
+ BOOST_CHECK(!try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ 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;
+ bool const try_succeeded=rw_mutex.try_lock_shared();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+}
+
+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()
+{
+
+ 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_shared();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_upgrade();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_upgrade();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_upgrade();
+ BOOST_CHECK(!try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_upgrade();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
+ test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
+ test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_to_unique_if_currently_locked_upgrade));
+ test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
+ test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
+ test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
+
+ return test;
+}
diff --git a/libs/thread/test/test_shared_mutex_timed_locks.cpp b/libs/thread/test/test_shared_mutex_timed_locks.cpp
new file mode 100644
index 0000000000..2e39cc062a
--- /dev/null
+++ b/libs/thread/test/test_shared_mutex_timed_locks.cpp
@@ -0,0 +1,268 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include "util.inl"
+#include "shared_mutex_locking_thread.hpp"
+
+#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
+ { \
+ boost::mutex::scoped_lock lock(mutex_name); \
+ BOOST_CHECK_EQUAL(value,expected_value); \
+ }
+
+
+void test_timed_lock_shared_times_out_if_write_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
+ BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_timed_lock_shared_succeeds_if_no_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
+ BOOST_CHECK(boost::get_system_time()<timeout);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK(boost::get_system_time()<timeout2);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+}
+
+void test_timed_lock_shared_succeeds_if_read_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
+ BOOST_CHECK(boost::get_system_time()<timeout);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK(boost::get_system_time()<timeout2);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ reader.join();
+}
+
+void test_timed_lock_times_out_if_write_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
+ BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_timed_lock_succeeds_if_no_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK(boost::get_system_time()<timeout);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
+ BOOST_CHECK(boost::get_system_time()<timeout2);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+}
+
+void test_timed_lock_times_out_if_read_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
+ BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ finish_lock.unlock();
+ reader.join();
+}
+
+void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ reader.join();
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held));
+
+ return test;
+}
diff --git a/libs/thread/test/test_thread.cpp b/libs/thread/test/test_thread.cpp
new file mode 100644
index 0000000000..fe6ffa36fa
--- /dev/null
+++ b/libs/thread/test/test_thread.cpp
@@ -0,0 +1,234 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
+#include <libs/thread/test/util.inl>
+
+int test_value;
+
+void simple_thread()
+{
+ test_value = 999;
+}
+
+void comparison_thread(boost::thread::id parent)
+{
+ boost::thread::id const my_id=boost::this_thread::get_id();
+
+ BOOST_CHECK(my_id != parent);
+ boost::thread::id const my_id2=boost::this_thread::get_id();
+ BOOST_CHECK(my_id == my_id2);
+
+ boost::thread::id const no_thread_id=boost::thread::id();
+ BOOST_CHECK(my_id != no_thread_id);
+}
+
+void test_sleep()
+{
+ boost::xtime xt = delay(3);
+ boost::thread::sleep(xt);
+
+ // Ensure it's in a range instead of checking actual equality due to time
+ // lapse
+ BOOST_CHECK(in_range(xt, 2));
+}
+
+void do_test_creation()
+{
+ test_value = 0;
+ boost::thread thrd(&simple_thread);
+ thrd.join();
+ BOOST_CHECK_EQUAL(test_value, 999);
+}
+
+void test_creation()
+{
+ timed_test(&do_test_creation, 1);
+}
+
+void do_test_id_comparison()
+{
+ boost::thread::id const self=boost::this_thread::get_id();
+ boost::thread thrd(boost::bind(&comparison_thread, self));
+ thrd.join();
+}
+
+void test_id_comparison()
+{
+ timed_test(&do_test_id_comparison, 1);
+}
+
+void interruption_point_thread(boost::mutex* m,bool* failed)
+{
+ boost::mutex::scoped_lock lk(*m);
+ boost::this_thread::interruption_point();
+ *failed=true;
+}
+
+void do_test_thread_interrupts_at_interruption_point()
+{
+ boost::mutex m;
+ bool failed=false;
+ boost::mutex::scoped_lock lk(m);
+ boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed));
+ thrd.interrupt();
+ lk.unlock();
+ thrd.join();
+ BOOST_CHECK(!failed);
+}
+
+void test_thread_interrupts_at_interruption_point()
+{
+ timed_test(&do_test_thread_interrupts_at_interruption_point, 1);
+}
+
+void disabled_interruption_point_thread(boost::mutex* m,bool* failed)
+{
+ boost::mutex::scoped_lock lk(*m);
+ boost::this_thread::disable_interruption dc;
+ boost::this_thread::interruption_point();
+ *failed=false;
+}
+
+void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
+{
+ boost::mutex m;
+ bool failed=true;
+ boost::mutex::scoped_lock lk(m);
+ boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed));
+ thrd.interrupt();
+ lk.unlock();
+ thrd.join();
+ BOOST_CHECK(!failed);
+}
+
+void test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
+{
+ timed_test(&do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, 1);
+}
+
+struct non_copyable_functor:
+ boost::noncopyable
+{
+ unsigned value;
+
+ non_copyable_functor():
+ value(0)
+ {}
+
+ void operator()()
+ {
+ value=999;
+ }
+};
+
+void do_test_creation_through_reference_wrapper()
+{
+ non_copyable_functor f;
+
+ boost::thread thrd(boost::ref(f));
+ thrd.join();
+ BOOST_CHECK_EQUAL(f.value, 999u);
+}
+
+void test_creation_through_reference_wrapper()
+{
+ timed_test(&do_test_creation_through_reference_wrapper, 1);
+}
+
+struct long_running_thread
+{
+ boost::condition_variable cond;
+ boost::mutex mut;
+ bool done;
+
+ long_running_thread():
+ done(false)
+ {}
+
+ void operator()()
+ {
+ boost::mutex::scoped_lock lk(mut);
+ while(!done)
+ {
+ cond.wait(lk);
+ }
+ }
+};
+
+void do_test_timed_join()
+{
+ long_running_thread f;
+ boost::thread thrd(boost::ref(f));
+ BOOST_CHECK(thrd.joinable());
+ boost::system_time xt=delay(3);
+ bool const joined=thrd.timed_join(xt);
+ BOOST_CHECK(in_range(boost::get_xtime(xt), 2));
+ BOOST_CHECK(!joined);
+ BOOST_CHECK(thrd.joinable());
+ {
+ boost::mutex::scoped_lock lk(f.mut);
+ f.done=true;
+ f.cond.notify_one();
+ }
+
+ xt=delay(3);
+ bool const joined2=thrd.timed_join(xt);
+ boost::system_time const now=boost::get_system_time();
+ BOOST_CHECK(xt>now);
+ BOOST_CHECK(joined2);
+ BOOST_CHECK(!thrd.joinable());
+}
+
+void test_timed_join()
+{
+ timed_test(&do_test_timed_join, 10);
+}
+
+void test_swap()
+{
+ boost::thread t(simple_thread);
+ boost::thread t2(simple_thread);
+ boost::thread::id id1=t.get_id();
+ boost::thread::id id2=t2.get_id();
+
+ t.swap(t2);
+ BOOST_CHECK(t.get_id()==id2);
+ BOOST_CHECK(t2.get_id()==id1);
+
+ swap(t,t2);
+ BOOST_CHECK(t.get_id()==id1);
+ BOOST_CHECK(t2.get_id()==id2);
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread test suite");
+
+ test->add(BOOST_TEST_CASE(test_sleep));
+ test->add(BOOST_TEST_CASE(test_creation));
+ test->add(BOOST_TEST_CASE(test_id_comparison));
+ test->add(BOOST_TEST_CASE(test_thread_interrupts_at_interruption_point));
+ test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point));
+ test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper));
+ test->add(BOOST_TEST_CASE(test_timed_join));
+ test->add(BOOST_TEST_CASE(test_swap));
+
+ return test;
+}
diff --git a/libs/thread/test/test_thread_exit.cpp b/libs/thread/test/test_thread_exit.cpp
new file mode 100644
index 0000000000..a706cb3306
--- /dev/null
+++ b/libs/thread/test/test_thread_exit.cpp
@@ -0,0 +1,73 @@
+// (C) Copyright 2009 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "boost/thread/thread.hpp"
+#include "boost/thread/mutex.hpp"
+#include "boost/thread/condition.hpp"
+#include "boost/thread/future.hpp"
+#include <utility>
+#include <memory>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+
+boost::thread::id exit_func_thread_id;
+
+void exit_func()
+{
+ exit_func_thread_id=boost::this_thread::get_id();
+}
+
+void tf1()
+{
+ boost::this_thread::at_thread_exit(exit_func);
+ BOOST_CHECK(exit_func_thread_id!=boost::this_thread::get_id());
+}
+
+void test_thread_exit_func_runs_when_thread_exits()
+{
+ exit_func_thread_id=boost::thread::id();
+ boost::thread t(tf1);
+ boost::thread::id const t_id=t.get_id();
+ t.join();
+ BOOST_CHECK(exit_func_thread_id==t_id);
+}
+
+struct fo
+{
+ void operator()()
+ {
+ exit_func_thread_id=boost::this_thread::get_id();
+ }
+};
+
+void tf2()
+{
+ boost::this_thread::at_thread_exit(fo());
+ BOOST_CHECK(exit_func_thread_id!=boost::this_thread::get_id());
+}
+
+
+void test_can_use_function_object_for_exit_func()
+{
+ exit_func_thread_id=boost::thread::id();
+ boost::thread t(tf2);
+ boost::thread::id const t_id=t.get_id();
+ t.join();
+ BOOST_CHECK(exit_func_thread_id==t_id);
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: futures test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_exit_func_runs_when_thread_exits));
+ test->add(BOOST_TEST_CASE(test_can_use_function_object_for_exit_func));
+
+ return test;
+}
diff --git a/libs/thread/test/test_thread_id.cpp b/libs/thread/test/test_thread_id.cpp
new file mode 100644
index 0000000000..a20805d8c4
--- /dev/null
+++ b/libs/thread/test/test_thread_id.cpp
@@ -0,0 +1,149 @@
+// 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>
+#include <boost/bind.hpp>
+
+void do_nothing()
+{}
+
+void test_thread_id_for_default_constructed_thread_is_default_constructed_id()
+{
+ boost::thread t;
+ BOOST_CHECK(t.get_id()==boost::thread::id());
+}
+
+void test_thread_id_for_running_thread_is_not_default_constructed_id()
+{
+ boost::thread t(do_nothing);
+ BOOST_CHECK(t.get_id()!=boost::thread::id());
+ t.join();
+}
+
+void test_different_threads_have_different_ids()
+{
+ boost::thread t(do_nothing);
+ boost::thread t2(do_nothing);
+ BOOST_CHECK(t.get_id()!=t2.get_id());
+ t.join();
+ t2.join();
+}
+
+void test_thread_ids_have_a_total_order()
+{
+ boost::thread t(do_nothing);
+ boost::thread t2(do_nothing);
+ boost::thread t3(do_nothing);
+ BOOST_CHECK(t.get_id()!=t2.get_id());
+ BOOST_CHECK(t.get_id()!=t3.get_id());
+ BOOST_CHECK(t2.get_id()!=t3.get_id());
+
+ BOOST_CHECK((t.get_id()<t2.get_id()) != (t2.get_id()<t.get_id()));
+ BOOST_CHECK((t.get_id()<t3.get_id()) != (t3.get_id()<t.get_id()));
+ BOOST_CHECK((t2.get_id()<t3.get_id()) != (t3.get_id()<t2.get_id()));
+
+ BOOST_CHECK((t.get_id()>t2.get_id()) != (t2.get_id()>t.get_id()));
+ BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id()));
+ BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id()));
+
+ BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>t.get_id()));
+ BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>t2.get_id()));
+ BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>t.get_id()));
+ BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>t3.get_id()));
+ BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>t2.get_id()));
+ BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>t3.get_id()));
+
+ BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>=t.get_id()));
+ BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>=t2.get_id()));
+ BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>=t.get_id()));
+ BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>=t3.get_id()));
+ BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>=t2.get_id()));
+ BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>=t3.get_id()));
+
+ BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id()));
+ BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id()));
+ BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id()));
+ BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id()));
+ BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id()));
+ BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id()));
+
+ if((t.get_id()<t2.get_id()) && (t2.get_id()<t3.get_id()))
+ {
+ BOOST_CHECK(t.get_id()<t3.get_id());
+ }
+ else if((t.get_id()<t3.get_id()) && (t3.get_id()<t2.get_id()))
+ {
+ BOOST_CHECK(t.get_id()<t2.get_id());
+ }
+ else if((t2.get_id()<t3.get_id()) && (t3.get_id()<t.get_id()))
+ {
+ BOOST_CHECK(t2.get_id()<t.get_id());
+ }
+ else if((t2.get_id()<t.get_id()) && (t.get_id()<t3.get_id()))
+ {
+ BOOST_CHECK(t2.get_id()<t3.get_id());
+ }
+ else if((t3.get_id()<t.get_id()) && (t.get_id()<t2.get_id()))
+ {
+ BOOST_CHECK(t3.get_id()<t2.get_id());
+ }
+ else if((t3.get_id()<t2.get_id()) && (t2.get_id()<t.get_id()))
+ {
+ BOOST_CHECK(t3.get_id()<t.get_id());
+ }
+ else
+ {
+ BOOST_CHECK(false);
+ }
+
+ boost::thread::id default_id;
+
+ BOOST_CHECK(default_id < t.get_id());
+ BOOST_CHECK(default_id < t2.get_id());
+ BOOST_CHECK(default_id < t3.get_id());
+
+ BOOST_CHECK(default_id <= t.get_id());
+ BOOST_CHECK(default_id <= t2.get_id());
+ BOOST_CHECK(default_id <= t3.get_id());
+
+ BOOST_CHECK(!(default_id > t.get_id()));
+ BOOST_CHECK(!(default_id > t2.get_id()));
+ BOOST_CHECK(!(default_id > t3.get_id()));
+
+ BOOST_CHECK(!(default_id >= t.get_id()));
+ BOOST_CHECK(!(default_id >= t2.get_id()));
+ BOOST_CHECK(!(default_id >= t3.get_id()));
+
+ t.join();
+ t2.join();
+ t3.join();
+}
+
+void get_thread_id(boost::thread::id* id)
+{
+ *id=boost::this_thread::get_id();
+}
+
+void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
+{
+ boost::thread::id id;
+ boost::thread t(boost::bind(get_thread_id,&id));
+ boost::thread::id t_id=t.get_id();
+ t.join();
+ BOOST_CHECK(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: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));
+ test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id));
+ test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids));
+ test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order));
+ test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id));
+ return test;
+}
diff --git a/libs/thread/test/test_thread_launching.cpp b/libs/thread/test/test_thread_launching.cpp
new file mode 100644
index 0000000000..714f33bf6a
--- /dev/null
+++ b/libs/thread/test/test_thread_launching.cpp
@@ -0,0 +1,226 @@
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/ref.hpp>
+#include <boost/utility.hpp>
+#include <string>
+#include <vector>
+
+bool normal_function_called=false;
+
+void normal_function()
+{
+ normal_function_called=true;
+}
+
+void test_thread_function_no_arguments()
+{
+ boost::thread function(normal_function);
+ function.join();
+ BOOST_CHECK(normal_function_called);
+}
+
+int nfoa_res=0;
+
+void normal_function_one_arg(int i)
+{
+ nfoa_res=i;
+}
+
+void test_thread_function_one_argument()
+{
+ boost::thread function(normal_function_one_arg,42);
+ function.join();
+ BOOST_CHECK_EQUAL(42,nfoa_res);
+}
+
+struct callable_no_args
+{
+ static bool called;
+
+ void operator()() const
+ {
+ called=true;
+ }
+};
+
+bool callable_no_args::called=false;
+
+void test_thread_callable_object_no_arguments()
+{
+ callable_no_args func;
+ boost::thread callable(func);
+ callable.join();
+ BOOST_CHECK(callable_no_args::called);
+}
+
+struct callable_noncopyable_no_args:
+ boost::noncopyable
+{
+ static bool called;
+
+ void operator()() const
+ {
+ called=true;
+ }
+};
+
+bool callable_noncopyable_no_args::called=false;
+
+void test_thread_callable_object_ref_no_arguments()
+{
+ callable_noncopyable_no_args func;
+
+ boost::thread callable(boost::ref(func));
+ callable.join();
+ BOOST_CHECK(callable_noncopyable_no_args::called);
+}
+
+struct callable_one_arg
+{
+ static bool called;
+ static int called_arg;
+
+ void operator()(int arg) const
+ {
+ called=true;
+ called_arg=arg;
+ }
+};
+
+bool callable_one_arg::called=false;
+int callable_one_arg::called_arg=0;
+
+void test_thread_callable_object_one_argument()
+{
+ callable_one_arg func;
+ boost::thread callable(func,42);
+ callable.join();
+ BOOST_CHECK(callable_one_arg::called);
+ BOOST_CHECK_EQUAL(callable_one_arg::called_arg,42);
+}
+
+struct callable_multiple_arg
+{
+ static bool called_two;
+ static int called_two_arg1;
+ static double called_two_arg2;
+ static bool called_three;
+ static std::string called_three_arg1;
+ static std::vector<int> called_three_arg2;
+ static int called_three_arg3;
+
+ void operator()(int arg1,double arg2) const
+ {
+ called_two=true;
+ called_two_arg1=arg1;
+ called_two_arg2=arg2;
+ }
+ void operator()(std::string const& arg1,std::vector<int> const& arg2,int arg3) const
+ {
+ called_three=true;
+ called_three_arg1=arg1;
+ called_three_arg2=arg2;
+ called_three_arg3=arg3;
+ }
+};
+
+bool callable_multiple_arg::called_two=false;
+bool callable_multiple_arg::called_three=false;
+int callable_multiple_arg::called_two_arg1;
+double callable_multiple_arg::called_two_arg2;
+std::string callable_multiple_arg::called_three_arg1;
+std::vector<int> callable_multiple_arg::called_three_arg2;
+int callable_multiple_arg::called_three_arg3;
+
+void test_thread_callable_object_multiple_arguments()
+{
+ std::vector<int> x;
+ for(unsigned i=0;i<7;++i)
+ {
+ x.push_back(i*i);
+ }
+
+ callable_multiple_arg func;
+
+ boost::thread callable3(func,"hello",x,1.2);
+ callable3.join();
+ BOOST_CHECK(callable_multiple_arg::called_three);
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg1,"hello");
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.size(),x.size());
+ for(unsigned j=0;j<x.size();++j)
+ {
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.at(j),x[j]);
+ }
+
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg3,1);
+
+ double const dbl=1.234;
+
+ boost::thread callable2(func,19,dbl);
+ callable2.join();
+ BOOST_CHECK(callable_multiple_arg::called_two);
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg1,19);
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg2,dbl);
+}
+
+struct X
+{
+ bool function_called;
+ int arg_value;
+
+ X():
+ function_called(false),
+ arg_value(0)
+ {}
+
+
+ void f0()
+ {
+ function_called=true;
+ }
+
+ void f1(int i)
+ {
+ arg_value=i;
+ }
+
+};
+
+void test_thread_member_function_no_arguments()
+{
+ X x;
+
+ boost::thread function(&X::f0,&x);
+ function.join();
+ BOOST_CHECK(x.function_called);
+}
+
+
+void test_thread_member_function_one_argument()
+{
+ X x;
+ boost::thread function(&X::f1,&x,42);
+ function.join();
+ BOOST_CHECK_EQUAL(42,x.arg_value);
+}
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread launching test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_function_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_function_one_argument));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_ref_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_one_argument));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_multiple_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_member_function_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_member_function_one_argument));
+ return test;
+}
diff --git a/libs/thread/test/test_thread_mf.cpp b/libs/thread/test/test_thread_mf.cpp
new file mode 100644
index 0000000000..aa5a5dc1e3
--- /dev/null
+++ b/libs/thread/test/test_thread_mf.cpp
@@ -0,0 +1,134 @@
+//
+// Copyright (C) 2008 Peter Dimov
+//
+// Distributed under the Boost Software License, Version 1.0.
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include <boost/thread/thread.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+struct X
+{
+ mutable unsigned int hash;
+
+ X(): hash(0) {}
+
+ int f0() { f1(17); return 0; }
+ int g0() const { g1(17); return 0; }
+
+ int f1(int a1) { hash = (hash * 17041 + a1) % 32768; return 0; }
+ int g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; return 0; }
+
+ int f2(int a1, int a2) { f1(a1); f1(a2); return 0; }
+ int g2(int a1, int a2) const { g1(a1); g1(a2); return 0; }
+
+ int f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); return 0; }
+ int g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); return 0; }
+
+ int f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); return 0; }
+ int g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); return 0; }
+
+ int f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); return 0; }
+ int g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); return 0; }
+
+ int f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); return 0; }
+ int g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); return 0; }
+
+ int f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); return 0; }
+ int g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); return 0; }
+
+ int f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); return 0; }
+ int g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); return 0; }
+};
+
+int main()
+{
+ X x;
+
+ // 0
+
+ boost::thread( &X::f0, &x ).join();
+ boost::thread( &X::f0, boost::ref(x) ).join();
+
+ boost::thread( &X::g0, &x ).join();
+ boost::thread( &X::g0, x ).join();
+ boost::thread( &X::g0, boost::ref(x) ).join();
+
+ // 1
+
+ boost::thread( &X::f1, &x, 1 ).join();
+ boost::thread( &X::f1, boost::ref(x), 1 ).join();
+
+ boost::thread( &X::g1, &x, 1 ).join();
+ boost::thread( &X::g1, x, 1 ).join();
+ boost::thread( &X::g1, boost::ref(x), 1 ).join();
+
+ // 2
+
+ boost::thread( &X::f2, &x, 1, 2 ).join();
+ boost::thread( &X::f2, boost::ref(x), 1, 2 ).join();
+
+ boost::thread( &X::g2, &x, 1, 2 ).join();
+ boost::thread( &X::g2, x, 1, 2 ).join();
+ boost::thread( &X::g2, boost::ref(x), 1, 2 ).join();
+
+ // 3
+
+ boost::thread( &X::f3, &x, 1, 2, 3 ).join();
+ boost::thread( &X::f3, boost::ref(x), 1, 2, 3 ).join();
+
+ boost::thread( &X::g3, &x, 1, 2, 3 ).join();
+ boost::thread( &X::g3, x, 1, 2, 3 ).join();
+ boost::thread( &X::g3, boost::ref(x), 1, 2, 3 ).join();
+
+ // 4
+
+ boost::thread( &X::f4, &x, 1, 2, 3, 4 ).join();
+ boost::thread( &X::f4, boost::ref(x), 1, 2, 3, 4 ).join();
+
+ boost::thread( &X::g4, &x, 1, 2, 3, 4 ).join();
+ boost::thread( &X::g4, x, 1, 2, 3, 4 ).join();
+ boost::thread( &X::g4, boost::ref(x), 1, 2, 3, 4 ).join();
+
+ // 5
+
+ boost::thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
+ boost::thread( &X::f5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
+
+ boost::thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join();
+ boost::thread( &X::g5, x, 1, 2, 3, 4, 5 ).join();
+ boost::thread( &X::g5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
+
+ // 6
+
+ boost::thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join();
+ boost::thread( &X::f6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
+
+ boost::thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join();
+ boost::thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join();
+ boost::thread( &X::g6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
+
+ // 7
+
+ boost::thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join();
+ boost::thread( &X::f7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
+
+ boost::thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join();
+ boost::thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join();
+ boost::thread( &X::g7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
+
+ // 8
+
+ boost::thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+ boost::thread( &X::f8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+
+ boost::thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+ boost::thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+ boost::thread( &X::g8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+
+ BOOST_TEST( x.hash == 23558 );
+
+ return boost::report_errors();
+}
diff --git a/libs/thread/test/test_thread_move.cpp b/libs/thread/test/test_thread_move.cpp
new file mode 100644
index 0000000000..f644e1ebd8
--- /dev/null
+++ b/libs/thread/test/test_thread_move.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2007-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)
+#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 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();
+ x.join();
+ BOOST_CHECK_EQUAL(the_id,x_id);
+}
+
+boost::thread make_thread(boost::thread::id* the_id)
+{
+ return boost::thread(do_nothing,the_id);
+}
+
+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();
+ 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::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;
+}
diff --git a/libs/thread/test/test_thread_move_return.cpp b/libs/thread/test/test_thread_move_return.cpp
new file mode 100644
index 0000000000..51f0b3faee
--- /dev/null
+++ b/libs/thread/test/test_thread_move_return.cpp
@@ -0,0 +1,35 @@
+// 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;
+}
diff --git a/libs/thread/test/test_thread_return_local.cpp b/libs/thread/test/test_thread_return_local.cpp
new file mode 100644
index 0000000000..be2aec5137
--- /dev/null
+++ b/libs/thread/test/test_thread_return_local.cpp
@@ -0,0 +1,35 @@
+// 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;
+}
diff --git a/libs/thread/test/test_tss.cpp b/libs/thread/test/test_tss.cpp
new file mode 100644
index 0000000000..894875fe6c
--- /dev/null
+++ b/libs/thread/test/test_tss.cpp
@@ -0,0 +1,359 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/tss.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+
+#include <iostream>
+
+#if defined(BOOST_HAS_WINTHREADS)
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#endif
+
+boost::mutex check_mutex;
+boost::mutex tss_mutex;
+int tss_instances = 0;
+int tss_total = 0;
+
+struct tss_value_t
+{
+ tss_value_t()
+ {
+ boost::mutex::scoped_lock lock(tss_mutex);
+ ++tss_instances;
+ ++tss_total;
+ value = 0;
+ }
+ ~tss_value_t()
+ {
+ boost::mutex::scoped_lock lock(tss_mutex);
+ --tss_instances;
+ }
+ int value;
+};
+
+boost::thread_specific_ptr<tss_value_t> tss_value;
+
+void test_tss_thread()
+{
+ tss_value.reset(new tss_value_t());
+ for (int i=0; i<1000; ++i)
+ {
+ int& n = tss_value->value;
+ // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to
+ // be thread safe. Must evaluate further.
+ if (n != i)
+ {
+ boost::mutex::scoped_lock lock(check_mutex);
+ BOOST_CHECK_EQUAL(n, i);
+ }
+ ++n;
+ }
+}
+
+#if defined(BOOST_THREAD_PLATFORM_WIN32)
+ typedef HANDLE native_thread_t;
+
+ DWORD WINAPI test_tss_thread_native(LPVOID /*lpParameter*/)
+ {
+ test_tss_thread();
+ return 0;
+ }
+
+ native_thread_t create_native_thread(void)
+ {
+ native_thread_t const res=CreateThread(
+ 0, //security attributes (0 = not inheritable)
+ 0, //stack size (0 = default)
+ &test_tss_thread_native, //function to execute
+ 0, //parameter to pass to function
+ 0, //creation flags (0 = run immediately)
+ 0 //thread id (0 = thread id not returned)
+ );
+ BOOST_CHECK(res!=0);
+ return res;
+ }
+
+ void join_native_thread(native_thread_t thread)
+ {
+ DWORD res = WaitForSingleObject(thread, INFINITE);
+ BOOST_CHECK(res == WAIT_OBJECT_0);
+
+ res = CloseHandle(thread);
+ BOOST_CHECK(SUCCEEDED(res));
+ }
+#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
+ typedef pthread_t native_thread_t;
+
+extern "C"
+{
+ void* test_tss_thread_native(void* lpParameter)
+ {
+ test_tss_thread();
+ return 0;
+ }
+}
+
+ native_thread_t create_native_thread()
+ {
+ native_thread_t thread_handle;
+
+ int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0);
+ BOOST_CHECK(!res);
+ return thread_handle;
+ }
+
+ void join_native_thread(native_thread_t thread)
+ {
+ void* result=0;
+ int const res=pthread_join(thread,&result);
+ BOOST_CHECK(!res);
+ }
+#endif
+
+void do_test_tss()
+{
+ tss_instances = 0;
+ tss_total = 0;
+
+ const int NUMTHREADS=5;
+ boost::thread_group threads;
+ try
+ {
+ for (int i=0; i<NUMTHREADS; ++i)
+ threads.create_thread(&test_tss_thread);
+ threads.join_all();
+ }
+ catch(...)
+ {
+ threads.interrupt_all();
+ threads.join_all();
+ throw;
+ }
+
+
+ std::cout
+ << "tss_instances = " << tss_instances
+ << "; tss_total = " << tss_total
+ << "\n";
+ std::cout.flush();
+
+ BOOST_CHECK_EQUAL(tss_instances, 0);
+ BOOST_CHECK_EQUAL(tss_total, 5);
+
+ tss_instances = 0;
+ tss_total = 0;
+
+ native_thread_t thread1 = create_native_thread();
+ native_thread_t thread2 = create_native_thread();
+ native_thread_t thread3 = create_native_thread();
+ native_thread_t thread4 = create_native_thread();
+ native_thread_t thread5 = create_native_thread();
+
+ join_native_thread(thread5);
+ join_native_thread(thread4);
+ join_native_thread(thread3);
+ join_native_thread(thread2);
+ join_native_thread(thread1);
+
+ std::cout
+ << "tss_instances = " << tss_instances
+ << "; tss_total = " << tss_total
+ << "\n";
+ std::cout.flush();
+
+ // The following is not really an error. TSS cleanup support still is available for boost threads.
+ // Also this usually will be triggered only when bound to the static version of thread lib.
+ // 2006-10-02 Roland Schwarz
+ //BOOST_CHECK_EQUAL(tss_instances, 0);
+ BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
+ BOOST_CHECK_EQUAL(tss_total, 5);
+}
+
+void test_tss()
+{
+ timed_test(&do_test_tss, 2);
+}
+
+bool tss_cleanup_called=false;
+
+struct Dummy
+{};
+
+void tss_custom_cleanup(Dummy* d)
+{
+ delete d;
+ tss_cleanup_called=true;
+}
+
+boost::thread_specific_ptr<Dummy> tss_with_cleanup(tss_custom_cleanup);
+
+void tss_thread_with_custom_cleanup()
+{
+ tss_with_cleanup.reset(new Dummy);
+}
+
+void do_test_tss_with_custom_cleanup()
+{
+ boost::thread t(tss_thread_with_custom_cleanup);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(tss_cleanup_called);
+}
+
+
+void test_tss_with_custom_cleanup()
+{
+ timed_test(&do_test_tss_with_custom_cleanup, 2);
+}
+
+Dummy* tss_object=new Dummy;
+
+void tss_thread_with_custom_cleanup_and_release()
+{
+ tss_with_cleanup.reset(tss_object);
+ tss_with_cleanup.release();
+}
+
+void do_test_tss_does_no_cleanup_after_release()
+{
+ tss_cleanup_called=false;
+ boost::thread t(tss_thread_with_custom_cleanup_and_release);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(!tss_cleanup_called);
+ if(!tss_cleanup_called)
+ {
+ delete tss_object;
+ }
+}
+
+struct dummy_class_tracks_deletions
+{
+ static unsigned deletions;
+
+ ~dummy_class_tracks_deletions()
+ {
+ ++deletions;
+ }
+
+};
+
+unsigned dummy_class_tracks_deletions::deletions=0;
+
+boost::thread_specific_ptr<dummy_class_tracks_deletions> tss_with_null_cleanup(NULL);
+
+void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker)
+{
+ tss_with_null_cleanup.reset(delete_tracker);
+}
+
+void do_test_tss_does_no_cleanup_with_null_cleanup_function()
+{
+ dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions;
+ boost::thread t(tss_thread_with_null_cleanup,delete_tracker);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(!dummy_class_tracks_deletions::deletions);
+ if(!dummy_class_tracks_deletions::deletions)
+ {
+ delete delete_tracker;
+ }
+}
+
+void test_tss_does_no_cleanup_after_release()
+{
+ timed_test(&do_test_tss_does_no_cleanup_after_release, 2);
+}
+
+void test_tss_does_no_cleanup_with_null_cleanup_function()
+{
+ timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
+}
+
+void thread_with_local_tss_ptr()
+{
+ {
+ 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_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;
+}
diff --git a/libs/thread/test/test_xtime.cpp b/libs/thread/test/test_xtime.cpp
new file mode 100644
index 0000000000..0dff620094
--- /dev/null
+++ b/libs/thread/test/test_xtime.cpp
@@ -0,0 +1,109 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/xtime.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+
+void test_xtime_cmp()
+{
+ boost::xtime xt1, xt2, cur;
+ BOOST_CHECK_EQUAL(
+ boost::xtime_get(&cur, boost::TIME_UTC),
+ static_cast<int>(boost::TIME_UTC));
+
+ xt1 = xt2 = cur;
+ xt1.nsec -= 1;
+ xt2.nsec += 1;
+
+ BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
+ BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
+ BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
+
+ xt1 = xt2 = cur;
+ xt1.sec -= 1;
+ xt2.sec += 1;
+
+ BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
+ BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
+ BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
+}
+
+void test_xtime_get()
+{
+ boost::xtime orig, cur, old;
+ BOOST_CHECK_EQUAL(
+ boost::xtime_get(&orig,
+ boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
+ old = orig;
+
+ for (int x=0; x < 100; ++x)
+ {
+ BOOST_CHECK_EQUAL(
+ boost::xtime_get(&cur, boost::TIME_UTC),
+ static_cast<int>(boost::TIME_UTC));
+ BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0);
+ BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0);
+ old = cur;
+ }
+}
+
+void test_xtime_mutex_backwards_compatibility()
+{
+ boost::timed_mutex m;
+ BOOST_CHECK(m.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))));
+ m.unlock();
+ boost::timed_mutex::scoped_timed_lock lk(m,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
+ BOOST_CHECK(lk.owns_lock());
+ if(lk.owns_lock())
+ {
+ lk.unlock();
+ }
+ BOOST_CHECK(lk.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))));
+ if(lk.owns_lock())
+ {
+ lk.unlock();
+ }
+}
+
+bool predicate()
+{
+ return false;
+}
+
+
+void test_xtime_condvar_backwards_compatibility()
+{
+ boost::condition_variable cond;
+ boost::condition_variable_any cond_any;
+ boost::mutex m;
+
+ boost::mutex::scoped_lock lk(m);
+ cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
+ cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate);
+ cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
+ cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate);
+}
+
+
+
+boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
+
+ test->add(BOOST_TEST_CASE(&test_xtime_cmp));
+ test->add(BOOST_TEST_CASE(&test_xtime_get));
+ test->add(BOOST_TEST_CASE(&test_xtime_mutex_backwards_compatibility));
+ test->add(BOOST_TEST_CASE(&test_xtime_condvar_backwards_compatibility));
+
+ return test;
+}
diff --git a/libs/thread/test/util.inl b/libs/thread/test/util.inl
new file mode 100644
index 0000000000..5c761d506d
--- /dev/null
+++ b/libs/thread/test/util.inl
@@ -0,0 +1,183 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// 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)
+
+#if !defined(UTIL_INL_WEK01242003)
+#define UTIL_INL_WEK01242003
+
+#include <boost/thread/xtime.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
+# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
+#endif
+
+// boostinspect:nounnamed
+
+namespace
+{
+inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
+{
+ const int MILLISECONDS_PER_SECOND = 1000;
+ const int NANOSECONDS_PER_SECOND = 1000000000;
+ const int NANOSECONDS_PER_MILLISECOND = 1000000;
+
+ boost::xtime xt;
+ if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
+ BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
+
+ nsecs += xt.nsec;
+ msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
+ secs += msecs / MILLISECONDS_PER_SECOND;
+ nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
+ xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
+ xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
+
+ return xt;
+}
+
+inline bool in_range(const boost::xtime& xt, int secs=1)
+{
+ boost::xtime min = delay(-secs);
+ boost::xtime max = delay(0);
+ return (boost::xtime_cmp(xt, min) >= 0) &&
+ (boost::xtime_cmp(xt, max) <= 0);
+}
+
+class execution_monitor
+{
+public:
+ enum wait_type { use_sleep_only, use_mutex, use_condition };
+
+ execution_monitor(wait_type type, int secs)
+ : done(false), type(type), secs(secs) { }
+ void start()
+ {
+ if (type != use_sleep_only) {
+ boost::mutex::scoped_lock lock(mutex); done = false;
+ } else {
+ done = false;
+ }
+ }
+ void finish()
+ {
+ if (type != use_sleep_only) {
+ boost::mutex::scoped_lock lock(mutex);
+ done = true;
+ if (type == use_condition)
+ cond.notify_one();
+ } else {
+ done = true;
+ }
+ }
+ bool wait()
+ {
+ boost::xtime xt = delay(secs);
+ if (type != use_condition)
+ boost::thread::sleep(xt);
+ if (type != use_sleep_only) {
+ boost::mutex::scoped_lock lock(mutex);
+ while (type == use_condition && !done) {
+ if (!cond.timed_wait(lock, xt))
+ break;
+ }
+ return done;
+ }
+ return done;
+ }
+
+private:
+ boost::mutex mutex;
+ boost::condition cond;
+ bool done;
+ wait_type type;
+ int secs;
+};
+
+template <typename F>
+class indirect_adapter
+{
+public:
+ indirect_adapter(F func, execution_monitor& monitor)
+ : func(func), monitor(monitor) { }
+ void operator()() const
+ {
+ try
+ {
+ boost::thread thrd(func);
+ thrd.join();
+ }
+ catch (...)
+ {
+ monitor.finish();
+ throw;
+ }
+ monitor.finish();
+ }
+
+private:
+ F func;
+ execution_monitor& monitor;
+ void operator=(indirect_adapter&);
+};
+
+template <typename F>
+void timed_test(F func, int secs,
+ execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
+{
+ execution_monitor monitor(type, secs);
+ indirect_adapter<F> ifunc(func, monitor);
+ monitor.start();
+ boost::thread thrd(ifunc);
+ BOOST_REQUIRE_MESSAGE(monitor.wait(),
+ "Timed test didn't complete in time, possible deadlock.");
+}
+
+template <typename F, typename T>
+class thread_binder
+{
+public:
+ thread_binder(const F& func, const T& param)
+ : func(func), param(param) { }
+ void operator()() const { func(param); }
+
+private:
+ F func;
+ T param;
+};
+
+template <typename F, typename T>
+thread_binder<F, T> bind(const F& func, const T& param)
+{
+ return thread_binder<F, T>(func, param);
+}
+
+template <typename R, typename T>
+class thread_member_binder
+{
+public:
+ thread_member_binder(R (T::*func)(), T& param)
+ : func(func), param(param) { }
+ void operator()() const { (param.*func)(); }
+
+private:
+ void operator=(thread_member_binder&);
+
+ R (T::*func)();
+ T& param;
+};
+
+
+template <typename R, typename T>
+thread_member_binder<R, T> bind(R (T::*func)(), T& param)
+{
+ return thread_member_binder<R, T>(func, param);
+}
+} // namespace
+
+#endif
diff --git a/libs/thread/tutorial/bounded_buffer.cpp b/libs/thread/tutorial/bounded_buffer.cpp
new file mode 100644
index 0000000000..276aaebf11
--- /dev/null
+++ b/libs/thread/tutorial/bounded_buffer.cpp
@@ -0,0 +1,69 @@
+// 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/condition.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+#include <vector>
+
+class bounded_buffer : private boost::noncopyable
+{
+public:
+ typedef boost::mutex::scoped_lock lock;
+ bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
+ void send (int m) {
+ lock lk(monitor);
+ while (buffered == circular_buf.size())
+ buffer_not_full.wait(lk);
+ circular_buf[end] = m;
+ end = (end+1) % circular_buf.size();
+ ++buffered;
+ buffer_not_empty.notify_one();
+ }
+ int receive() {
+ lock lk(monitor);
+ while (buffered == 0)
+ buffer_not_empty.wait(lk);
+ int i = circular_buf[begin];
+ begin = (begin+1) % circular_buf.size();
+ --buffered;
+ buffer_not_full.notify_one();
+ return i;
+ }
+private:
+ int begin, end, buffered;
+ std::vector<int> circular_buf;
+ boost::condition buffer_not_full, buffer_not_empty;
+ boost::mutex monitor;
+};
+bounded_buffer buf(2);
+
+void sender() {
+ int n = 0;
+ while (n < 100) {
+ buf.send(n);
+ std::cout << "sent: " << n << std::endl;
+ ++n;
+ }
+ buf.send(-1);
+}
+
+void receiver() {
+ int n;
+ do {
+ n = buf.receive();
+ std::cout << "received: " << n << std::endl;
+ } while (n != -1); // -1 indicates end of buffer
+}
+
+int main()
+{
+ boost::thread thrd1(&sender);
+ boost::thread thrd2(&receiver);
+ thrd1.join();
+ thrd2.join();
+}
diff --git a/libs/thread/tutorial/counter.cpp b/libs/thread/tutorial/counter.cpp
new file mode 100644
index 0000000000..a5ca0b4d63
--- /dev/null
+++ b/libs/thread/tutorial/counter.cpp
@@ -0,0 +1,28 @@
+// 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/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+boost::mutex mutex;
+int counter=0;
+
+void change_count()
+{
+ boost::mutex::scoped_lock lock(mutex);
+ int i = ++counter;
+ std::cout << "count == " << i << std::endl;
+}
+
+int main()
+{
+ const int num_threads = 4;
+ boost::thread_group thrds;
+ for (int i=0; i < num_threads; ++i)
+ thrds.create_thread(&change_count);
+ thrds.join_all();
+}
diff --git a/libs/thread/tutorial/factorial.cpp b/libs/thread/tutorial/factorial.cpp
new file mode 100644
index 0000000000..9dd1001d9d
--- /dev/null
+++ b/libs/thread/tutorial/factorial.cpp
@@ -0,0 +1,32 @@
+// 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/thread.hpp>
+#include <iostream>
+
+class factorial
+{
+public:
+ factorial(int x, int& res) : x(x), res(res) { }
+ void operator()() { res = calculate(x); }
+ int result() const { return res; }
+
+private:
+ int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
+
+private:
+ int x;
+ int& res;
+};
+
+int main()
+{
+ int result;
+ factorial f(10, result);
+ boost::thread thrd(f);
+ thrd.join();
+ std::cout << "10! = " << result << std::endl;
+}
diff --git a/libs/thread/tutorial/factorial2.cpp b/libs/thread/tutorial/factorial2.cpp
new file mode 100644
index 0000000000..c30421bc53
--- /dev/null
+++ b/libs/thread/tutorial/factorial2.cpp
@@ -0,0 +1,32 @@
+// 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/thread.hpp>
+#include <boost/ref.hpp>
+#include <iostream>
+
+class factorial
+{
+public:
+ factorial(int x) : x(x), res(0) { }
+ void operator()() { res = calculate(x); }
+ int result() const { return res; }
+
+private:
+ int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
+
+private:
+ int x;
+ int res;
+};
+
+int main()
+{
+ factorial f(10);
+ boost::thread thrd(boost::ref(f));
+ thrd.join();
+ std::cout << "10! = " << f.result() << std::endl;
+}
diff --git a/libs/thread/tutorial/factorial3.cpp b/libs/thread/tutorial/factorial3.cpp
new file mode 100644
index 0000000000..2515bfeabf
--- /dev/null
+++ b/libs/thread/tutorial/factorial3.cpp
@@ -0,0 +1,36 @@
+// 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/thread.hpp>
+#include <iostream>
+
+const int NUM_CALCS=5;
+
+class factorial
+{
+public:
+ factorial(int x, int& res) : x(x), res(res) { }
+ void operator()() { res = calculate(x); }
+ int result() const { return res; }
+
+private:
+ int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); }
+
+private:
+ int x;
+ int& res;
+};
+
+int main()
+{
+ int results[NUM_CALCS];
+ boost::thread_group thrds;
+ for (int i=0; i < NUM_CALCS; ++i)
+ thrds.create_thread(factorial(i*10, results[i]));
+ thrds.join_all();
+ for (int j=0; j < NUM_CALCS; ++j)
+ std::cout << j*10 << "! = " << results[j] << std::endl;
+}
diff --git a/libs/thread/tutorial/helloworld.cpp b/libs/thread/tutorial/helloworld.cpp
new file mode 100644
index 0000000000..5003108f49
--- /dev/null
+++ b/libs/thread/tutorial/helloworld.cpp
@@ -0,0 +1,19 @@
+// 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/thread.hpp>
+#include <iostream>
+
+void helloworld()
+{
+ std::cout << "Hello World!" << std::endl;
+}
+
+int main()
+{
+ boost::thread thrd(&helloworld);
+ thrd.join();
+}
diff --git a/libs/thread/tutorial/helloworld2.cpp b/libs/thread/tutorial/helloworld2.cpp
new file mode 100644
index 0000000000..dc7a698a81
--- /dev/null
+++ b/libs/thread/tutorial/helloworld2.cpp
@@ -0,0 +1,24 @@
+// 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/thread.hpp>
+#include <iostream>
+
+struct helloworld
+{
+ helloworld(const char* who) : m_who(who) { }
+ void operator()()
+ {
+ std::cout << m_who << "says, \"Hello World.\"" << std::endl;
+ }
+ const char* m_who;
+};
+
+int main()
+{
+ boost::thread thrd(helloworld("Bob"));
+ thrd.join();
+}
diff --git a/libs/thread/tutorial/helloworld3.cpp b/libs/thread/tutorial/helloworld3.cpp
new file mode 100644
index 0000000000..cd43987f58
--- /dev/null
+++ b/libs/thread/tutorial/helloworld3.cpp
@@ -0,0 +1,20 @@
+// 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/thread.hpp>
+#include <boost/bind.hpp>
+#include <iostream>
+
+void helloworld(const char* who)
+{
+ std::cout << who << "says, \"Hello World.\"" << std::endl;
+}
+
+int main()
+{
+ boost::thread thrd(boost::bind(&helloworld, "Bob"));
+ thrd.join();
+}
diff --git a/libs/thread/tutorial/helloworld4.cpp b/libs/thread/tutorial/helloworld4.cpp
new file mode 100644
index 0000000000..cd43987f58
--- /dev/null
+++ b/libs/thread/tutorial/helloworld4.cpp
@@ -0,0 +1,20 @@
+// 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/thread.hpp>
+#include <boost/bind.hpp>
+#include <iostream>
+
+void helloworld(const char* who)
+{
+ std::cout << who << "says, \"Hello World.\"" << std::endl;
+}
+
+int main()
+{
+ boost::thread thrd(boost::bind(&helloworld, "Bob"));
+ thrd.join();
+}
diff --git a/libs/thread/tutorial/once.cpp b/libs/thread/tutorial/once.cpp
new file mode 100644
index 0000000000..5a5b6f5589
--- /dev/null
+++ b/libs/thread/tutorial/once.cpp
@@ -0,0 +1,31 @@
+// 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/thread.hpp>
+#include <boost/thread/once.hpp>
+#include <cassert>
+
+int value=0;
+boost::once_flag once = BOOST_ONCE_INIT;
+
+void init()
+{
+ ++value;
+}
+
+void thread_proc()
+{
+ boost::call_once(&init, once);
+}
+
+int main(int argc, char* argv[])
+{
+ boost::thread_group threads;
+ for (int i=0; i<5; ++i)
+ threads.create_thread(&thread_proc);
+ threads.join_all();
+ assert(value == 1);
+}
diff --git a/libs/thread/tutorial/tss.cpp b/libs/thread/tutorial/tss.cpp
new file mode 100644
index 0000000000..f867a9180a
--- /dev/null
+++ b/libs/thread/tutorial/tss.cpp
@@ -0,0 +1,36 @@
+// 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/thread.hpp>
+#include <boost/thread/tss.hpp>
+#include <cassert>
+
+boost::thread_specific_ptr<int> value;
+
+void increment()
+{
+ int* p = value.get();
+ ++*p;
+}
+
+void thread_proc()
+{
+ value.reset(new int(0)); // initialize the thread's storage
+ for (int i=0; i<10; ++i)
+ {
+ increment();
+ int* p = value.get();
+ assert(*p == i+1);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ boost::thread_group threads;
+ for (int i=0; i<5; ++i)
+ threads.create_thread(&thread_proc);
+ threads.join_all();
+}