mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
1 Commits
boost-1.53
...
boost-1.50
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87a0e26efb |
@@ -40,17 +40,12 @@ import path ;
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: requirements <threading>multi
|
||||
#<link>static:<define>BOOST_THREAD_STATIC_LINK=1
|
||||
#<link>shared:<define>BOOST_THREAD_DYN_LINK=1
|
||||
<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
|
||||
#<define>BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
#<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
<library>/boost/system//boost_system
|
||||
#-pedantic -ansi -std=gnu++0x -Wextra -fpermissive
|
||||
<warnings>all
|
||||
@@ -62,7 +57,7 @@ project boost/thread
|
||||
|
||||
<toolset>darwin:<cxxflags>-Wextra
|
||||
<toolset>darwin:<cxxflags>-pedantic
|
||||
#<toolset>darwin:<cxxflags>-ansi
|
||||
<toolset>darwin:<cxxflags>-ansi
|
||||
<toolset>darwin:<cxxflags>-fpermissive
|
||||
<toolset>darwin:<cxxflags>-Wno-long-long
|
||||
|
||||
@@ -72,7 +67,7 @@ project boost/thread
|
||||
|
||||
<toolset>clang:<cxxflags>-Wextra
|
||||
<toolset>clang:<cxxflags>-pedantic
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
|
||||
@@ -90,32 +85,16 @@ project boost/thread
|
||||
#<toolset>clang-2.8:<cxxflags>-Wno-unused-function
|
||||
#<toolset>clang-2.9:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
#<toolset>clang-2.9:<cxxflags>-Wno-unused-function
|
||||
<toolset>clang-3.0:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
<toolset>clang-3.0:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
#<toolset>clang-3.0:<cxxflags>-Wno-unused-function
|
||||
#<toolset>clang-3.0:<cxxflags>-Wno-unused-variable
|
||||
|
||||
# Note: Some of the remarks from the Intel compiler are disabled
|
||||
# remark #193: zero used for undefined preprocessing identifier "XXX"
|
||||
# remark #304: access control not specified ("public" by default)
|
||||
# remark #593: variable "XXX" was set but never used
|
||||
# remark #1418: external function definition with no prior declaration
|
||||
# remark #2415: variable "XXX" of static storage duration was declared but never referenced
|
||||
|
||||
<toolset>intel:<cxxflags>-wd193,304,383,444
|
||||
<toolset>intel:<cxxflags>-wd593,981
|
||||
<toolset>intel:<cxxflags>-wd1418
|
||||
<toolset>intel:<cxxflags>-wd2415
|
||||
|
||||
|
||||
# : default-build <threading>multi
|
||||
: usage-requirements # pass these requirement to dependents (i.e. users)
|
||||
#<link>static:<define>BOOST_THREAD_STATIC_LINK=1
|
||||
#<link>shared:<define>BOOST_THREAD_DYN_LINK=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
#<define>BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
#<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
<library>/boost/system//boost_system
|
||||
;
|
||||
|
||||
@@ -225,10 +204,10 @@ rule usage-requirements ( properties * )
|
||||
}
|
||||
}
|
||||
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties)
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties)
|
||||
{
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -253,7 +232,10 @@ rule requirements ( properties * )
|
||||
}
|
||||
}
|
||||
}
|
||||
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties)
|
||||
{
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
210
doc/changes.qbk
210
doc/changes.qbk
@@ -8,172 +8,8 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[heading Version 4.0.0 - boost 1.53]
|
||||
|
||||
[/
|
||||
[*Breaking changes:]
|
||||
|
||||
[warning
|
||||
BOOST_THREAD_VERSION==3 by default since Boost 1.53. So that all the deprecated features since 1.50 are not included by default. You can change this by setting the appropriated define (see Configuration section).
|
||||
]
|
||||
]
|
||||
|
||||
[*Deprecated features:]
|
||||
|
||||
[warning Deprecated features since boost 1.53 will be available only until boost 1.58.]
|
||||
|
||||
* C++11 compliance: packaged_task<R> is deprecated, use instead packaged_task<R()>.
|
||||
See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7537 #7537] deprecate Mutex::scoped_lock and scoped_try_lock and boost::condition
|
||||
|
||||
[*New Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6270 #6270] c++11 compliance: Add thread constructor from movable callable and movable arguments
|
||||
Provided when BOOST_THREAD_PROVIDES_VARIADIC_THREAD is defined (Default value from Boost 1.55):
|
||||
See BOOST_THREAD_PROVIDES_VARIADIC_THREAD and BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7279 #7279] C++11 compliance: Add noexcept in system related functions
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7280 #7280] C++11 compliance: Add promise::...at_thread_exit functions
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7281 #7281] C++11 compliance: Add ArgTypes to packaged_task template.
|
||||
Provided when BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined (Default value from Boost 1.55).
|
||||
See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7282 #7282] C++11 compliance: Add packaged_task::make_ready_at_thread_exit function
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7412 #7412] C++11 compliance: Add async from movable callable and movable arguments
|
||||
Provided when BOOST_THREAD_PROVIDES_VARIADIC_THREAD and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK are defined (Default value from Boost 1.55):
|
||||
See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK, BOOST_THREAD_PROVIDES_VARIADIC_THREAD and BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7413 #7413] C++11 compliance: Add async when the launch policy is deferred.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7414 #7414] C++11 compliance: future::get post-condition should be valid()==false.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7422 #7422] Provide a condition variable with zero-overhead performance penality.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7414 #7444] Async: Add make_future/make_shared_future.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7540 #7540] Threads: Add a helper class that join a thread on destruction.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7541 #7541] Threads: Add a thread wrapper class that joins on destruction.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7575 #7575] C++11 compliance: A future created by async should "join" in the destructor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7587 #7587] Synchro: Add strict_lock and nested_strict_lock.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7588 #7588] Synchro: Split the locks.hpp in several files to limit dependencies.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7590 #7590] Synchro: Add lockable concept checkers based on Boost.ConceptCheck.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7591 #7591] Add lockable traits that can be used with enable_if.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7592 #7592] Synchro: Add a null_mutex that is a no-op and that is a model of UpgardeLockable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7593 #7593] Synchro: Add a externally_locked class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7590 #7594] Threads: Allow to disable thread interruptions.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7464 #7464] BOOST_TEST(n_alive == 1); fails due to race condition in a regression test tool.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7657 #7657] Serious performance and memory consumption hit if condition_variable methods condition notify_one or notify_all is used repeatedly.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7665 #7665] this_thread::sleep_for no longer uses steady_clock in thread.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7668 #7668] thread_group::join_all() should check whether its threads are joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7669 #7669] thread_group::join_all() should catch resource_deadlock_would_occur.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7672 #7672] lockable_traits.hpp syntax error: "defined" token misspelled.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7798 #7798] boost::future set_wait_callback thread safety issues.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7808 #7808] Incorrect description of effects for this_thread::sleep_for and this_thread::sleep_until.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7812 #7812] Returns: cv_status::no_timeout if the call is returning because the time period specified by rel_time has elapsed, cv_status::timeout otherwise.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7874 #7874] compile warning: thread.hpp:342: warning: type attributes are honored only at type definition.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7875 #7875] BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED should not be enabled by default.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7882 #7882] wrong exception text from condition_variable::wait(unique_lock<mutex>&).
|
||||
|
||||
|
||||
[heading Version 3.1.0 - boost 1.52]
|
||||
|
||||
Deprecated Features:
|
||||
|
||||
Deprecated features since boost 1.50 available only until boost 1.55:
|
||||
|
||||
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have yet 1 year to move to the new features.
|
||||
|
||||
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
|
||||
|
||||
Breaking changes when BOOST_THREAD_VERSION==3 (Default value since Boost 1.53):
|
||||
|
||||
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 3, but the user can however choose the version 2 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Rename the unique_future to future following the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
|
||||
|
||||
New Features:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2361 #2361] thread_specific_ptr: document nature of the key, complexity and rationale.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] C++11 compliance: Missing async().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7283 #7283] C++11 compliance: Add notify_all_at_thread_exit.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7345 #7345] C++11 compliance: Add noexcept to recursive mutex try_lock.
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2797 #2797] Two problems with thread_specific_ptr.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5274 #5274] failed to compile future.hpp with stlport 5.1.5 under msvc8.1, because of undefined class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5431 #5431] compile error in Windows CE 6.0(interlocked).
|
||||
[/* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms.]
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5696 #5696] win32 detail::set_tss_data does nothing when tss_cleanup_function is NULL.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel C++ Compiler XE 12.1.5.344 Build 20120612
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7045 #7045] Thread library does not automatically compile date_time.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7173 #7173] wrong function name interrupt_point().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7200 #7200] Unable to build boost.thread modularized.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7220 #7220] gcc 4.6.2 warns about inline+dllimport functions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7238 #7238] this_thread::sleep_for() does not respond to interrupt().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7245 #7245] Minor typos on documentation related to version 3.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7272 #7272] win32/thread_primitives.hpp: (Unneccessary) Warning.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7284 #7284] Clarify that there is no access priority between lock and shared_lock on shared mutex.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7329 #7329] boost/thread/future.hpp does not compile on HPUX.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7336 #7336] BOOST_THREAD_DONT_USE_SYSTEM doesn't work.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7329 #7349] packaged_task holds reference to temporary.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7350 #7350] allocator_destructor does not destroy object
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7360 #7360] Memory leak in pthread implementation of boost::thread_specific_ptr
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7370 #7370] Boost.Thread documentation
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7438 #7438] Segmentation fault in test_once regression test in group.join_all();
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7499 #7499] call_once doesn't call even once
|
||||
|
||||
|
||||
[heading Version 3.0.1 - boost 1.51]
|
||||
|
||||
Deprecated Features:
|
||||
|
||||
Deprecated features since boost 1.50 available only until boost 1.55:
|
||||
|
||||
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
|
||||
|
||||
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
|
||||
|
||||
Breaking changes when BOOST_THREAD_VERSION==3:
|
||||
|
||||
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 3, but the user can however choose the version 2 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Rename the unique_future to future following the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
|
||||
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4258 #4258] Linking with boost thread does not work on mingw/gcc 4.5.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4885 #4885] Access violation in set_tss_data at process exit due to invalid assumption about TlsAlloc.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel Compiler and /debug:parallel
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7044 #7044] boost 1.50.0 header missing.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7052 #7052] Thread: BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 only masks thread::operator==, thread::operator!= forward declarations, not definitions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7066 #7066] An attempt to fix current_thread_tls_key static initialization order.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7074 #7074] Multiply defined symbol boost::allocator_arg.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7078 #7078] Trivial 64-bit warning fix on Windows for thread attribute stack size
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7089 #7089] BOOST_THREAD_WAIT_BUG limits functionality without solving anything
|
||||
|
||||
[/
|
||||
#6787 boost::thread::sleep() hangs if system time is rolled back
|
||||
#7045 Thread library does not automatically compile date_time
|
||||
]
|
||||
|
||||
[heading Version 3.0.0 - boost 1.50]
|
||||
|
||||
Breaking changes when BOOST_THREAD_VERSION==3:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Breaking change: Rename the unique_future to future following the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
|
||||
|
||||
New Features:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/1850 #1850] Request for unlock_guard to compliment lock_guard.
|
||||
@@ -184,31 +20,25 @@ New Features:
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6195 #6195] c++11 compliance: Provide the standard time related interface using Boost.Chrono.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6217 #6217] Enhance Boost.Thread shared mutex interface following Howard Hinnant proposal.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6224 #6224] c++11 compliance: Add the use of standard noexcept on compilers supporting them.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6225 #6225] Add the use of standard =delete defaulted operations on compilers supporting them.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6226 #6226] c++11 compliance: Add explicit bool conversion from locks.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6228 #6228] Add promise constructor with allocator following the standard c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6230 #6230] c++11 compliance: Follows the exception reporting mechanism as defined in the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6231 #6231] Add BasicLockable requirements in the documentation to follow c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6272 #6272] c++11 compliance: Add thread::id hash specialization.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6273 #6273] c++11 compliance: Add cv_status enum class and use it on the conditions wait functions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6231 #6231] Add BasicLockable requirements in the documentation to follow c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6342 #6342] c++11 compliance: Adapt the one_flag to the c++11 interface.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6671 #6671] upgrade_lock: missing mutex and release functions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6672 #6672] upgrade_lock:: missing constructors from time related types.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6675 #6675] upgrade_lock:: missing non-member swap.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6676 #6676] lock conversion should be explicit.
|
||||
* Added missing packaged_task::result_type and packaged_task:: constructor with allocator.
|
||||
* Added packaged_task::reset()
|
||||
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2380 #2380] boost::move from lvalue does not work with gcc.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2430 #2430] shared_mutex for win32 doesn't have timed_lock_upgrade.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2575 #2575] Bug- Boost 1.36.0 on Itanium platform.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3160 #3160] Duplicate tutorial code in boost::thread.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4345 #4345] thread::id and joining problem with cascade of threads.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4521 #4521] Error using boost::move on packaged_task (MSVC 10).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4711 #4711] Must use implementation details to return move-only types.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4921 #4921] BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB are crucial and need to be documented.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5013 #5013] documentation: boost::thread: pthreas_exit causes terminate().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5173 #5173] boost::this_thread::get_id is very slow.
|
||||
@@ -217,15 +47,24 @@ Fixed Bugs:
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5990 #5990] shared_future<T>::get() has wrong return type.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6174 #6174] packaged_task doesn't correctly handle moving results.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6222 #6222] Compile error with SunStudio: unique_future move.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6354 #6354] PGI: Compiler threading support is not turned on.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6673 #6673] shared_lock: move assign doesn't works with c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6674 #6674] shared_mutex: try_lock_upgrade_until doesn't works.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6908 #6908] Compile error due to unprotected definitions of _WIN32_WINNT and WINVER.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6940 #6940] TIME_UTC is a macro in C11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6959 #6959] call of abs is ambiguous.
|
||||
* Fix issue signaled on the ML with task_object(task_object const&) in presence of task_object(task_object &&)
|
||||
|
||||
|
||||
[/
|
||||
Deprecated features since boost 1.50 available only until boost 1.55:
|
||||
|
||||
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
|
||||
|
||||
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
|
||||
|
||||
Breaking changes:
|
||||
|
||||
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 2, but the user can however choose the version 1 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
|
||||
|
||||
* #6266 c++11 compliance: thread destructor should call terminate if joinable
|
||||
* #6269 c++11 compliance: thread move assignment should call terminate if joinable
|
||||
]
|
||||
|
||||
[heading Version 2.1.1 - boost 1.49]
|
||||
|
||||
@@ -344,18 +183,11 @@ been moved to __thread_id__.
|
||||
The following features will be included in next releases.
|
||||
|
||||
# Complete the C++11 missing features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7285 #7285] C++11 compliance: Allow to pass movable arguments for call_once.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
|
||||
|
||||
|
||||
# Add some of the extension proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf A Standardized Representation of Asynchronous Operations], in particular
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7449 #7449] Synchro: Add a synchronized value class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7445 #7445] Async: Add future<>.then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] Missing async().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Use of variadic templates on Generic Locking Algorithms on compilers providing them.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6270 #6270] Add thread constructor from movable callable and movable arguments following C++11.
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,106 +1,97 @@
|
||||
[/
|
||||
(C) Copyright 2011-12 Vicente J. Botet Escriba.
|
||||
(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 Conformance and Extension]
|
||||
[section:compliance Compliance with standard]
|
||||
|
||||
[section:cpp11 C++11 standard Thread library]
|
||||
|
||||
|
||||
[table C++11 standard Conformance
|
||||
[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] [Yes] [-] [-]]
|
||||
[[30.2.2] [Exceptions] [No] [-] [#12]]
|
||||
[[30.2.3] [Native handles] [Yes] [-] [-]]
|
||||
[[30.2.4] [Timing specifications] [Yes] [-] [-]]
|
||||
[[30.2.5] [Requirements for Lockable types] [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] [Yes] [-] [-]]
|
||||
[[30.2.5.2] [BasicLockable requirements] [No] [-] [#13]]
|
||||
[[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
|
||||
[[30.2.5.4] [TimedLockable requirements] [Yes] [-] [-]]
|
||||
[[30.2.5.4] [TimedLockable requirements] [Partial] [chrono] [#6195]]
|
||||
[[30.2.6] [decay_copy] [-] [-] [-]]
|
||||
[[30.3] [Threads] [Yes] [-] [-]]
|
||||
[[30.3.1] [Class thread] [Yes] [-] [-]]
|
||||
[[30.3.1.1] [Class thread::id] [Yes] [-] [-]]
|
||||
[[30.3.1.2] [thread constructors] [Partial] [-] [-]]
|
||||
[[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] [Yes] [-] [-]]
|
||||
[[30.3.1.5] [thread members] [Yes] [-] [-]]
|
||||
[[30.3.1.6] [thread static members] [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] [Yes] [-] [-]]
|
||||
[[30.3.2] [Namespace this_thread] [Partial] [chrono] [#6195]]
|
||||
[[30.4] [Mutual exclusion] [Partial] [-] [-]]
|
||||
[[30.4.1] [Mutex requirements] [Yes] [-] [-]]
|
||||
[[30.4.1.1] [In general] [Yes] [-] [-]]
|
||||
[[30.4.1.2] [Mutex types] [Yes] [-] [-]]
|
||||
[[30.4.1.2.1] [Class mutex] [Yes] [-] [-]]
|
||||
[[30.4.1.2.2] [Class recursive_mutex] [Yes] [-] [-]]
|
||||
[[30.4.1.3] [Timed mutex types] [Yes] [-] [-]]
|
||||
[[30.4.1.3.1] [Class timed_mutex] [Yes] [-] [-]]
|
||||
[[30.4.1.3.1] [Class recursive_timed_mutex] [Yes] [-] [-]]
|
||||
[[30.4.2] [Locks] [Yes] [-] [-]]
|
||||
[[30.4.2.1] [Class template lock_guard] [Yes] [-] [-]]
|
||||
[[30.4.2.2] [Class template unique_lock] [Yes] [-] [-]]
|
||||
[[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Yes] [-] [-]]
|
||||
[[30.4.2.2.2] [unique_lock locking] [Yes] [-] [-]]
|
||||
[[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] [Yes] [] [-]]
|
||||
[[30.4.3] [Generic locking algorithms] [Partial] [variadic] [#6227]]
|
||||
[[30.4.4] [Call once] [Partial] [call_once] [#7285]]
|
||||
[[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] [Partial] [interface] [#7285]]
|
||||
[[30.5] [Condition variables] [Yes] [-] [-]]
|
||||
[[30.5.1] [Class condition_variable] [Yes] [-] [-]]
|
||||
[[30.5.2] [Class condition_variable_any] [Yes] [-] [-]]
|
||||
[[30.6] [Futures] [Partial] [noexcept] [#7279]]
|
||||
[[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] [Yes] [-] [-]]
|
||||
[[30.6.3] [Class future_error] [Partial] [noexcept] [#7279]]
|
||||
[[30.6.4] [Shared state] [-] [-] [-]]
|
||||
[[30.6.5] [Class template promise] [Yes] [-] [-]]
|
||||
[[30.6.6] [Class template future] [Yes] [-] [-]]
|
||||
[[30.6.7] [Class template shared_future] [Yes] [-] [-]]
|
||||
[[30.6.8] [Function template async] [Yes] [-] [-]]
|
||||
[[30.6.9] [Class template packaged_task] [Yes] [-] [-]]
|
||||
[[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.2.x] [Interruption] [-]]
|
||||
[[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]
|
||||
|
||||
[section:shared Shared Locking extensions]
|
||||
|
||||
[table Howard's Shared Locking Proposal Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X] [Shared Locking] [Yes] [Needs `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION]]
|
||||
[[X.1] [Shared Lockables Concepts] [Yes] [ - ]]
|
||||
[[X.1.1] [SharedLockable concept] [Yes] [ - ]]
|
||||
[[X.1.2] [UpgradeLockable concept] [Yes] [ - ]]
|
||||
[[X.2] [Shared Mutex Types] [Yes] [ - ]]
|
||||
[[X.2.1] [shared_mutex class] [Yes] [ - ]]
|
||||
[[X.2.2] [upgrade_mutex class] [Yes] [ - ]]
|
||||
[[X.3] [Locks] [Yes] [-]]
|
||||
[[X.3.1] [unique_lock class adaptations] [Yes] [-]]
|
||||
[[X.3.2] [shared_lock class] [Yes] [ - ]]
|
||||
[[X.3.3] [upgrade_lock class] [Yes] [-]]
|
||||
[table Clock Requirements
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[XXXX] [DDDD] [SSSS] [CCCC]]
|
||||
[[XXXX] [DDDD] [SSSS] [CCCC]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
};
|
||||
class condition_variable;
|
||||
class condition_variable_any;
|
||||
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
|
||||
}
|
||||
|
||||
The classes `condition_variable` and `condition_variable_any` provide a
|
||||
@@ -87,7 +86,7 @@ optimizations in some cases, based on the knowledge of the mutex type;
|
||||
|
||||
[section:condition_variable Class `condition_variable`]
|
||||
|
||||
//#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -131,7 +130,7 @@ optimizations in some cases, based on the knowledge of the mutex type;
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred);
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
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);
|
||||
@@ -346,8 +345,8 @@ 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:] [`cv_status::timeout` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `cv_status::no_timeout` otherwise.]]
|
||||
[[Returns:] [`cv_status::no_timeout` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `cv_status::timeout` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
@@ -378,8 +377,8 @@ 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:] [`cv_status::timeout ` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `cv_status::no_timeout ` otherwise.]]
|
||||
[[Returns:] [`cv_status::no_timeout ` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `cv_status::timeout ` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
@@ -419,7 +418,14 @@ return true;
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
while(!pred())
|
||||
{
|
||||
if(!wait_for(lock,rel_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
@@ -433,7 +439,7 @@ return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
|
||||
[section:condition_variable_any Class `condition_variable_any`]
|
||||
|
||||
//#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -475,7 +481,7 @@ return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred);
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
|
||||
template<typename lock_type,typename duration_type>
|
||||
@@ -724,12 +730,19 @@ return true;
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for_predicate `template <class lock_type, class Rep, class Period, class Predicate> bool wait_for(lock_type& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
|
||||
[section:wait_for_predicate `template <class lock_type, class Rep, class Period, class Predicate> bool wait_until(lock_type& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
while(!pred())
|
||||
{
|
||||
if(!__cvany_wait_for(lock,rel_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
@@ -738,53 +751,14 @@ return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:condition Typedef `condition` DEPRECATED V3]
|
||||
[section:condition Typedef `condition`]
|
||||
|
||||
// #include <boost/thread/condition.hpp>
|
||||
namespace boost
|
||||
{
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
typedef condition_variable_any condition;
|
||||
|
||||
}
|
||||
|
||||
The typedef `condition` is provided for backwards compatibility with previous boost releases.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:notify_all_at_thread_exit Non-member Function `notify_all_at_thread_exit`()]
|
||||
|
||||
// #include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
|
||||
}
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`lk` is locked by the calling thread and either no other thread is waiting on `cond`, or `lk.mutex()` returns the same value for each of the lock arguments supplied by all concurrently waiting (via `wait`, `wait_for`, or `wait_until`) threads.]]
|
||||
[[Effects:] [transfers ownership of the lock associated with `lk` into internal storage and schedules `cond` to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification shall be as if
|
||||
|
||||
``
|
||||
lk.unlock();
|
||||
cond.notify_all();
|
||||
``
|
||||
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[/
|
||||
[[Synchronization:] [The call to notify_all_at_thread_exit and the completion of the destructors for all the current threadÕs variables of thread storage duration synchronize with (1.10) calls to functions waiting on cond.
|
||||
]]
|
||||
[[Note:] [The supplied lock will be held until the thread exits, and care must be taken to ensure that this does not cause deadlock due to lock ordering issues. After calling notify_all_at_thread_exit it is recommended that the thread should be exited as soon as possible, and that no blocking or time-consuming tasks are run on that thread.
|
||||
]]
|
||||
[[Note:] [It is the userÕs responsibility to ensure that waiting threads do not erroneously assume that the thread has finished if they experience spurious wakeups. This typically requires that the condition being waited for is satisfied while holding the lock on lk, and that this lock is not released and reacquired prior to calling notify_all_at_thread_exit.
|
||||
]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -8,168 +8,47 @@
|
||||
|
||||
[section:configuration Configuration]
|
||||
|
||||
[section:system Boost.System]
|
||||
|
||||
[table Default Values for Configurable Features
|
||||
[[Feature] [Anti-Feature] [V2] [V3] [V4] ]
|
||||
[[USES_CHRONO] [DONT_USE_CHRONO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ]
|
||||
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ]
|
||||
Boost.Thread uses by default Boost.System to define the exceptions. For backward compatibility and also for compilers that don't work well with Boost.System the user can define `BOOST_THREAD_DONT_USE_SYSTEM `.
|
||||
|
||||
|
||||
|
||||
[[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] ]
|
||||
|
||||
[[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] ]
|
||||
|
||||
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] ]
|
||||
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] ]
|
||||
|
||||
[[USES_DATETIME] [DONT_USE_DATETIME] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_SIGNATURE_PACKAGED_TASK] [DONT_PROVIDE_SIGNATURE_PACKAGED_TASK] [NO] [NO] [YES] ]
|
||||
[[PROVIDES_FUTURE_INVALID_AFTER_GET] [DONT_PROVIDE_FUTURE_INVALID_AFTER_GET] [NO] [NO] [YES] ]
|
||||
[/ [[PROVIDES_FUTURE_CONTINUATION] [DONT_PROVIDE_FUTURE_CONTINUATION] [NO] [NO] [YES] ] ]
|
||||
|
||||
[[PROVIDES_VARIADIC_THREAD] [DONT_PROVIDE_VARIADIC_THREAD] [NO] [NO] [C++11] ]
|
||||
|
||||
]
|
||||
|
||||
[section:chrono Boost.Chrono]
|
||||
|
||||
Boost.Thread uses by default Boost.Chrono for the time related functions and define `BOOST_THREAD_USES_CHRONO` if `BOOST_THREAD_DONT_USE_CHRONO` is not defined. The user should define `BOOST_THREAD_DONT_USE_CHRONO` for compilers that don't work well with Boost.Chrono.
|
||||
`BOOST_THREAD_USES_SYSTEM` is defined when Boost.Thread uses Boost.Move.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:chrono Boost.Chrono]
|
||||
|
||||
Boost.Thread uses by default Boost.Chrono for the time related functions. For backward compatibility and also for compilers that don't work well with Boost.Chrono the user can define `BOOST_THREAD_DONT_USE_CHRONO`. If `BOOST_THREAD_DONT_USE_SYSTEM` is defined then `BOOST_THREAD_DONT_USE_CHRONO` is defined implicitly.
|
||||
|
||||
`BOOST_THREAD_USES_CHRONO` is defined when Boost.Thread uses Boost.Chrono.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move Boost.Move]
|
||||
|
||||
Boost.Thread uses by default an internal move semantic implementation. Since version 3.0.0 you can use the move emulation emulation provided by Boost.Move.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_USES_MOVE ` if you want to use Boost.Move interface.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_USE_MOVE ` if you don't want to use Boost.Move interface.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_USE_MOVE ` if you want to use boost::unique_future.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:date_time Boost.DateTime]
|
||||
|
||||
The Boost.DateTime time related functions introduced in Boost 1.35.0, using the [link date_time Boost.Date_Time] library are deprecated. These include (but are not limited to):
|
||||
|
||||
* __sleep__
|
||||
* __timed_join__
|
||||
* __cond_timed_wait__
|
||||
* __timed_lock_ref__
|
||||
|
||||
|
||||
When `BOOST_THREAD_VERSION<=3` define `BOOST_THREAD_DONT_USE_DATETIME ` if you don't want to use Boost.DateTime related interfaces.
|
||||
When `BOOST_THREAD_VERSION>3` define `BOOST_THREAD_USES_DATETIME ` if you want to use Boost.DateTime related interfaces.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:thread_eq `boost::thread::oprator==` deprecated]
|
||||
|
||||
The following nested typedefs are deprecated:
|
||||
|
||||
* `boost::thread::oprator==`
|
||||
* `boost::thread::oprator!=`
|
||||
|
||||
When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature.
|
||||
|
||||
Use instead
|
||||
|
||||
* `boost::thread::id::oprator==`
|
||||
* `boost::thread::id::oprator!=`
|
||||
|
||||
[warning This is a breaking change respect to version 1.x.]
|
||||
|
||||
When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_PROVIDES_THREAD_EQ ` if you want this feature.
|
||||
When `BOOST_THREAD_VERSION<4` define `BOOST_THREAD_DONT_PROVIDE_THREAD_EQ ` if you don't want this feature.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:condition boost::condition deprecated]
|
||||
|
||||
`boost::condition` is deprecated. When `BOOST_THREAD_PROVIDES_CONDITION` is defined Boost.Thread provides this deprecated feature.
|
||||
|
||||
Use instead `boost::condition_variable_any`.
|
||||
|
||||
[warning This is a breaking change respect to version 1.x.]
|
||||
|
||||
When `BOOST_THREAD_VERSION>3` define `BOOST_THREAD_PROVIDES_CONDITION` if you want this feature.
|
||||
When `BOOST_THREAD_VERSION<=3` define `BOOST_THREAD_DONT_PROVIDE_CONDITION` if you don't want this feature.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:nested_lock Mutex nested lock types deprecated]
|
||||
|
||||
|
||||
The following nested typedefs are deprecated:
|
||||
|
||||
* `boost::mutex::scoped_lock`,
|
||||
* `boost::mutex::scoped_try_lock`,
|
||||
* `boost::timed_mutex::scoped_lock`
|
||||
* `boost::timed_mutex::scoped_try_lock`
|
||||
* `boost::timed_mutex::timed_scoped_timed_lock`
|
||||
* `boost::recursive_mutex::scoped_lock`,
|
||||
* `boost::recursive_mutex::scoped_try_lock`,
|
||||
* `boost::recursive_timed_mutex::scoped_lock`
|
||||
* `boost::recursive_timed_mutex::scoped_try_lock`
|
||||
* `boost::recursive_timed_mutex::timed_scoped_timed_lock`
|
||||
|
||||
When `BOOST_THREAD_PROVIDES_NESTED_LOCKS` is defined Boost.Thread provides these deprecated feature.
|
||||
|
||||
|
||||
Use instead
|
||||
* `boost::unique_lock<boost::mutex>`,
|
||||
* `boost::unique_lock<boost::mutex>` with the `try_to_lock_t` constructor,
|
||||
* `boost::unique_lock<boost::timed_mutex>`
|
||||
* `boost::unique_lock<boost::timed_mutex>` with the `try_to_lock_t` constructor
|
||||
* `boost::unique_lock<boost::timed_mutex>`
|
||||
* `boost::unique_lock<boost::recursive_mutex>`,
|
||||
* `boost::unique_lock<boost::recursive_mutex>` with the `try_to_lock_t` constructor,
|
||||
* `boost::unique_lock<boost::recursive_timed_mutex>`
|
||||
* `boost::unique_lock<boost::recursive_timed_mutex>` with the `try_to_lock_t` constructor
|
||||
* `boost::unique_lock<boost::recursive_timed_mutex>`
|
||||
|
||||
[warning This is a breaking change respect to version 1.x.]
|
||||
|
||||
When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_PROVIDES_NESTED_LOCKS` if you want these features.
|
||||
When `BOOST_THREAD_VERSION<4` define `BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS` if you don't want thes features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:id thread::id]
|
||||
|
||||
Boost.Thread uses by default a thread::id on Posix based on the pthread type (BOOST_THREAD_PROVIDES_BASIC_THREAD_ID). For backward compatibility and also for compilers that don't work well with this modification the user can define `BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID`.
|
||||
|
||||
Define `BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
[section:shared_gen Shared Locking Generic]
|
||||
|
||||
The shared mutex implementation on Windows platform provides currently less functionality than the generic one that is used for PTheads based platforms. In order to have access to these functions, the user needs to define `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` to use the generic implementation, that while could be less efficient, provides all the functions.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN ` if you don't want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared_upwards Shared Locking Upwards Conversion]
|
||||
|
||||
Boost.Threads includes in version 3 the Shared Locking Upwards Conversion as defined in [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking].
|
||||
Boost.Threads includes in version 2 the Shared Locking Upwards Conversion as defined in [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking].
|
||||
These conversions need to be used carefully to avoid deadlock or livelock. The user need to define explicitly `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` to get these upwards conversions.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -189,7 +68,7 @@ C++11 uses `std::future`. Versions of Boost.Thread previous to version 3.0.0 use
|
||||
Since version 3.0.0 `boost::future` replaces `boost::unique_future` when `BOOST_THREAD_PROVIDES_FUTURE` is defined. The documentation doesn't contains anymore however `boost::unique_future`.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_FUTURE` if you want to use boost::future.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE` if you want to use boost::unique_future.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE` if you want to use boost::unique_future.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -200,7 +79,7 @@ C++11 promise initialize the associated state at construction time. Versions of
|
||||
Since version 3.0.0 this difference in behavior can be configured. When `BOOST_THREAD_PROVIDES_PROMISE_LAZY` is defined the backward compatible behavior is provided.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY ` if you want to use boost::future.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_PROVIDES_PROMISE_LAZY ` if you want to use boost::unique_future.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_PROVIDES_PROMISE_LAZY ` if you want to use boost::unique_future.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -244,7 +123,7 @@ Since version 3.0.0 Boost.Thread implements this constructor using the following
|
||||
which introduces a dependency on Boost.Container. This feature is provided only if `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS` is defined.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS ` if you don't want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -253,10 +132,10 @@ When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALL
|
||||
C++11 has a different semantic for the thread destructor and the move assignment. Instead of detaching the thread, calls to terminate() if the thread was joinable. When `BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE` and `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE` is defined Boost.Thread provides the C++ semantic.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -271,90 +150,41 @@ You should now just do
|
||||
boost::once_flag once;
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_ONCE_CXX11` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11` if you don't want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:deprecated Deprecated]
|
||||
|
||||
[section:deprecated Signature parameter for packaged_task]
|
||||
Version 3.0.0 deprecates some Boost.Thread features.
|
||||
|
||||
C++11 packaged task class has a Signature template parameter. When `BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK ` is defined Boost.Thread provides this C++ feature.
|
||||
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define `BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define `BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
|
||||
|
||||
[warning This is a breaking change respect to version 3.x.]
|
||||
|
||||
When `BOOST_THREAD_VERSION<4` define `BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK` if you want this feature.
|
||||
When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK` if you don't want this feature.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:thread_const-var thread constructor with variadic rvalue parameters]
|
||||
|
||||
C++11 thread constructor accep a variable number of rvalue argumentshas. When `BOOST_THREAD_PROVIDES_VARIADIC_THREAD ` is defined Boost.Thread provides this C++ feature if the following are not defined
|
||||
|
||||
* BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
* BOOST_NO_CXX11_DECLTYPE
|
||||
* BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
* BOOST_NO_CXX11_HDR_TUPLE
|
||||
|
||||
When `BOOST_THREAD_VERSION>4` define `BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD ` if you don't want this feature.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_invalid future<>::get() invalidates the future]
|
||||
|
||||
C++11 future<>::get() invalidates the future once its value has been obtained. When `BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET ` is defined Boost.Thread provides this C++ feature.
|
||||
|
||||
[warning This is a breaking change respect to version 3.x.]
|
||||
|
||||
When `BOOST_THREAD_VERSION<4` define `BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET` if you want this feature.
|
||||
When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET` if you don't want this feature.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:intr Interruptions]
|
||||
|
||||
Thread interruption, while useful, makes any interruption point less efficient than if the thread were not interruptible.
|
||||
|
||||
When `BOOST_THREAD_PROVIDES_INTERRUPTIONS` is defined Boost.Thread provides interruptions.
|
||||
When `BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS` is defined Boost.Thread don't provide interruption.
|
||||
|
||||
Boost.Thread defines BOOST_THREAD_PROVIDES_INTERRUPTIONS if neither BOOST_THREAD_PROVIDES_INTERRUPTIONS nor BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS are defined, so that there is no compatibility break.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:version Version]
|
||||
|
||||
`BOOST_THREAD_VERSION` defines the Boost.Thread version.
|
||||
The default version is 2. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
The default version is 1. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
|
||||
* `BOOST_THREAD_PROVIDES_PROMISE_LAZY`
|
||||
* `BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0`
|
||||
|
||||
The user can request the version 3 by defining `BOOST_THREAD_VERSION` to 3. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
The user can request the version 2 by defining `BOOST_THREAD_VERSION` to 2. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION `
|
||||
* Conformity & Breaking change `BOOST_THREAD_PROVIDES_FUTURE`
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_FUTURE`
|
||||
* Uniformity `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN`
|
||||
* Extension `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION`
|
||||
* Conformity `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS`
|
||||
* Conformity & Breaking change BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Conformity & Breaking change BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Conformity & Breaking change `BOOST_THREAD_PROVIDES_ONCE_CXX11`
|
||||
* Breaking change BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Breaking change BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_ONCE_CXX11`
|
||||
|
||||
* Breaking change `BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY`
|
||||
|
||||
The default value for `BOOST_THREAD_VERSION` will be changed to 3 since Boost 1.54.
|
||||
|
||||
The user can request the version 4 by defining `BOOST_THREAD_VERSION` to 4. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
|
||||
* Conformity & Breaking change `BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK `
|
||||
* Conformity & Breaking change `BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET `
|
||||
* Conformity `BOOST_THREAD_PROVIDES_VARIADIC_THREAD`
|
||||
* Breaking change `BOOST_THREAD_DONT_PROVIDE_THREAD_EQ`
|
||||
* Breaking change `BOOST_THREAD_DONT_USE_DATETIME`
|
||||
|
||||
|
||||
The default value for `BOOST_THREAD_VERSION` will be changed to 4 since Boost 1.56.
|
||||
* Breaking change `BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -369,31 +199,17 @@ Some compilers don't work correctly with some of the added features.
|
||||
If __SUNPRO_CC < 0x5100 the library defines
|
||||
|
||||
* `BOOST_THREAD_DONT_USE_MOVE`
|
||||
|
||||
If __SUNPRO_CC < 0x5100 the library defines
|
||||
|
||||
* `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS`
|
||||
|
||||
|
||||
[endsect]
|
||||
[section:vacpp VACPP]
|
||||
|
||||
If __IBMCPP__ < 1100 the library defines
|
||||
If __IBMCPP__ is defined the library defines
|
||||
|
||||
* `BOOST_THREAD_DONT_USE_CHRONO`
|
||||
* `BOOST_THREAD_USES_DATE`
|
||||
|
||||
And Boost.Thread doesn't links with Boost.Chrono.
|
||||
|
||||
|
||||
[endsect]
|
||||
[section:ce WCE]
|
||||
|
||||
If _WIN32_WCE && _WIN32_WCE==0x501 the library defines
|
||||
|
||||
* `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS`
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -340,7 +340,7 @@ Instead of
|
||||
|
||||
use
|
||||
|
||||
switch (boost::native_value(ev))
|
||||
switch (BOOST_SCOPED_ENUM_NATIVE(future_errc)(ev))
|
||||
{
|
||||
case future_errc::broken_promise:
|
||||
|
||||
|
||||
@@ -1,583 +0,0 @@
|
||||
[/
|
||||
/ Copyright (c) 2008,2012 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 External Locking -- `strict_lock` and `externally_locked` classes]
|
||||
|
||||
|
||||
[note This tutorial is an adaptation of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System"
|
||||
to the Boost library.]
|
||||
|
||||
[/
|
||||
[section Internal locking]
|
||||
|
||||
Consider, for example, modeling a bank account class that supports simultaneous deposits and withdrawals from multiple locations (arguably the "Hello, World" of multi-threaded programming). In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_; // explicit mutex declaration
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ -= amount;
|
||||
}
|
||||
int GetBalance() {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
The object-level locking idiom doesn't cover the entire richness of a threading model. For example, the model above is quite deadlock-prone when you try to coordinate multi-object transactions. Nonetheless, object-level locking is useful in many cases, and in combination with other mechanisms can provide a satisfactory solution to many threaded access problems in object-oriented programs.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Internal and external locking]
|
||||
|
||||
The BankAccount class above uses internal locking. Basically, a class that uses internal locking guarantees that any concurrent calls to its public member functions don't corrupt an instance of that class. This is typically ensured by having each public member function acquire a lock on the object upon entry. This way, for any given object of that class, there can be only one member function call active at any moment, so the operations are nicely serialized.
|
||||
|
||||
This approach is reasonably easy to implement and has an attractive simplicity. Unfortunately, "simple" might sometimes morph into "simplistic."
|
||||
|
||||
Internal locking is insufficient for many real-world synchronization tasks. Imagine that you want to implement an ATM withdrawal transaction with the BankAccount class. The requirements are simple. The ATM transaction consists of two withdrawals-one for the actual money and one for the $2 commission. The two withdrawals must appear in strict sequence; that is, no other transaction can exist between them.
|
||||
|
||||
The obvious implementation is erratic:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
acct.Withdraw(sum);
|
||||
// preemption possible
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
The problem is that between the two calls above, another thread can perform another operation on the account, thus breaking the second design requirement.
|
||||
|
||||
In an attempt to solve this problem, let's lock the account from the outside during the two operations:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
boost::lock_guard<boost::mutex> guard(acct.mtx_); // mtx_ field is private
|
||||
acct.Withdraw(sum);
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
|
||||
Notice that the code above doesn't compiles, the `mtx_` field is private.
|
||||
We have two possibilities:
|
||||
|
||||
* make `mtx_` public which seams odd
|
||||
* make the `BankAccount` lockable by adding the lock/unlock functions
|
||||
|
||||
We can add these functions explicitly
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_;
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ -= amount;
|
||||
}
|
||||
void lock() {
|
||||
mtx_.lock();
|
||||
}
|
||||
void unlock() {
|
||||
mtx_.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
or inheriting from a class which add these lockable functions.
|
||||
|
||||
The `basic_lockable_adapter` class helps to define the `BankAccount` class as
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<thread_mutex>
|
||||
{
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
boost::lock_guard<BankAccount> guard(*this);
|
||||
// boost::lock_guard<boost::mutex> guard(*this->mutex());
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
boost::lock_guard<BankAccount> guard(*this);
|
||||
// boost::lock_guard<boost::mutex> guard(*this->mutex());
|
||||
balance_ -= amount;
|
||||
}
|
||||
int GetBalance() {
|
||||
boost::lock_guard<BankAccount> guard(*this);
|
||||
// boost::lock_guard<boost::mutex> guard(*this->mutex());
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
and the code that does not compiles becomes
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
// boost::lock_guard<boost::mutex> guard(*acct.mutex());
|
||||
boost::lock_guard<BankAccount> guard(acct);
|
||||
acct.Withdraw(sum);
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
Notice that now acct is being locked by Withdraw after it has already been locked by guard. When running such code, one of two things happens.
|
||||
|
||||
* Your mutex implementation might support the so-called recursive mutex semantics. This means that the same thread can lock the same mutex several times successfully. In this case, the implementation works but has a performance overhead due to unnecessary locking. (The locking/unlocking sequence in the two Withdraw calls is not needed but performed anyway-and that costs time.)
|
||||
* Your mutex implementation might not support recursive locking, which means that as soon as you try to acquire it the second time, it blocks-so the ATMWithdrawal function enters the dreaded deadlock.
|
||||
|
||||
As `boost::mutex` is not recursive, we need to use its recursive version `boost::recursive_mutex`.
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<recursive_mutex>
|
||||
{
|
||||
|
||||
// ...
|
||||
};
|
||||
|
||||
The caller-ensured locking approach is more flexible and the most efficient, but very dangerous. In an implementation using caller-ensured locking, BankAccount still holds a mutex, but its member functions don't manipulate it at all. Deposit and Withdraw are not thread-safe anymore. Instead, the client code is responsible for locking BankAccount properly.
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<boost:mutex> {
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
balance_ -= amount;
|
||||
}
|
||||
};
|
||||
|
||||
Obviously, the caller-ensured locking approach has a safety problem. BankAccount's implementation code is finite, and easy to reach and maintain, but there's an unbounded amount of client code that manipulates BankAccount objects. In designing applications, it's important to differentiate between requirements imposed on bounded code and unbounded code. If your class makes undue requirements on unbounded code, that's usually a sign that encapsulation is out the window.
|
||||
|
||||
To conclude, if in designing a multi-threaded class you settle on internal locking, you expose yourself to inefficiency or deadlocks. On the other hand, if you rely on caller-provided locking, you make your class error-prone and difficult to use. Finally, external locking completely avoids the issue by leaving it all to the client code.
|
||||
[endsect]
|
||||
]
|
||||
[section Locks as Permits]
|
||||
|
||||
So what to do? Ideally, the BankAccount class should do the following:
|
||||
|
||||
* Support both locking models (internal and external).
|
||||
* Be efficient; that is, use no unnecessary locking.
|
||||
* Be safe; that is, BankAccount objects cannot be manipulated without appropriate locking.
|
||||
|
||||
Let's make a worthwhile observation: Whenever you lock a BankAccount, you do so by using a `lock_guard<BankAccount>` object. Turning this statement around, wherever there's a `lock_guard<BankAccount>`, there's also a locked `BankAccount` somewhere. Thus, you can think of-and use-a `lock_guard<BankAccount>` object as a permit. Owning a `lock_guard<BankAccount>` gives you rights to do certain things. The `lock_guard<BankAccount>` object should not be copied or aliased (it's not a transmissible permit).
|
||||
|
||||
# As long as a permit is still alive, the `BankAccount` object stays locked.
|
||||
# When the `lock_guard<BankAccount>` is destroyed, the `BankAccount`'s mutex is released.
|
||||
|
||||
The net effect is that at any point in your code, having access to a `lock_guard<BankAccount>` object guarantees that a `BankAccount` is locked. (You don't know exactly which `BankAccount` is locked, however-an issue that we'll address soon.)
|
||||
|
||||
For now, let's make a couple of enhancements to the `lock_guard` class template defined in Boost.Thread.
|
||||
We'll call the enhanced version `strict_lock`. Essentially, a `strict_lock`'s role is only to live on the stack as an automatic variable.
|
||||
`strict_lock` must adhere to a non-copy and non-alias policy.
|
||||
`strict_lock` disables copying by making the copy constructor and the assignment operator private.
|
||||
While we're at it, let's disable operator new and operator delete;
|
||||
`strict_lock` are not intended to be allocated on the heap.
|
||||
`strict_lock` avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.
|
||||
|
||||
|
||||
template <typename Lockable>
|
||||
class strict_lock {
|
||||
public:
|
||||
typedef Lockable lockable_type;
|
||||
|
||||
|
||||
explicit strict_lock(lockable_type& obj) : obj_(obj) {
|
||||
obj.lock(); // locks on construction
|
||||
}
|
||||
strict_lock() = delete;
|
||||
strict_lock(strict_lock const&) = delete;
|
||||
strict_lock& operator=(strict_lock const&) = delete;
|
||||
|
||||
~strict_lock() { obj_.unlock(); } // unlocks on destruction
|
||||
|
||||
bool owns_lock(mutex_type const* l) const noexcept // strict lockers specific function
|
||||
{
|
||||
return l == &obj_;
|
||||
}
|
||||
private:
|
||||
lockable_type& obj_;
|
||||
};
|
||||
|
||||
Silence can be sometimes louder than words-what's forbidden to do with a `strict_lock` is as important as what you can do. Let's see what you can and what you cannot do with a `strict_lock` instantiation:
|
||||
|
||||
* You can create a `strict_lock<T>` only starting from a valid T object. Notice that there is no other way you can create a `strict_lock<T>`.
|
||||
|
||||
BankAccount myAccount("John Doe", "123-45-6789");
|
||||
strict_locerk<BankAccount> myLock(myAccount); // ok
|
||||
|
||||
* You cannot copy `strict_lock`s to one another. In particular, you cannot pass `strict_lock`s by value to functions or have them returned by functions:
|
||||
|
||||
extern strict_lock<BankAccount> Foo(); // compile-time error
|
||||
extern void Bar(strict_lock<BankAccount>); // compile-time error
|
||||
|
||||
* However, you still can pass `strict_lock`s by reference to and from functions:
|
||||
|
||||
// ok, Foo returns a reference to strict_lock<BankAccount>
|
||||
extern strict_lock<BankAccount>& Foo();
|
||||
// ok, Bar takes a reference to strict_lock<BankAccount>
|
||||
extern void Bar(strict_lock<BankAccount>&);
|
||||
|
||||
* You cannot allocate a `strict_lock` on the heap. However, you still can put `strict_lock`s on the heap if they're members of a class.
|
||||
|
||||
strict_lock<BankAccount>* pL =
|
||||
new strict_lock<BankAccount>(myAcount); //error!
|
||||
// operator new is not accessible
|
||||
class Wrapper {
|
||||
strict_lock memberLock_;
|
||||
...
|
||||
};
|
||||
Wrapper* pW = new Wrapper; // ok
|
||||
|
||||
(Making `strict_lock` a member variable of a class is not recommended. Fortunately, disabling copying and default construction makes `strict_lock` quite an unfriendly member variable.)
|
||||
|
||||
* You cannot take the address of a `strict_lock` object. This interesting feature, implemented by disabling unary operator&, makes it very unlikely to alias a `strict_lock` object. Aliasing is still possible by taking references to a `strict_lock`:
|
||||
|
||||
strict_lock<BankAccount> myLock(myAccount); // ok
|
||||
strict_lock<BankAccount>* pAlias = &myLock; // error!
|
||||
// strict_lock<BankAccount>::operator& is not accessible
|
||||
strict_lock<BankAccount>& rAlias = myLock; // ok
|
||||
|
||||
Fortunately, references don't engender as bad aliasing as pointers because they're much less versatile (references cannot be copied or reseated).
|
||||
|
||||
* You can even make `strict_lock` final; that is, impossible to derive from. This task is left in the form of an exercise to the reader.
|
||||
|
||||
All these rules were put in place with one purpose-enforcing that owning a `strict_lock<T>` is a reasonably strong guarantee that
|
||||
|
||||
# you locked a T object, and
|
||||
# that object will be unlocked at a later point.
|
||||
|
||||
Now that we have such a strict `strict_lock`, how do we harness its power in defining a safe, flexible interface for BankAccount? The idea is as follows:
|
||||
|
||||
* Each of BankAccount's interface functions (in our case, Deposit and Withdraw) comes in two overloaded variants.
|
||||
* One version keeps the same signature as before, and the other takes an additional argument of type `strict_lock<BankAccount>`. The first version is internally locked; the second one requires external locking. External locking is enforced at compile time by requiring client code to create a `strict_lock<BankAccount>` object.
|
||||
* BankAccount avoids code bloating by having the internal locked functions forward to the external locked functions, which do the actual job.
|
||||
|
||||
A little code is worth 1,000 words, a (hacked into) saying goes, so here's the new BankAccount class:
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<boost:recursive_mutex>
|
||||
{
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount, strict_lock<BankAccount>&) {
|
||||
// Externally locked
|
||||
balance_ += amount;
|
||||
}
|
||||
void Deposit(int amount) {
|
||||
strict_lock<boost:mutex> guard(*this); // Internally locked
|
||||
Deposit(amount, guard);
|
||||
}
|
||||
void Withdraw(int amount, strict_lock<BankAccount>&) {
|
||||
// Externally locked
|
||||
balance_ -= amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
strict_lock<boost:mutex> guard(*this); // Internally locked
|
||||
Withdraw(amount, guard);
|
||||
}
|
||||
};
|
||||
|
||||
Now, if you want the benefit of internal locking, you simply call Deposit(int) and Withdraw(int). If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
strict_lock<BankAccount> guard(acct);
|
||||
acct.Withdraw(sum, guard);
|
||||
acct.Withdraw(2, guard);
|
||||
}
|
||||
|
||||
This function has the best of both worlds-it's reasonably safe and efficient at the same time.
|
||||
|
||||
It's worth noting that `strict_lock` being a template gives extra safety compared to a straight polymorphic approach. In such a design, BankAccount would derive from a Lockable interface. `strict_lock` would manipulate Lockable references so there's no need for templates. This approach is sound; however, it provides fewer compile-time guarantees. Having a `strict_lock` object would only tell that some object derived from Lockable is currently locked. In the templated approach, having a `strict_lock<BankAccount>` gives a stronger guarantee-it's a `BankAccount` that stays locked.
|
||||
|
||||
There's a weasel word in there-I mentioned that ATMWithdrawal is reasonably safe. It's not really safe because there's no enforcement that the `strict_lock<BankAccount>` object locks the appropriate BankAccount object. The type system only ensures that some BankAccount object is locked. For example, consider the following phony implementation of ATMWithdrawal:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
BankAccount fakeAcct("John Doe", "123-45-6789");
|
||||
strict_lock<BankAccount> guard(fakeAcct);
|
||||
acct.Withdraw(sum, guard);
|
||||
acct.Withdraw(2, guard);
|
||||
}
|
||||
|
||||
This code compiles warning-free but obviously doesn't do the right thing-it locks one account and uses another.
|
||||
|
||||
It's important to understand what can be enforced within the realm of the C++ type system and what needs to be enforced at runtime. The mechanism we've put in place so far ensures that some BankAccount object is locked during the call to `BankAccount::Withdraw(int, strict_lock<BankAccount>&)`. We must enforce at runtime exactly what object is locked.
|
||||
|
||||
If our scheme still needs runtime checks, how is it useful? An unwary or malicious programmer can easily lock the wrong object and manipulate any BankAccount without actually locking it.
|
||||
|
||||
First, let's get the malice issue out of the way. C is a language that requires a lot of attention and discipline from the programmer. C++ made some progress by asking a little less of those, while still fundamentally trusting the programmer. These languages are not concerned with malice (as Java is, for example). After all, you can break any C/C++ design simply by using casts "appropriately" (if appropriately is an, er, appropriate word in this context).
|
||||
|
||||
The scheme is useful because the likelihood of a programmer forgetting about any locking whatsoever is much greater than the likelihood of a programmer who does remember about locking, but locks the wrong object.
|
||||
|
||||
Using `strict_lock` permits compile-time checking of the most common source of errors, and runtime checking of the less frequent problem.
|
||||
|
||||
Let's see how to enforce that the appropriate BankAccount object is locked. First, we need to add a member function to the `strict_lock` class template.
|
||||
The `bool strict_lock<T>::owns_lock(Loclable*)` function returns a reference to the locked object.
|
||||
|
||||
template <class Lockable> class strict_lock {
|
||||
... as before ...
|
||||
public:
|
||||
bool owns_lock(Lockable* mtx) const { return mtx==&obj_; }
|
||||
};
|
||||
|
||||
Second, BankAccount needs to use this function compare the locked object against this:
|
||||
|
||||
class BankAccount {
|
||||
: public basic_lockable_adapter<boost::recursive_mutex>
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount, strict_lock<BankAccount>& guard) {
|
||||
// Externally locked
|
||||
if (!guard.owns_lock(*this))
|
||||
throw "Locking Error: Wrong Object Locked";
|
||||
balance_ += amount;
|
||||
}
|
||||
// ...
|
||||
};
|
||||
|
||||
The overhead incurred by the test above is much lower than locking a recursive mutex for the second time.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Improving External Locking]
|
||||
|
||||
Now let's assume that BankAccount doesn't use its own locking at all, and has only a thread-neutral implementation:
|
||||
|
||||
class BankAccount {
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
balance_ -= amount;
|
||||
}
|
||||
};
|
||||
|
||||
Now you can use BankAccount in single-threaded and multi-threaded applications alike, but you need to provide your own synchronization in the latter case.
|
||||
|
||||
Say we have an AccountManager class that holds and manipulates a BankAccount object:
|
||||
|
||||
class AccountManager
|
||||
: public basic_lockable_adapter<boost::mutex>
|
||||
{
|
||||
BankAccount checkingAcct_;
|
||||
BankAccount savingsAcct_;
|
||||
...
|
||||
};
|
||||
|
||||
Let's also assume that, by design, AccountManager must stay locked while accessing its BankAccount members. The question is, how can we express this design constraint using the C++ type system? How can we state "You have access to this BankAccount object only after locking its parent AccountManager object"?
|
||||
|
||||
The solution is to use a little bridge template `externally_locked` that controls access to a BankAccount.
|
||||
|
||||
template <typename T, typename Lockable>
|
||||
class externally_locked {
|
||||
BOOST_CONCEPT_ASSERT((LockableConcept<Lockable>));
|
||||
|
||||
public:
|
||||
externally_locked(T& obj, Lockable& lockable)
|
||||
: obj_(obj)
|
||||
, lockable_(lockable)
|
||||
{}
|
||||
|
||||
externally_locked(Lockable& lockable)
|
||||
: obj_()
|
||||
, lockable_(lockable)
|
||||
{}
|
||||
|
||||
T& get(strict_lock<Lockable>& lock) {
|
||||
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME // define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME if you don't want to check locker check the same lockable
|
||||
if (!lock.is_locking(&lockable_)) throw lock_error(); run time check throw if not locks the same
|
||||
#endif
|
||||
return obj_;
|
||||
}
|
||||
void set(const T& obj, Lockable& lockable) {
|
||||
obj_ = obj;
|
||||
lockable_=lockable;
|
||||
}
|
||||
private:
|
||||
T obj_;
|
||||
Lockable& lockable_;
|
||||
};
|
||||
|
||||
`externally_locked` cloaks an object of type T, and actually provides full access to that object through the get and set member functions, provided you pass a reference to a `strict_lock<Owner>` object.
|
||||
|
||||
Instead of making `checkingAcct_` and `savingsAcct_` of type `BankAccount`, `AccountManager` holds objects of type `externally_locked<BankAccount, AccountManager>`:
|
||||
|
||||
class AccountManager
|
||||
: public basic_lockable_adapter<thread_mutex>
|
||||
{
|
||||
public:
|
||||
typedef basic_lockable_adapter<thread_mutex> lockable_base_type;
|
||||
AccountManager()
|
||||
: checkingAcct_(*this)
|
||||
, savingsAcct_(*this)
|
||||
{}
|
||||
inline void Checking2Savings(int amount);
|
||||
inline void AMoreComplicatedChecking2Savings(int amount);
|
||||
private:
|
||||
|
||||
externally_locked<BankAccount, AccountManager> checkingAcct_;
|
||||
externally_locked<BankAccount, AccountManager> savingsAcct_;
|
||||
};
|
||||
|
||||
The pattern is the same as before - to access the BankAccount object cloaked by `checkingAcct_`, you need to call `get`. To call `get`, you need to pass it a `strict_lock<AccountManager>`. The one thing you have to take care of is to not hold pointers or references you obtained by calling `get`. If you do that, make sure that you don't use them after the strict_lock has been destroyed. That is, if you alias the cloaked objects, you're back from "the compiler takes care of that" mode to "you must pay attention" mode.
|
||||
|
||||
Typically, you use `externally_locked` as shown below. Suppose you want to execute an atomic transfer from your checking account to your savings account:
|
||||
|
||||
void AccountManager::Checking2Savings(int amount) {
|
||||
strict_lock<AccountManager> guard(*this);
|
||||
checkingAcct_.get(guard).Withdraw(amount);
|
||||
savingsAcct_.get(guard).Deposit(amount);
|
||||
}
|
||||
|
||||
We achieved two important goals. First, the declaration of `checkingAcct_` and `savingsAcct_` makes it clear to the code reader that that variable is protected by a lock on an AccountManager. Second, the design makes it impossible to manipulate the two accounts without actually locking a BankAccount. `externally_locked` is what could be called active documentation.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Allowing other strict locks]
|
||||
|
||||
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compiles:
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard(*this, defer_lock);
|
||||
if (some_condition()) {
|
||||
guard.lock();
|
||||
}
|
||||
checkingAcct_.get(guard).Withdraw(amount); // COMPILE ERROR
|
||||
savingsAcct_.get(guard).Deposit(amount); // COMPILE ERROR
|
||||
do_something_else();
|
||||
}
|
||||
|
||||
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard(*this, defer_lock);
|
||||
if (some_condition()) {
|
||||
guard1.lock();
|
||||
}
|
||||
{
|
||||
strict_lock<AccountManager> guard(guard1);
|
||||
checkingAcct_.get(guard).Withdraw(amount);
|
||||
savingsAcct_.get(guard).Deposit(amount);
|
||||
}
|
||||
guard1.unlock();
|
||||
}
|
||||
|
||||
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.
|
||||
|
||||
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict\_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parolle". The advantage is that now we can manage with more than two strict locks without changing our code. Ths is really nice.
|
||||
|
||||
Now we need to state that both classes are `strict_lock`s.
|
||||
|
||||
template <typename Locker>
|
||||
struct is_strict_lock : mpl::false_ {};
|
||||
|
||||
template <typename Lockable>
|
||||
struct is_strict_lock<strict_lock<Lockable> > : mpl::true_ {}
|
||||
|
||||
template <typename Locker>
|
||||
struct is_strict_lock<nested_strict_lock<Locker> > : mpl::true_ {}
|
||||
|
||||
|
||||
Well let me show how this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
|
||||
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction he will restore the ownership. Note also that the Locker needs to have already a reference to the mutex otherwise an exception is thrown and the use of the `lock_traits`.
|
||||
|
||||
template <typename Locker >
|
||||
class nested_strict_lock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((MovableLockerConcept<Locker>));
|
||||
public:
|
||||
typedef typename lockable_type<Locker>::type lockable_type;
|
||||
typedef typename syntactic_lock_traits<lockable_type>::lock_error lock_error;
|
||||
|
||||
nested_strict_lock(Locker& lock)
|
||||
: lock_(lock) // Store reference to locker
|
||||
, tmp_lock_(lock.move()) // Move ownership to temporaty locker
|
||||
{
|
||||
#ifndef BOOST_THREAD_STRCIT_LOCKER_DONT_CHECK_OWNERSHIP // Define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP if you don't want to check locker ownership
|
||||
if (tmp_lock_.mutex()==0) {
|
||||
lock_=tmp_lock_.move(); // Rollback for coherency purposes
|
||||
throw lock_error();
|
||||
}
|
||||
#endif
|
||||
if (!tmp_lock_) tmp_lock_.lock(); // ensures it is locked
|
||||
}
|
||||
~nested_strict_lock() {
|
||||
lock_=tmp_lock_.move(); // Move ownership to nesting locker
|
||||
}
|
||||
typedef bool (nested_strict_lock::*bool_type)() const;
|
||||
operator bool_type() const { return &nested_strict_lock::owns_lock; }
|
||||
bool operator!() const { return false; }
|
||||
bool owns_lock() const { return true; }
|
||||
const lockable_type* mutex() const { return tmp_lock_.mutex(); }
|
||||
bool is_locking(lockable_type* l) const { return l==mutex(); }
|
||||
|
||||
BOOST_ADRESS_OF_DELETE(nested_strict_lock)
|
||||
BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
|
||||
BOOST_DEFAULT_CONSTRUCTOR_DELETE(nested_strict_lock) 8
|
||||
BOOST_COPY_CONSTRUCTOR_DELETE(nested_strict_lock) 9
|
||||
BOOST_COPY_ASSIGNEMENT_DELETE(nested_strict_lock) 10
|
||||
|
||||
private:
|
||||
Locker& lock_;
|
||||
Locker tmp_lock_;
|
||||
};
|
||||
|
||||
The `externally_locked` get function is now a template function taking a Locker as parameters instead of a `strict_lock`.
|
||||
We can add test in debug mode that ensure that the Lockable object is locked.
|
||||
|
||||
template <typename T, typename Lockable>
|
||||
class externally_locked {
|
||||
public:
|
||||
// ...
|
||||
template <class Locker>
|
||||
T& get(Locker& lock) {
|
||||
BOOST_CONCEPT_ASSERT((StrictLockerConcept<Locker>));
|
||||
|
||||
BOOST_STATIC_ASSERT((is_strict_lock<Locker>::value)); // locker is a strict locker "sur parolle"
|
||||
BOOST_STATIC_ASSERT((is_same<Lockable,
|
||||
typename lockable_type<Locker>::type>::value)); // that locks the same type
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP // define BOOST_THREAD_EXTERNALLY_LOCKED_NO_CHECK_OWNERSHIP if you don't want to check locker ownership
|
||||
if (! lock ) throw lock_error(); // run time check throw if no locked
|
||||
#endif
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME
|
||||
if (!lock.is_locking(&lockable_)) throw lock_error();
|
||||
#endif
|
||||
return obj_;
|
||||
}
|
||||
};
|
||||
|
||||
The `AccountManager::AMoreComplicatedFunction` function needs only to replace the `strict_lock` by a `nested_strict_lock`.
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard1(*this);
|
||||
if (some_condition()) {
|
||||
guard1.lock();
|
||||
}
|
||||
{
|
||||
nested_strict_lock<unique_lock<AccountManager> > guard(guard1);
|
||||
checkingAcct_.get(guard).Withdraw(amount);
|
||||
savingsAcct_.get(guard).Deposit(amount);
|
||||
}
|
||||
guard1.unlock();
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
1150
doc/future_ref.qbk
1150
doc/future_ref.qbk
File diff suppressed because it is too large
Load Diff
301
doc/futures.qbk
301
doc/futures.qbk
@@ -23,26 +23,25 @@
|
||||
|
||||
|
||||
[template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]]
|
||||
[def __unique_future__ [unique_future_link `future`]]
|
||||
[def __unique_future `future`]
|
||||
[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::future<R>::get()`]]
|
||||
[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::future<R>::wait()`]]
|
||||
[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::future<R>::is_ready()`]]
|
||||
[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::future<R>::has_value()`]]
|
||||
[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::future<R>::has_exception()`]]
|
||||
[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::future<R>::get_state()`]]
|
||||
[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`]]
|
||||
@@ -70,7 +69,6 @@
|
||||
|
||||
[template packaged_task_link[link_text] [link thread.synchronization.futures.reference.packaged_task [link_text]]]
|
||||
[def __packaged_task__ [packaged_task_link `boost::packaged_task`]]
|
||||
[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()`]]
|
||||
@@ -93,13 +91,10 @@ the result is ready, it is returned from __unique_future_get__ by rvalue-referen
|
||||
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 non `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
|
||||
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.
|
||||
|
||||
`boost::async` is a simple way of running asynchronous tasks. A call to `boost::async` returns a __unique_future__ that will contain the result of the task.
|
||||
|
||||
|
||||
You can wait for futures either individually or with one of the __wait_for_any__ and __wait_for_all__ functions.
|
||||
|
||||
[endsect]
|
||||
@@ -119,7 +114,7 @@ place of the return value.
|
||||
}
|
||||
|
||||
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
|
||||
boost::__unique_future__<int> fi=pt.get_future();
|
||||
boost::unique_future<int> fi=pt.get_future();
|
||||
|
||||
boost::thread task(boost::move(pt)); // launch task on a thread
|
||||
|
||||
@@ -137,7 +132,7 @@ future. A promise can therefore be used where the value may come from more than
|
||||
produce multiple values.
|
||||
|
||||
boost::promise<int> pi;
|
||||
boost::__unique_future__<int> fi;
|
||||
boost::unique_future<int> fi;
|
||||
fi=pi.get_future();
|
||||
|
||||
pi.set_value(42);
|
||||
@@ -179,7 +174,7 @@ call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task t
|
||||
{
|
||||
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());
|
||||
boost::unique_future<int> f(task.get_future());
|
||||
|
||||
assert(f.get()==42);
|
||||
}
|
||||
@@ -187,280 +182,6 @@ call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task t
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:at_thread_exit Handling Detached Threads and Thread Specific Variables]
|
||||
|
||||
Detached threads pose a problem for objects with thread storage duration.
|
||||
If we use a mechanism other than `thread::__join` to wait for a __thread to complete its work - such as waiting for a future to be ready -
|
||||
then the destructors of thread specific variables will still be running after the waiting thread has resumed.
|
||||
This section explain how the standard mechanism can be used to make such synchronization safe by ensuring that the
|
||||
objects with thread storage duration are destroyed prior to the future being made ready. e.g.
|
||||
|
||||
int find_the_answer(); // uses thread specific objects
|
||||
void thread_func(boost::promise<int>&& p)
|
||||
{
|
||||
p.set_value_at_thread_exit(find_the_answer());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::promise<int> p;
|
||||
boost::thread t(thread_func,boost::move(p));
|
||||
t.detach(); // we're going to wait on the future
|
||||
std::cout<<p.get_future().get()<<std::endl;
|
||||
}
|
||||
|
||||
When the call to `get()` returns, we know that not only is the future value ready, but the thread specific variables
|
||||
on the other thread have also been destroyed.
|
||||
|
||||
Such mechanisms are provided for `boost::condition_variable`, `boost::promise` and `boost::packaged_task`. e.g.
|
||||
|
||||
void task_executor(boost::packaged_task<void(int)> task,int param)
|
||||
{
|
||||
task.make_ready_at_thread_exit(param); // execute stored task
|
||||
} // destroy thread specific and wake threads waiting on futures from task
|
||||
|
||||
Other threads can wait on a future obtained from the task without having to worry about races due to the execution of
|
||||
destructors of the thread specific objects from the task's thread.
|
||||
|
||||
boost::condition_variable cv;
|
||||
boost::mutex m;
|
||||
complex_type the_data;
|
||||
bool data_ready;
|
||||
|
||||
void thread_func()
|
||||
{
|
||||
boost::unique_lock<std::mutex> lk(m);
|
||||
the_data=find_the_answer();
|
||||
data_ready=true;
|
||||
boost::notify_all_at_thread_exit(cv,boost::move(lk));
|
||||
} // destroy thread specific objects, notify cv, unlock mutex
|
||||
|
||||
void waiting_thread()
|
||||
{
|
||||
boost::unique_lock<std::mutex> lk(m);
|
||||
while(!data_ready)
|
||||
{
|
||||
cv.wait(lk);
|
||||
}
|
||||
process(the_data);
|
||||
}
|
||||
|
||||
The waiting thread is guaranteed that the thread specific objects used by `thread_func()` have been destroyed by the time
|
||||
`process(the_data)` is called. If the lock on `m` is released and re-acquired after setting `data_ready` and before calling
|
||||
`boost::notify_all_at_thread_exit()` then this does NOT hold, since the thread may return from the wait due to a
|
||||
spurious wake-up.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:async Executing asynchronously]
|
||||
|
||||
`boost::async` is a simple way of running asynchronous tasks to make use of the available hardware concurrency.
|
||||
A call to `boost::async` returns a `boost::future` that will contain the result of the task. Depending on
|
||||
the launch policy, the task is either run asynchronously on its own thread or synchronously on whichever thread
|
||||
calls the `wait()` or `get()` member functions on that `future`.
|
||||
|
||||
A launch policy of either boost::launch::async, which asks the runtime to create an asynchronous thread,
|
||||
or boost::launch::deferred, which indicates you simply want to defer the function call until a later time (lazy evaluation).
|
||||
This argument is optional - if you omit it your function will use the default policy.
|
||||
|
||||
For example, consider computing the sum of a very large array. The first task is to not compute asynchronously when
|
||||
the overhead would be significant. The second task is to split the work into two pieces, one executed by the host
|
||||
thread and one executed asynchronously.
|
||||
|
||||
|
||||
int parallel_sum(int* data, int size)
|
||||
{
|
||||
int sum = 0;
|
||||
if ( size < 1000 )
|
||||
for ( int i = 0; i < size; ++i )
|
||||
sum += data[i];
|
||||
else {
|
||||
auto handle = boost::async(parallel_sum, data+size/2, size-size/2);
|
||||
sum += parallel_sum(data, size/2);
|
||||
sum += handle.get();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared Shared Futures]
|
||||
|
||||
`shared_future` is designed to be shared between threads,
|
||||
that is to allow multiple concurrent get operations.
|
||||
|
||||
[heading Multiple get]
|
||||
|
||||
The second `get()` call in the following example future
|
||||
|
||||
void bad_second_use( type arg ) {
|
||||
|
||||
auto ftr = async( [=]{ return work( arg ); } );
|
||||
if ( cond1 )
|
||||
{
|
||||
use1( ftr.get() );
|
||||
} else
|
||||
{
|
||||
use2( ftr.get() );
|
||||
}
|
||||
use3( ftr.get() ); // second use is undefined
|
||||
}
|
||||
|
||||
Using a `shared_mutex` solves the issue
|
||||
|
||||
void good_second_use( type arg ) {
|
||||
|
||||
shared_future<type> ftr = async( [=]{ return work( arg ); } );
|
||||
if ( cond1 )
|
||||
{
|
||||
use1( ftr.get() );
|
||||
} else
|
||||
{
|
||||
use2( ftr.get() );
|
||||
}
|
||||
use3( ftr.get() ); // second use is defined
|
||||
}
|
||||
|
||||
[heading share()]
|
||||
|
||||
Namming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists.
|
||||
Here `share()` could be used to simplify the code
|
||||
|
||||
void better_second_use( type arg ) {
|
||||
|
||||
auto ftr = async( [=]{ return work( arg ); } ).share();
|
||||
if ( cond1 )
|
||||
{
|
||||
use1( ftr.get() );
|
||||
} else
|
||||
{
|
||||
use2( ftr.get() );
|
||||
}
|
||||
use3( ftr.get() ); // second use is defined
|
||||
}
|
||||
|
||||
[heading Writting on get()]
|
||||
|
||||
The user can either read or write the future avariable.
|
||||
|
||||
void write_to_get( type arg ) {
|
||||
|
||||
auto ftr = async( [=]{ return work( arg ); } ).share();
|
||||
if ( cond1 )
|
||||
{
|
||||
use1( ftr.get() );
|
||||
} else
|
||||
{
|
||||
if ( cond2 )
|
||||
use2( ftr.get() );
|
||||
else
|
||||
ftr.get() = something(); // assign to non-const reference.
|
||||
}
|
||||
use3( ftr.get() ); // second use is defined
|
||||
}
|
||||
|
||||
This works because the `shared_future<>::get()` function returns a non-const reference to the appropriate storage.
|
||||
Of course the access to this storage must be ensured by the user. The library doesn't ensure the access to the internal storage is thread safe.
|
||||
|
||||
There has been some work by the C++ standard committe on an `atomic_future` that behaves as an `atomic` variable, that is is thread_safe,
|
||||
and a `shared_future` that can be shared between several threads, but there were not enough consensus and time to get it ready for C++11.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:make_future Making immediate futures easier]
|
||||
|
||||
Some functions may know the value at the point of construction. In these cases the value is immediately available,
|
||||
but needs to be returned as a future or shared_future. By using make_future (make_shared_future) a future (shared_future)
|
||||
can be created which holds a pre-computed result in its shared state.
|
||||
|
||||
Without these features it is non-trivial to create a future directly from a value.
|
||||
First a promise must be created, then the promise is set, and lastly the future is retrieved from the promise.
|
||||
This can now be done with one operation.
|
||||
|
||||
[heading make_future / make_shared_future]
|
||||
|
||||
This function creates a future for a given value. If no value is given then a future<void> is returned.
|
||||
This function is primarily useful in cases where sometimes, the return value is immediately available, but sometimes
|
||||
it is not. The example below illustrates, that in an error path the value is known immediately, however in other paths
|
||||
the function must return an eventual value represented as a future.
|
||||
|
||||
|
||||
boost::future<int> compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_future(0);
|
||||
if (x < 0) return boost::make_future(-1);
|
||||
boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
return f1;
|
||||
}
|
||||
|
||||
There are two variations of this function. The first takes a value of any type, and returns a future of that type.
|
||||
The input value is passed to the shared state of the returned future. The second version takes no input and returns a future<void>.
|
||||
make_shared_future has the same functionality as make_future, except has a return type of shared_future.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:then Associating future continuations]
|
||||
|
||||
In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second
|
||||
operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future.
|
||||
With .then, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is
|
||||
invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits
|
||||
or wasting threads on polling, greatly improving the responsiveness and scalability of an application.
|
||||
|
||||
future.then provides the ability to sequentially compose two futures by declaring one to be the continuation of another.
|
||||
With .then the antecedent future is ready (has a value or exception stored in the shared state) before the continuation
|
||||
starts as instructed by the lambda function.
|
||||
|
||||
In the example below the future<int> f2 is registered to be a continuation of future<int> f1 using the .then member
|
||||
function. This operation takes a lambda function which describes how f2 should proceed after f1 is ready.
|
||||
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
using namespace boost;
|
||||
int main()
|
||||
{
|
||||
future<int> f1 = async([]() { return 123; });
|
||||
future<string> f2 = f1.then([](future<int> f) { return f.get().to_string(); // here .get() won't block });
|
||||
}
|
||||
|
||||
One key feature of this function is the ability to chain multiple asynchronous operations. In asynchronous programming,
|
||||
it's common to define a sequence of operations, in which each continuation executes only when the previous one completes.
|
||||
In some cases, the antecedent future produces a value that the continuation accepts as input. By using future.then,
|
||||
creating a chain of continuations becomes straightforward and intuitive:
|
||||
|
||||
myFuture.then(...).then(...).then(...).
|
||||
|
||||
Some points to note are:
|
||||
|
||||
* Each continuation will not begin until the preceding has completed.
|
||||
* If an exception is thrown, the following continuation can handle it in a try-catch block
|
||||
|
||||
|
||||
Input Parameters:
|
||||
|
||||
* Lambda function2: One option which was considered was to follow JavaScript's approach and take two functions, one for
|
||||
success and one for error handling. However this option is not viable in C++ as there is no single base type for
|
||||
exceptions as there is in JavaScript. The lambda function takes a future as its input which carries the exception
|
||||
through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
|
||||
* Scheduler: Providing an overload to .then, to take a scheduler reference places great flexibility over the execution
|
||||
of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful
|
||||
asynchronous operations. The lifetime of the scheduler must outlive the continuation.
|
||||
* Launch policy: if the additional flexibility that the scheduler provides is not required.
|
||||
|
||||
|
||||
Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using
|
||||
.then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning
|
||||
a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A
|
||||
shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future
|
||||
to a shared_future when needed using future::share().
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[include future_ref.qbk]
|
||||
|
||||
[endsect]
|
||||
@@ -1,450 +0,0 @@
|
||||
[/
|
||||
/ Copyright (c) 2008 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 Internal Locking]
|
||||
[note This tutorial is an adaptation of chapter Concurrency of the Object-Oriented Programming in the BETA Programming Language and of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System" to the Boost library.]
|
||||
[section Concurrent threads of execution]
|
||||
|
||||
Consider, for example, modeling a bank account class that supports simultaneous deposits and withdrawals from multiple locations (arguably the "Hello, World" of multithreaded programming).
|
||||
|
||||
From here a component is a model of the `Callable` concept.
|
||||
|
||||
On C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
|
||||
|
||||
boost::thread thread1(S);
|
||||
|
||||
where `S` is a model of `Callable`. The meaning of this expression is that execution of `S()` will take place concurrently with the current thread of execution executing the expression.
|
||||
|
||||
The following example includes a bank account of a person (Joe) and two components, one corresponding to a bank agent depositing money in Joe's account, and one representing Joe. Joe will only be withdrawing money from the account:
|
||||
|
||||
class BankAccount;
|
||||
|
||||
BankAccount JoesAccount;
|
||||
|
||||
void bankAgent()
|
||||
{
|
||||
for (int i =10; i>0; --i) {
|
||||
//...
|
||||
JoesAccount.Deposit(500);
|
||||
//...
|
||||
}
|
||||
}
|
||||
|
||||
void Joe() {
|
||||
for (int i =10; i>0; --i) {
|
||||
//...
|
||||
int myPocket = JoesAccount.Withdraw(100);
|
||||
std::cout << myPocket << std::endl;
|
||||
//...
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
//...
|
||||
boost::thread thread1(bankAgent); // start concurrent execution of bankAgent
|
||||
boost::thread thread2(Joe); // start concurrent execution of Joe
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
return 0;
|
||||
}
|
||||
|
||||
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. Joe will similarly withdraw $100 from his account. These sentences describe that the bankAgent and Joe are executed concurrently.
|
||||
|
||||
The above example works well as long as the bankAgent and Joe doesn't access JoesAccount at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_;
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
mtx_.lock();
|
||||
balance_ += amount;
|
||||
mtx_.unlock();
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
mtx_.lock();
|
||||
balance_ -= amount;
|
||||
mtx_.unlock();
|
||||
}
|
||||
int GetBalance() {
|
||||
mtx_.lock();
|
||||
int b = balance_;
|
||||
mtx_.unlock();
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
Execution of the Deposit and Withdraw operations will no longer be able to make simultaneous access to balance.
|
||||
|
||||
Mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
|
||||
|
||||
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_; // explicit mutex declaration
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ -= amount;
|
||||
}
|
||||
int GetBalance() {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
The object-level locking idiom doesn't cover the entire richness of a threading model. For example, the model above is quite deadlock-prone when you try to coordinate multi-object transactions. Nonetheless, object-level locking is useful in many cases, and in combination with other mechanisms can provide a satisfactory solution to many threaded access problems in object-oriented programs.
|
||||
|
||||
The BankAccount class above uses internal locking. Basically, a class that uses internal locking guarantees that any concurrent calls to its public member functions don't corrupt an instance of that class. This is typically ensured by having each public member function acquire a lock on the object upon entry. This way, for any given object of that class, there can be only one member function call active at any moment, so the operations are nicely serialized.
|
||||
|
||||
This approach is reasonably easy to implement and has an attractive simplicity. Unfortunately, "simple" might sometimes morph into "simplistic."
|
||||
|
||||
Internal locking is insufficient for many real-world synchronization tasks. Imagine that you want to implement an ATM withdrawal transaction with the BankAccount class. The requirements are simple. The ATM transaction consists of two withdrawals-one for the actual money and one for the $2 commission. The two withdrawals must appear in strict sequence; that is, no other transaction can exist between them.
|
||||
|
||||
The obvious implementation is erratic:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
acct.Withdraw(sum);
|
||||
// preemption possible
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
The problem is that between the two calls above, another thread can perform another operation on the account, thus breaking the second design requirement.
|
||||
|
||||
In an attempt to solve this problem, let's lock the account from the outside during the two operations:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
boost::lock_guard<boost::mutex> guard(acct.mtx_); 1
|
||||
acct.Withdraw(sum);
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
Notice that the code above doesn't compiles, the `mtx_` field is private.
|
||||
We have two possibilities:
|
||||
|
||||
* make `mtx_` public which seams odd
|
||||
* make the `BankAccount` lockable by adding the lock/unlock functions
|
||||
|
||||
We can add these functions explicitly
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_;
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
boost::lock_guard<boost::mutex> guard(mtx_);
|
||||
balance_ -= amount;
|
||||
}
|
||||
void lock() {
|
||||
mtx_.lock();
|
||||
}
|
||||
void unlock() {
|
||||
mtx_.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
or inheriting from a class which add these lockable functions.
|
||||
|
||||
The `basic_lockable_adapter` class helps to define the `BankAccount` class as
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<mutex>
|
||||
{
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
boost::lock_guard<BankAccount> guard(*this);
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
boost::lock_guard<BankAccount> guard(*this);
|
||||
balance_ -= amount;
|
||||
}
|
||||
int GetBalance() {
|
||||
boost::lock_guard<BankAccount> guard(*this);
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
and the code that doesn't compiles becomes
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
boost::lock_guard<BankAccount> guard(acct);
|
||||
acct.Withdraw(sum);
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
Notice that now acct is being locked by Withdraw after it has already been locked by guard. When running such code, one of two things happens.
|
||||
|
||||
* Your mutex implementation might support the so-called recursive mutex semantics. This means that the same thread can lock the same mutex several times successfully. In this case, the implementation works but has a performance overhead due to unnecessary locking. (The locking/unlocking sequence in the two Withdraw calls is not needed but performed anyway-and that costs time.)
|
||||
* Your mutex implementation might not support recursive locking, which means that as soon as you try to acquire it the second time, it blocks-so the ATMWithdrawal function enters the dreaded deadlock.
|
||||
|
||||
As `boost::mutex` is not recursive, we need to use its recursive version `boost::recursive_mutex`.
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<recursive_mutex>
|
||||
{
|
||||
|
||||
// ...
|
||||
};
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/
|
||||
[section Monitors]
|
||||
|
||||
The use of `mutex` and `lockers`, as in `BankAccount`, is a common way of defining objects shared by two or more concurrent components. The basic_lockable_adapter class was a first step.
|
||||
We shall therefore introduce an abstraction that makes it easier to define such objects.
|
||||
The following class describes a so-called monitor pattern.
|
||||
|
||||
template <
|
||||
typename Lockable=mutex
|
||||
>
|
||||
class basic_monitor : protected basic_lockable_adapter<Lockable> { // behaves like an BasicLockable for the derived classes
|
||||
protected:
|
||||
typedef unspecified synchronizer; // is an strict lock guard
|
||||
};
|
||||
|
||||
[/shared_monitor]
|
||||
[/monitor]
|
||||
|
||||
A basic_monitor object behaves like a `BasicLockable` object but only for the inheriting classes.
|
||||
Protected inheritance from lockable_adapter provide to all the derived classes all BasicLockable operations. In addition has a protected nested class, synchronizer, used when defining the monitor operations to synchronize the access critical regions. The BankAccount may be described using Monitor in the following way:
|
||||
|
||||
class BankAccount : protected basic_monitor<>
|
||||
{
|
||||
protected:
|
||||
int balance_;
|
||||
public:
|
||||
BankAccount() : balance_(0) {}
|
||||
BankAccount(const BankAccount &rhs) {
|
||||
synchronizer _(*rhs.mutex());
|
||||
balance_=rhs.balance_;
|
||||
}
|
||||
|
||||
BankAccount& operator=(BankAccount &rhs)
|
||||
{
|
||||
if(&rhs == this) return *this;
|
||||
|
||||
int balance=0;
|
||||
{
|
||||
synchronizer _(*rhs.mutex());
|
||||
balance=rhs.balance_;
|
||||
}
|
||||
synchronizer _(*this->mutex());
|
||||
balance_=balance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Deposit(int amount) {
|
||||
synchronizer _(*this->mutex());
|
||||
balance_ += amount;
|
||||
}
|
||||
int Withdraw(int amount) {
|
||||
synchronizer _(*this->mutex());
|
||||
balance_ -= amount;
|
||||
return amount;
|
||||
}
|
||||
int GetBalance() {
|
||||
synchronizer _(*this->mutex());
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
In the following, a monitor means some sub-class of monitor. A synchronized operation means an operation using the synchronizer guard defined within some monitor. Monitor is one example of a high-level concurrency abstraction that can be defined by means of mutexes.
|
||||
|
||||
|
||||
[section Monitor Conditions]
|
||||
|
||||
It may happen that a component executing an entry operation of a monitor is unable to continue execution due to some condition not being fulfilled. Consider, for instance, a bounded buffer of characters. Such a buffer may be implemented as a monitor with two operations Push and Pull: the Puss operation cannot be executed if the buffer is full, and the Pull operation cannot be executed if the buffer is empty. A sketch of such a buffer monitor may look as
|
||||
follows:
|
||||
|
||||
class sync_buffer {
|
||||
boost::mutex mtx_; 1
|
||||
public:
|
||||
...
|
||||
bool full() { return in_==out_; }
|
||||
bool empty() { return in_==(out_%size)+1; }
|
||||
void push(T& v) {
|
||||
// wait if buffer is full
|
||||
data_[in_]=v;
|
||||
in_ = (in_% size)+1;
|
||||
}
|
||||
T pull() {
|
||||
// wait if buffer is empty
|
||||
out_ = (out_% size)+1;
|
||||
return data_[out_];
|
||||
}
|
||||
};
|
||||
|
||||
The meaning of a wait is that the calling component is delayed until the condition becomes true. We can do that using Boost.Thread condition variables like:
|
||||
|
||||
template <typename T, unsigned size>
|
||||
class sync_buffer
|
||||
{
|
||||
typedef boost::mutex mutex_type;
|
||||
typedef boost::condition_variable condition_type;
|
||||
typedef boost::unique_lock<mutex_type> unique_lock_type;
|
||||
mutex_type mtx_;
|
||||
condition_type not_full_;
|
||||
condition_type not_empty_;
|
||||
|
||||
T data_[size+1];
|
||||
unsigned in_, out_;
|
||||
|
||||
public:
|
||||
sync_buffer():in_(0), out_(0) {}
|
||||
|
||||
bool full() { return out_==(in_+1)%(size+1); }
|
||||
bool empty() { return out_==in_; }
|
||||
|
||||
unsigned get_in() {return in_;}
|
||||
unsigned get_out() {return out_;}
|
||||
void push(T v) {
|
||||
unique_lock_type guard(mtx_); 1
|
||||
while (full()) { 2
|
||||
not_full_.wait(guard);
|
||||
}
|
||||
data_[in_]=v;
|
||||
in_ = (in_+1)% (size+1);
|
||||
not_empty_.notify_one(); 3
|
||||
}
|
||||
|
||||
T pull() {
|
||||
unique_lock_type guard(mtx_); 4
|
||||
while (empty()) { 5
|
||||
not_empty_.wait(guard);
|
||||
}
|
||||
unsigned idx = out_;
|
||||
out_ = (out_+1)% (size+1);
|
||||
not_full_.notify_one(); 6
|
||||
return data_[idx];
|
||||
}
|
||||
};
|
||||
|
||||
The Monitor class replace the nested synchronizer unique_lock with the class `condition_unique_lock` for this purpose:
|
||||
|
||||
template <
|
||||
typename Lockable,
|
||||
class Condition=condition_safe<typename best_condition<Lockable>::type >
|
||||
, typename ScopeTag=typename scope_tag<Lockable>::type
|
||||
>
|
||||
class condition_unique_lock
|
||||
: protected unique_lock<Lockable,ScopeTag>
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((LockableConcept<Lockable>));
|
||||
public:
|
||||
typedef Lockable lockable_type;
|
||||
typedef Condition condition;
|
||||
|
||||
explicit condition_unique_lock(lockable_type& obj); 1
|
||||
condition_unique_lock(lockable_type& obj, condition &cond); 2
|
||||
template <typename Predicate>
|
||||
condition_unique_lock(lockable_type& obj, condition &cond, Predicate pred); 3
|
||||
~condition_unique_lock() 4
|
||||
|
||||
typedef bool (condition_unique_lock::*bool_type)() const; 5
|
||||
operator bool_type() const; 6
|
||||
bool operator!() const { return false; } 7
|
||||
bool owns_lock() const { return true; } 8
|
||||
bool is_locking(lockable_type* l) const 9
|
||||
|
||||
void relock_on(condition & cond);
|
||||
template<typename Clock, typename Duration>
|
||||
void relock_until(condition & cond, chrono::time_point<Clock, Duration> const& abs_time);
|
||||
template<typename duration_type>
|
||||
void relock_on_for(condition & cond, duration_type const& rel_time);
|
||||
|
||||
template<typename Predicate>
|
||||
void relock_when(condition &cond, Predicate pred);
|
||||
template<typename Predicate>
|
||||
template<typename Clock, typename Duration>
|
||||
void relock_when_until(condition &cond, Predicate pred,
|
||||
chrono::time_point<Clock, Duration> const& abs_time);
|
||||
template<typename Predicate, typename duration_type>
|
||||
void relock_when_for(condition &cond, Predicate pred,
|
||||
duration_type const& rel_time);
|
||||
|
||||
10
|
||||
};
|
||||
|
||||
|
||||
We may now give the complete version of the buffer class. The content of the buffer is: `data_[out_+1], data_[out_+2], ... data_R[in_-1]` where all the indexes are modulo size. The buffer is full if `in_=out_` and it is empty if `in_=(out_+1)%size`.
|
||||
|
||||
template <typename T, unsigned size>
|
||||
class sync_buffer : protected basic_monitor<>
|
||||
{
|
||||
condition not_full_;
|
||||
condition not_empty_;
|
||||
|
||||
T data_[size+1];
|
||||
unsigned in_, out_;
|
||||
|
||||
struct not_full {
|
||||
explicit not_full(sync_buffer &b):that_(b){};
|
||||
bool operator()() const { return !that_.full(); }
|
||||
sync_buffer &that_;
|
||||
};
|
||||
struct not_empty {
|
||||
explicit not_empty(sync_buffer &b):that_(b){};
|
||||
bool operator()() const { return !that_.empty(); }
|
||||
sync_buffer &that_;
|
||||
};
|
||||
public:
|
||||
BOOST_COPY_CONSTRUCTOR_DELETE(sync_buffer) 1
|
||||
BOOST_COPY_ASSIGNEMENT_DELETE(sync_buffer) 2
|
||||
sync_buffer():in_(0), out_(0) {}
|
||||
|
||||
bool full() { return out_==(in_+1)%(size+1); }
|
||||
bool empty() { return out_==in_; }
|
||||
|
||||
unsigned get_in() {return in_;}
|
||||
unsigned get_out() {return out_;}
|
||||
|
||||
void push(T v) {
|
||||
synchronizer _(*this->mutex(), not_full_, not_full(*this)); 3
|
||||
data_[in_]=v;
|
||||
in_ = (in_+1)% (size+1);
|
||||
not_empty_.notify_one(); 4
|
||||
}
|
||||
|
||||
T pull() {
|
||||
synchronizer _(*this->mutex(), not_empty_, not_empty(*this)); 5
|
||||
unsigned idx = out_;
|
||||
out_ = (out_+1)% (size+1);
|
||||
not_full_.notify_one(); 6
|
||||
return data_[idx];
|
||||
}
|
||||
};
|
||||
|
||||
Monitors and conditions are useful for describing simple cases of shared objects (by simple we mean a limited use of conditions). If the conditions for delaying a calling component become complicated, the monitor may similarly become difficult to program and read.
|
||||
|
||||
[endsect] [/Monitor Conditions]
|
||||
|
||||
[endsect] [/Monitors]
|
||||
]
|
||||
|
||||
[section Synchronized variables]
|
||||
[/include synchronized_value.qbk]
|
||||
[endsect] [/Synchronized variables]
|
||||
|
||||
|
||||
[endsect] [/Internal Locking]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -89,7 +89,7 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_lock(system_time const & abs_time);
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time);
|
||||
@@ -131,7 +131,7 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
~recursive_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock() noexcept;
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
@@ -187,7 +187,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
|
||||
~recursive_timed_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock() noexcept;
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_lock scoped_timed_lock;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_lock(system_time const & abs_time);
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time);
|
||||
|
||||
@@ -12,9 +12,7 @@ __boost_thread__ enables the use of multiple threads of execution with shared da
|
||||
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 (version 1).
|
||||
|
||||
Anthony Williams version (version 2) was a major rewrite designed to
|
||||
The __boost_thread__ library was originally written and designed by William E. Kempf (version 0). Anthony Williams version (version 1) was 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],
|
||||
@@ -22,8 +20,8 @@ closely follow the proposals presented to the C++ Standards Committee, in partic
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
|
||||
|
||||
Vicente J. Botet Escriba started (version 3) the adaptation to comply with the accepted Thread C++11 library (Make use of Boost.Chrono and Boost.Move) and the [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] Howard Hinnant proposal except for the upward conversions.
|
||||
Some minor non-standard features have been added also as thread attributes, reverse_lock, shared_lock_guard.
|
||||
Vicente J. Botet Escriba started in version 2 the adaptation to comply with the accepted Thread C++11 library (Make use of Boost.Chrono and Boost.Move) and the [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] Howard Hinnant proposal except for the upward conversions.
|
||||
Some minor features have been added also as thread attributes, reverse_lock, shared_lock_guard.
|
||||
|
||||
In order to use the classes and functions described here, you can
|
||||
either include the specific headers specified by the descriptions of
|
||||
@@ -44,27 +42,6 @@ The definition of these macros determines whether BOOST_THREAD_USE_DLL is define
|
||||
|
||||
The source code compiled when building the library defines a macros BOOST_THREAD_SOURCE that is used to import or export it. The user must not define this macro in any case.
|
||||
|
||||
Boost.Thread depends on some non header-only libraries.
|
||||
|
||||
* Boost.System: This dependency is mandatory and you will need to link with the library.
|
||||
|
||||
* Boost.Chrono: This dependency is optional (see below how to configure) and you will need to link with the library if you use some of the time related interfaces.
|
||||
|
||||
* Boost.DateTime: This dependency is mandatory, but even if Boost.DateTime is a non header-only library Boost.Thread uses only parts that are header-only, so in principle you should not need to link with the library.
|
||||
|
||||
It seems that there are some IDE (as e.g. Visual Studio) that deduce the libraries that a program needs to link to inspecting the sources. Such IDE could force to link to Boost.DateTime and/or Boost.Chrono.
|
||||
|
||||
As the single mandatory dependency is to Boost.System, the following
|
||||
|
||||
bjam toolset=msvc-11.0 --build-type=complete --with-thread
|
||||
|
||||
will install only boost_thread and boost_system.
|
||||
|
||||
Users of such IDE should force the Boost.Chrono and Boost.DateTime build using
|
||||
|
||||
bjam toolset=msvc-11.0 --build-type=complete --with-thread --with-chrono --with-date_time
|
||||
|
||||
|
||||
The following section describes all the macros used to configure Boost.Thread.
|
||||
|
||||
[include configuration.qbk]
|
||||
|
||||
@@ -1,463 +0,0 @@
|
||||
[/
|
||||
(C) Copyright 2008-9 Anthony Williams.
|
||||
(C) Copyright 12 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:ScopedThreads Scoped Threads]
|
||||
|
||||
[heading Synopsis]
|
||||
|
||||
//#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
struct detach;
|
||||
struct join_if_joinable;
|
||||
struct interrupt_and_join_if_joinable;
|
||||
template <class CallableThread = join_if_joinable>
|
||||
class strict_scoped_thread;
|
||||
template <class CallableThread = join_if_joinable>
|
||||
class scoped_thread;
|
||||
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
|
||||
|
||||
[section:motovation Motivation]
|
||||
Based on the scoped_thread class defined in C++ Concurrency in Action Boost.Thread defines a thread wrapper class that instead of calling terminate if the thread is joinable on destruction, call a specific action given as template parameter.
|
||||
|
||||
While the scoped_thread class defined in C++ Concurrency in Action is closer to strict_scoped_thread class that doesn't allows any change in the wrapped thread, Boost.Thread provides a class scoped_thread that provides the same non-deprecated interface than __thread.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Scoped Threads are wrappers around a thread that allows the user to state what to do at destruction time. One of the common uses is to join the thread at destruction time so this is the default behavior. This is the single difference respect to a thread. While thread call std::terminate() on the destructor is the thread is joinable, strict_scoped_thread<> or scoped_thread<> join the thread if joinable.
|
||||
|
||||
The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface than __thread and forwards all the operations.
|
||||
|
||||
boost::strict_scoped_thread<> t1((boost::thread(F)));
|
||||
boost::strict_scoped_thread<> t2((boost::thread(F)));
|
||||
t2.interrupt();
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:thread_functors Free Thread Functors]
|
||||
|
||||
//#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
struct detach;
|
||||
struct join_if_joinable;
|
||||
struct interrupt_and_join_if_joinable;
|
||||
|
||||
|
||||
[section:detach Functor `detach`]
|
||||
|
||||
struct detach
|
||||
{
|
||||
void operator()(thread& t)
|
||||
{
|
||||
t.detach();
|
||||
}
|
||||
};
|
||||
[endsect]
|
||||
[section:join_if_joinable Functor `join_if_joinable`]
|
||||
|
||||
struct join_if_joinable
|
||||
{
|
||||
void operator()(thread& t)
|
||||
{
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:interrupt_and_join_if_joinable Functor `interrupt_and_join_if_joinable`]
|
||||
|
||||
struct interrupt_and_join_if_joinable
|
||||
{
|
||||
void operator()(thread& t)
|
||||
{
|
||||
t.interrupt();
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:strict_scoped_thread Class `strict_scoped_thread`]
|
||||
|
||||
// #include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
template <class CallableThread = join_if_joinable>
|
||||
class strict_scoped_thread
|
||||
{
|
||||
thread t_; // for exposition purposes only
|
||||
public:
|
||||
|
||||
strict_scoped_thread(strict_scoped_thread const&) = delete;
|
||||
strict_scoped_thread& operator=(strict_scoped_thread const&) = delete;
|
||||
|
||||
explicit strict_scoped_thread(thread&& t) noexcept;
|
||||
|
||||
~strict_scoped_thread();
|
||||
|
||||
};
|
||||
|
||||
|
||||
RAI __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
|
||||
CallableThread: A callable `void(thread&)`.
|
||||
|
||||
The default is a `join_if_joinable`.
|
||||
|
||||
|
||||
`std/boost::thread` destructor terminates the program if the __thread is not joinable.
|
||||
This wrapper can be used to join the thread before destroying it seems a natural need.
|
||||
|
||||
[heading Example]
|
||||
|
||||
boost::strict_scoped_thread<> t((boost::thread(F)));
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
|
||||
explicit strict_scoped_thread(thread&& t) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [move the thread to own `t_`]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
~strict_scoped_thread();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to `CallableThread()(t_)`. ]]
|
||||
|
||||
[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:scoped_thread Class `scoped_thread`]
|
||||
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
class scoped_thread
|
||||
{
|
||||
thread t_; // for exposition purposes only
|
||||
public:
|
||||
scoped_thread() noexcept;
|
||||
scoped_thread(const scoped_thread&) = delete;
|
||||
scoped_thread& operator=(const scoped_thread&) = delete;
|
||||
|
||||
explicit scoped_thread(thread&& th) noexcept;
|
||||
|
||||
~scoped_thread();
|
||||
|
||||
// move support
|
||||
scoped_thread(scoped_thread && x) noexcept;
|
||||
scoped_thread& operator=(scoped_thread && x) noexcept;
|
||||
|
||||
void swap(scoped_thread& x) noexcept;
|
||||
|
||||
typedef thread::id id;
|
||||
|
||||
id get_id() const noexcept;
|
||||
|
||||
bool joinable() const noexcept;
|
||||
void join();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& t);
|
||||
#endif
|
||||
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void interrupt();
|
||||
bool interruption_requested() const noexcept;
|
||||
#endif
|
||||
|
||||
|
||||
};
|
||||
|
||||
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
|
||||
|
||||
|
||||
RAI __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
|
||||
CallableThread: A callable void(thread&).
|
||||
The default is join_if_joinable.
|
||||
|
||||
thread std::thread destructor terminates the program if the thread is not joinable.
|
||||
Having a wrapper that can join the thread before destroying it seems a natural need.
|
||||
|
||||
Remark: `scoped_thread` is not a __thread as __thread is not designed to be derived from as a polymorphic type.
|
||||
|
||||
Anyway `scoped_thread` can be used in most of the contexts a __thread could be used as it has the
|
||||
same non-deprecated interface with the exception of the construction.
|
||||
|
||||
[heading Example]
|
||||
|
||||
boost::scoped_thread<> t((boost::thread(F)));
|
||||
t.interrupt();
|
||||
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
|
||||
scoped_thread() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a scoped_thread instance that wraps to __not_a_thread__.]]
|
||||
|
||||
[[Postconditions:] [`this->get_id()==thread::id()`]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_constructor Move Constructor]
|
||||
|
||||
scoped_thread(scoped_thread&& other) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if any) to the newly constructed scoped_thread instance.]]
|
||||
|
||||
[[Postconditions:] [`other.get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the construction]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_assignment Move assignment operator]
|
||||
|
||||
scoped_thread& operator=(scoped_thread&& other) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if
|
||||
any) to `*this`.
|
||||
|
||||
- if defined `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE`: If there was a `scoped_thread` previously associated with `*this` then that `scoped_thread` is detached, DEPRECATED
|
||||
|
||||
- if defined `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE`: If the `scoped_thread` is joinable calls to std::terminate.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:thread_constructor Move Constructor from a __thread]
|
||||
|
||||
scoped_thread(thread&& t);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [move the thread to own `t_`.]]
|
||||
|
||||
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
~scoped_thread();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to `CallableThread()(t_)`. ]]
|
||||
|
||||
[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:joinable Member function `joinable()`]
|
||||
|
||||
bool joinable() const noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [Equivalent to return t_.joinable().]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:join Member function `join()`]
|
||||
|
||||
void join();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to t_.join().]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_join_for Member function `try_join_for()`]
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `t_.try_join_for(rel_time)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_join_until Member function `try_join_until()`]
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `t_.try_join_until(abs_time)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:detach Member function `detach()`]
|
||||
|
||||
void detach();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to `t_.detach()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:get_id Member function `get_id()`]
|
||||
|
||||
thread::id get_id() const noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `t_.get_id()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:interrupt Member function `interrupt()`]
|
||||
|
||||
void interrupt();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to `t_.interrupt()`.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:hardware_concurrency Static member function `hardware_concurrency()`]
|
||||
|
||||
unsigned hardware_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `thread::hardware_concurrency()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `t_.native_handle()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:swap Member function `swap()`]
|
||||
|
||||
void swap(scoped_thread& other) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent `t_.swap(other.t_)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
[section:non_member_swap Non-member function `swap(scoped_thread&,scoped_thread&)`]
|
||||
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [`lhs.swap(rhs)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
@@ -5,7 +5,7 @@
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:shared_mutex Class `shared_mutex` -- EXTENSION]
|
||||
[section:shared_mutex Class `shared_mutex`]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_lock_shared(system_time const& timeout);
|
||||
bool timed_lock(system_time const& timeout);
|
||||
#endif
|
||||
@@ -58,11 +58,10 @@ __shared_lockable_concept__.
|
||||
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`, `__try_lock_until()`, __timed_lock_ref__, __lock_shared_ref__,
|
||||
`__try_lock_shared_for()`, `__try_lock_shared_until()`, __try_lock_shared_ref__ and __timed_lock_shared_ref__ are permitted.
|
||||
|
||||
Note the the lack of reader-writer priority policies in shared_mutex. This is due to an algorithm credited to Alexander Terekhov which lets the OS decide which thread is the next to get the lock without caring whether a unique lock or shared lock is being sought. This results in a complete lack of reader or writer starvation. It is simply fair.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:upgrade_mutex Class `upgrade_mutex` -- EXTENSION]
|
||||
[section:upgrade_mutex Class `upgrade_mutex`]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
@@ -142,87 +141,3 @@ Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`,
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:null_mutex Class `null_mutex` -- EXTENSION]
|
||||
|
||||
#include <boost/thread/null_mutex.hpp>
|
||||
|
||||
class null_mutex
|
||||
{
|
||||
public:
|
||||
null_mutex(null_mutex const&) = delete;
|
||||
null_mutex& operator=(null_mutex const&) = delete;
|
||||
|
||||
null_mutex();
|
||||
~null_mutex();
|
||||
|
||||
void lock_shared();
|
||||
bool try_lock_shared();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_shared();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock();
|
||||
|
||||
void lock_upgrade();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_upgrade();
|
||||
|
||||
// Shared <-> Exclusive
|
||||
|
||||
bool try_unlock_shared_and_lock();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_unlock_shared_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_unlock_shared_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_and_lock_shared();
|
||||
|
||||
// Shared <-> Upgrade
|
||||
|
||||
bool try_unlock_shared_and_lock_upgrade();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
|
||||
// Upgrade <-> Exclusive
|
||||
|
||||
void unlock_upgrade_and_lock();
|
||||
bool try_unlock_upgrade_and_lock();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_unlock_upgrade_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_and_lock_upgrade();
|
||||
};
|
||||
|
||||
The class `boost::null_mutex` provides a no-op implementation of a multiple-reader / single-writer mutex. It is a model of the
|
||||
__UpgradeLockable concept.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -11,34 +11,4 @@
|
||||
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html Mutex, Lock, Condition Variable Rationale] adds rationale for the design decisions made for mutexes, locks and condition variables.
|
||||
|
||||
|
||||
In addition to the C++11 standard locks, Boost.Thread provides other locks and some utilities that help the user to make their code thread-safe.
|
||||
|
||||
[include internal_locking.qbk]
|
||||
|
||||
[include external_locking.qbk]
|
||||
|
||||
[section:with Executing Around a Function]
|
||||
|
||||
In particular, the library provides some lock factories.
|
||||
|
||||
template <class Lockable, class Function>
|
||||
auto with_lock_guard(Lockable& m, Function f) -> decltype(fn())
|
||||
{
|
||||
auto&& _ = boost::make_lock_guard(f);
|
||||
f();
|
||||
}
|
||||
|
||||
|
||||
that can be used as
|
||||
|
||||
int i = with_lock_guard(mtx, {}() -> bool
|
||||
{
|
||||
// access the protected state
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
[endsect] [/ With]
|
||||
|
||||
[endsect] [/ Tutorial]
|
||||
[endsect]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 4.0.0]
|
||||
[version 3.0.0]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-12 Vicente J. Botet Escriba]
|
||||
@@ -26,9 +26,9 @@
|
||||
[def __lockable_concept_type__ [lockable_concept_link `Lockable`]]
|
||||
[def __BasicLockable [link thread.synchronization.mutex_concepts.basic_lockable `BasicLockable`]]
|
||||
[def __Lockable [link thread.synchronization.mutex_concepts.lockable `Lockable`]]
|
||||
[def __TimedLockable [link thread.synchronization.mutex_concepts.timed_lockable `TimedLockable`]]
|
||||
[def __SharedLockable [link thread.synchronization.mutex_concepts.shared_lockable `SharedLockable`]]
|
||||
[def __UpgradeLockable [link thread.synchronization.mutex_concepts.upgrade_lockable `UpgradeLockable`]]
|
||||
[def __TimedLockable [link thread.synchronization.mutex_concepts.timed_lockable `TimedLockable `]]
|
||||
[def __SharedLockable [link thread.synchronization.mutex_concepts.shared_lockable `SharedLockable `]]
|
||||
[def __UpgradeLockable [link thread.synchronization.mutex_concepts.upgrade_lockable `UpgradeLockable `]]
|
||||
|
||||
[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]]
|
||||
@@ -135,7 +135,6 @@
|
||||
|
||||
[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()`]]
|
||||
[def __owns_lock [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()`]]
|
||||
@@ -146,7 +145,6 @@
|
||||
[def __boost_thread__ [*Boost.Thread]]
|
||||
[def __not_a_thread__ ['Not-a-Thread]]
|
||||
[def __interruption_points__ [link interruption_points ['interruption points]]]
|
||||
[def __lock_error__ `lock_error`]
|
||||
|
||||
[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]]
|
||||
[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]]
|
||||
@@ -156,27 +154,19 @@
|
||||
[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`]]
|
||||
|
||||
|
||||
[def __StrictLock [link thread.synchronization.lock_concepts.StrictLock `StrictLock`]]
|
||||
|
||||
[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]]
|
||||
|
||||
[def __lock_guard__ [link thread.synchronization.lock_guard.lock_guard `boost::lock_guard`]]
|
||||
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
|
||||
[def __unique_lock__ [unique_lock_link `boost::unique_lock`]]
|
||||
[def __unique_lock [unique_lock_link `boost::unique_lock`]]
|
||||
[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]]
|
||||
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
|
||||
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
|
||||
[def __reverse_lock [link thread.synchronization.other_locks.reverse_lock `reverse_lock`]]
|
||||
[def __shared_lock_guard [link thread.synchronization.other_locks.shared_lock_guard `shared_lock_guard`]]
|
||||
[def __shared_lock_guard_constructor_adopt [link thread.synchronization.other_locks.shared_lock_guard `shared_lock_guard`]]
|
||||
|
||||
[def __strict_lock [link thread.synchronization.other_locks.strict_locks.strict_lock `strict_lock`]]
|
||||
[def __nested_strict_lock [link thread.synchronization.other_locks.strict_locks.nested_strict_lock `nested_strict_lock`]]
|
||||
|
||||
|
||||
[def __thread__ [link thread.thread_management.thread `boost::thread`]]
|
||||
[def __thread [link thread.thread_management.thread `thread`]]
|
||||
[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()`]]
|
||||
@@ -184,6 +174,7 @@
|
||||
[def __try_join_for [link thread.thread_management.thread.try_join_for `try_join_for`]]
|
||||
[def __try_join_until [link thread.thread_management.thread.try_join_until `try_join_until`]]
|
||||
|
||||
|
||||
[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()`]]
|
||||
@@ -229,7 +220,6 @@
|
||||
[include changes.qbk]
|
||||
|
||||
[include thread_ref.qbk]
|
||||
[include scoped_thread.qbk]
|
||||
|
||||
[section:synchronization Synchronization]
|
||||
[include sync_tutorial.qbk]
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
{
|
||||
thread::id get_id() noexcept;
|
||||
template<typename TimeDuration>
|
||||
void yield() noexcept; // DEPRECATED
|
||||
void yield() noexcept;
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
template <class Rep, class Period>
|
||||
@@ -36,10 +36,9 @@
|
||||
class disable_interruption; // EXTENSION
|
||||
class restore_interruption; // EXTENSION
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template <TimeDuration>
|
||||
void sleep(TimeDuration const& rel_time); // DEPRECATED
|
||||
void sleep(system_time const& abs_time); // DEPRECATED
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
void sleep(TimeDuration const& rel_time);
|
||||
void sleep(system_time const& abs_time);
|
||||
#endif
|
||||
}
|
||||
class thread_group; // EXTENSION
|
||||
@@ -201,81 +200,18 @@ __thread_interrupted__, `std::terminate()` is called.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:detac Detaching thread]
|
||||
|
||||
A thread can 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__.
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread t(my_func);
|
||||
t.detach();
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:join Joining a thread]
|
||||
|
||||
In order to wait for a thread of execution to finish, the __join__, __join_for or __join_until (__timed_join__ deprecated) 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.
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread t(my_func);
|
||||
t.join();
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread t;
|
||||
t.join(); // do nothing
|
||||
}
|
||||
|
||||
Timed based join are similar, except that a call to __join_for or __join_until will also return if the thread being waited for
|
||||
does not complete when the specified time has elapsed or reached respectively.
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread t;
|
||||
if ( t.join_for(boost::chrono::milliseconds(500)) )
|
||||
// do something else
|
||||
t.join(); // join anyway
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor1 Destructor V1]
|
||||
[section:join 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__.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor2 Destructor V2]
|
||||
|
||||
When the __thread__ object that represents a thread of execution is destroyed the program terminates if the thread is __joinable__.
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread t(my_func);
|
||||
} // calls std::terminate()
|
||||
|
||||
You can use a thread_joiner to ensure that the thread has been joined at the thread destructor.
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread t(my_func);
|
||||
boost::thread_joiner g(t);
|
||||
// do someting else
|
||||
} // here the thread_joiner destructor will join the thread before it is destroyed.
|
||||
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.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -402,7 +338,7 @@ The user can access to some synchronization functions related to the native curr
|
||||
|
||||
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::interruption_point()` will be just ignored.
|
||||
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.
|
||||
|
||||
@@ -423,8 +359,6 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
class attributes; // EXTENSION
|
||||
|
||||
thread() noexcept;
|
||||
thread(const thread&) = delete;
|
||||
thread& operator=(const thread&) = delete;
|
||||
@@ -440,15 +374,15 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
|
||||
template <class F,class A1,class A2,...>
|
||||
thread(F f,A1 a1,A2 a2,...);
|
||||
template <class F, class ...Args>
|
||||
explicit thread(F&& f, Args&&... args);
|
||||
// template <class F, class ...Args>
|
||||
// explicit thread(F&& f, Args&&... args); // NOT YET IMPLEMENTED
|
||||
|
||||
template <class F>
|
||||
explicit thread(attributes& attrs, F f); // EXTENSION
|
||||
template <class F>
|
||||
thread(attributes& attrs, F &&f); // EXTENSION
|
||||
template <class F, class ...Args>
|
||||
explicit thread(attributes& attrs, F&& f, Args&&... args);
|
||||
// template <class F, class ...Args>
|
||||
// explicit thread(attributes& attrs, F&& f, Args&&... args); // NOT YET IMPLEMENTED
|
||||
|
||||
// move support
|
||||
thread(thread && x) noexcept;
|
||||
@@ -457,6 +391,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
void swap(thread& x) noexcept;
|
||||
|
||||
class id;
|
||||
class attributes;
|
||||
|
||||
id get_id() const noexcept;
|
||||
|
||||
@@ -478,19 +413,19 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
bool interruption_requested() const noexcept; // EXTENSION
|
||||
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_join(const system_time& wait_until); // DEPRECATED
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_join(const system_time& wait_until);
|
||||
template<typename TimeDuration>
|
||||
bool timed_join(TimeDuration const& rel_time); // DEPRECATED
|
||||
static void sleep(const system_time& xt);// DEPRECATED
|
||||
bool timed_join(TimeDuration const& rel_time);
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
bool operator==(const thread& other) const; // DEPRECATED
|
||||
bool operator!=(const thread& other) const; // DEPRECATED
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
static void yield();
|
||||
static void sleep(const system_time& xt);
|
||||
#endif
|
||||
static void yield() noexcept; // DEPRECATED
|
||||
|
||||
};
|
||||
|
||||
@@ -532,25 +467,11 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
|
||||
thread& operator=(thread&& other) noexcept;
|
||||
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE behavior.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Join the thread before moving.
|
||||
]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the thread managed by `other` (if
|
||||
any) to `*this`.
|
||||
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If there was a thread previously associated with `*this` then that thread is detached, DEPRECATED
|
||||
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate.
|
||||
]]
|
||||
any) to `*this`. Version 1: If there was a thread previously associated with
|
||||
`*this` then that thread is detached, version 2: If the thread is joinable calls to std::terminate.]]
|
||||
|
||||
[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]]
|
||||
|
||||
@@ -558,7 +479,6 @@ any) to `*this`.
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:callable_constructor Thread Constructor]
|
||||
@@ -706,29 +626,34 @@ are copied into internal storage for access by the new thread.]]]
|
||||
|
||||
~thread();
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE behavior.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Join the thread before destroying or use a scoped thread.
|
||||
]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If `*this` has an associated thread of execution, calls __detach__, DEPRECATED
|
||||
|
||||
- BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate. Destroys `*this`.]]
|
||||
[[Effects:] [Version 1: If `*this` has an associated thread of execution, calls __detach__, Version 2: If the thread is joinable calls to std::terminate. Destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Note:] [Either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/
|
||||
[section:v2_destructor V3 Thread Destructor]
|
||||
|
||||
~thread();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` has an associated thread of execution, calls terminate. Destroys `*this`.]]
|
||||
|
||||
[[Note:] [Either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.]]
|
||||
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
]
|
||||
|
||||
[section:joinable Member function `joinable()`]
|
||||
|
||||
@@ -755,25 +680,18 @@ Join the thread before destroying or use a scoped thread.
|
||||
|
||||
[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete.]]
|
||||
|
||||
[[Synchronization:] [The completion of the thread represented by `*this` synchronizes with the
|
||||
corresponding successful `join()` return. ]]
|
||||
[[Note:] [Operations on *this are not synchronized.
|
||||
]]
|
||||
|
||||
[[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 or `system_error`]]
|
||||
|
||||
[[Error Conditions:] [
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or `this->get_id() == boost::this_thread::get_id()`.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED` is defined.
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
|
||||
|
||||
[/
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable.
|
||||
]
|
||||
|
||||
]]
|
||||
@@ -784,24 +702,16 @@ corresponding successful `join()` return. ]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_join Member function `timed_join()` DEPRECATED]
|
||||
[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);
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.00.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __try_join_for, __try_join_until.
|
||||
]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [the thread is joinable.]]
|
||||
[[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.]]
|
||||
@@ -817,13 +727,12 @@ unchanged.]]
|
||||
|
||||
[[Error Conditions:] [
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
|
||||
|
||||
[/
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable.
|
||||
]
|
||||
|
||||
]]
|
||||
@@ -841,7 +750,7 @@ unchanged.]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [the thread is joinable.]]
|
||||
[[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 specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]]
|
||||
@@ -857,13 +766,12 @@ unchanged.]]
|
||||
|
||||
[[Error Conditions:] [
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
|
||||
|
||||
[/
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable.
|
||||
]
|
||||
|
||||
]]
|
||||
@@ -881,7 +789,7 @@ unchanged.]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [the thread is joinable.]]
|
||||
[[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 `abs_time` has
|
||||
been reach. If `*this` doesn't refer to a thread of execution, returns immediately.]]
|
||||
@@ -897,14 +805,12 @@ unchanged.]]
|
||||
|
||||
[[Error Conditions:] [
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
|
||||
|
||||
[/
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable.
|
||||
]
|
||||
|
||||
]]
|
||||
@@ -919,7 +825,7 @@ unchanged.]]
|
||||
|
||||
[section:detach Member function `detach()`]
|
||||
|
||||
void detach();
|
||||
void detach() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -929,15 +835,7 @@ unchanged.]]
|
||||
|
||||
[[Postconditions:] [`*this` no longer refers to any thread of execution.]]
|
||||
|
||||
[[Throws:] [`system_error`]]
|
||||
|
||||
[[Error Conditions:] [
|
||||
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
]]
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
@@ -959,7 +857,7 @@ a default-constructed __thread_id__.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:interrupt Member function `interrupt()` EXTENSION]
|
||||
[section:interrupt Member function `interrupt()`]
|
||||
|
||||
void interrupt();
|
||||
|
||||
@@ -1007,61 +905,38 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:equals `operator==` DEPRECATED]
|
||||
[section:equals `operator==` DEPRECATED V3]
|
||||
|
||||
bool operator==(const thread& other) const;
|
||||
|
||||
[warning
|
||||
DEPRECATED since 4.0.0.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use `a.__get_id()==b.__get_id()` instead`.
|
||||
]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [`get_id()==other.get_id()`]]
|
||||
|
||||
[[See:] [Use `a.__get_id()==b.__get_id()` instead]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:not_equals `operator!=` DEPRECATED]
|
||||
[section:not_equals `operator!=` DEPRECATED V3]
|
||||
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
[warning
|
||||
DEPRECATED since 4.0.0.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use `a.__get_id()!=b.__get_id()` instead`.
|
||||
]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [`get_id()!=other.get_id()`]]
|
||||
|
||||
[[See:] [Use `a.__get_id()!=b.__get_id()` instead`]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:sleep Static member function `sleep()` DEPRECATED]
|
||||
[section:sleep Static member function `sleep()`]
|
||||
|
||||
void sleep(system_time const& abs_time);
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
|
||||
]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Suspends the current thread until the specified time has been reached.]]
|
||||
@@ -1070,26 +945,22 @@ Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
|
||||
|
||||
[[Notes:] [`sleep()` is one of the predefined __interruption_points__.]]
|
||||
|
||||
[[See:] [Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:yield Static member function `yield()` DEPRECATED]
|
||||
[section:yield Static member function `yield()`]
|
||||
|
||||
void yield();
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `this_thread::__yield()`.
|
||||
]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [See [link thread.thread_management.this_thread.yield `boost::this_thread::yield()`].]]
|
||||
|
||||
[[See:] [Use `this_thread::__yield()`]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -1377,9 +1248,9 @@ thread attributes implementation. If no such instance exists, `native_handle()`
|
||||
class disable_interruption; // EXTENSION
|
||||
class restore_interruption; // EXTENSION
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
void sleep(TimeDuration const& rel_time); // DEPRECATED
|
||||
void sleep(system_time const& abs_time); // DEPRECATED
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
void sleep(TimeDuration const& rel_time);
|
||||
void sleep(system_time const& abs_time)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1460,7 +1331,7 @@ thread attributes implementation. If no such instance exists, `native_handle()`
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:sleep Non-member function `sleep()` DEPRECATED]
|
||||
[section:sleep Non-member function `sleep()`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
@@ -1471,15 +1342,6 @@ thread attributes implementation. If no such instance exists, `native_handle()`
|
||||
void sleep(system_time const& abs_time)
|
||||
}
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `__sleep_for()` and `__sleep_until()` instead.
|
||||
]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Suspends the current thread until the time period
|
||||
@@ -1490,6 +1352,8 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
|
||||
[[Notes:] [`sleep()` is one of the predefined __interruption_points__.]]
|
||||
|
||||
[[See:] [Use `__sleep_for()` and `__sleep_until()` instead.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -1506,7 +1370,8 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Suspends the current thread until the time point specified by
|
||||
[[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:] [Nothing if Clock satisfies the TrivialClock requirements and operations of Duration
|
||||
@@ -1530,8 +1395,8 @@ do not throw exceptions. __thread_interrupted__ if the current thread of executi
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Suspends the current thread until the duration specified by
|
||||
by `rel_time` has elapsed.]]
|
||||
[[Effects:] [Suspends the current thread until the time point specified by
|
||||
`abs_time` has been reached.]]
|
||||
|
||||
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted.]]
|
||||
|
||||
@@ -1705,17 +1570,14 @@ registered with `at_thread_exit()`]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:threadgroup Class `thread_group` EXTENSION]
|
||||
[section:threadgroup Class `thread_group`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_group.hpp>
|
||||
|
||||
class thread_group
|
||||
class thread_group:
|
||||
private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_group(const thread_group&) = delete;
|
||||
thread_group& operator=(const thread_group&) = delete;
|
||||
|
||||
thread_group();
|
||||
~thread_group();
|
||||
|
||||
@@ -1723,8 +1585,6 @@ registered with `at_thread_exit()`]]
|
||||
thread* create_thread(F threadfunc);
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
bool is_this_thread_in();
|
||||
bool is_thread_in(thread* thrd);
|
||||
void join_all();
|
||||
void interrupt_all();
|
||||
int size() const;
|
||||
@@ -1780,7 +1640,7 @@ registered with `at_thread_exit()`]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [The expression `delete thrd` is well-formed and will not result in undefined behaviour and `is_thread_in(thrd) == false`.]]
|
||||
[[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.]]
|
||||
|
||||
@@ -1810,40 +1670,12 @@ registered with `at_thread_exit()`]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`is_this_thread_in() == false`.]]
|
||||
|
||||
[[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:is_this_thread_in Member function `is_this_thread_in()`]
|
||||
|
||||
bool is_this_thread_in();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [true if there is a thread `th` in the group such that `th.get_id() == this_thread::get_id()`.]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:is_thread_in Member function `is_thread_in()`]
|
||||
|
||||
bool is_thread_in(thread* thrd);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [true if there is a thread `th` in the group such that `th.get_id() == thrd->get_id()`.]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
18
doc/time.qbk
18
doc/time.qbk
@@ -10,16 +10,14 @@
|
||||
As of Boost 1.50.0, the __boost_thread__ library uses Boost.Chrono library for all operations that require a
|
||||
time out as defined in the standard c++11. These include (but are not limited to):
|
||||
|
||||
* `boost::this_thread::__sleep_for`
|
||||
* `boost::this_thread::__sleep_until`
|
||||
* `boost::__thread::__try_join_for`
|
||||
* `boost::__thread::__try_join_until`
|
||||
* `boost::__condition_variable::__wait_for`
|
||||
* `boost::__condition_variable::__wait_until`
|
||||
* `boost::__condition_variable_any::__cvany_wait_for`
|
||||
* `boost::__condition_variable_any::__cvany_wait_until`
|
||||
* `__TimedLockable::__try_lock_for`
|
||||
* `__TimedLockable::__try_lock_until`
|
||||
* __sleep_for
|
||||
* __sleep_until
|
||||
* __try_join_for
|
||||
* __try_join_until
|
||||
* __wait_for
|
||||
* __wait_until
|
||||
* __try_lock_for
|
||||
* __try_lock_until
|
||||
|
||||
[section:deprecated Deprecated]
|
||||
The time related functions introduced in Boost 1.35.0, using the [link date_time Boost.Date_Time] library are deprecated. These include (but are not limited to):
|
||||
|
||||
13
doc/tss.qbk
13
doc/tss.qbk
@@ -47,16 +47,10 @@ 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.
|
||||
|
||||
[heading Rationale about the nature of the key]
|
||||
|
||||
Boost.Thread uses the address of the `thread_specific_ptr` instance as key of the thread specific pointers. This avoids to create/destroy a key which will need a lock to protect from race conditions. This has a little performance liability, as the access must be done using an associative container.
|
||||
|
||||
[section:thread_specific_ptr Class `thread_specific_ptr`]
|
||||
|
||||
// #include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
@@ -72,7 +66,6 @@ Boost.Thread uses the address of the `thread_specific_ptr` instance as key of th
|
||||
T* release();
|
||||
void reset(T* new_value=0);
|
||||
};
|
||||
}
|
||||
|
||||
[section:default_constructor `thread_specific_ptr();`]
|
||||
|
||||
@@ -109,14 +102,10 @@ supplied `cleanup_function` will be used to destroy any thread-local objects whe
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [All the thread specific instances associated to this thread_specific_ptr (except maybe the one associated to this thread) must be null.]]
|
||||
|
||||
[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Remarks:] [The requirement is due to the fact that in order to delete all these instances, the implementation should be forced to maintain a list of all the threads having an associated specific ptr, which is against the goal of thread specific data.]]
|
||||
|
||||
]
|
||||
|
||||
[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lockable_adapter.hpp>
|
||||
#include <boost/thread/externally_locked.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
class BankAccount
|
||||
{
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount)
|
||||
{
|
||||
balance_ += amount;
|
||||
}
|
||||
void Withdraw(int amount)
|
||||
{
|
||||
balance_ -= amount;
|
||||
}
|
||||
int GetBalance()
|
||||
{
|
||||
return balance_;
|
||||
}
|
||||
};
|
||||
|
||||
//[AccountManager
|
||||
class AccountManager: public basic_lockable_adapter<mutex>
|
||||
{
|
||||
public:
|
||||
typedef basic_lockable_adapter<mutex> lockable_base_type;
|
||||
AccountManager() :
|
||||
lockable_base_type(), checkingAcct_(*this), savingsAcct_(*this)
|
||||
{
|
||||
}
|
||||
inline void Checking2Savings(int amount);
|
||||
inline void AMoreComplicatedChecking2Savings(int amount);
|
||||
private:
|
||||
/*<-*/
|
||||
bool some_condition()
|
||||
{
|
||||
return true;
|
||||
} /*->*/
|
||||
externally_locked<BankAccount, AccountManager > checkingAcct_;
|
||||
externally_locked<BankAccount, AccountManager > savingsAcct_;
|
||||
};
|
||||
//]
|
||||
|
||||
//[Checking2Savings
|
||||
void AccountManager::Checking2Savings(int amount)
|
||||
{
|
||||
strict_lock<AccountManager> guard(*this);
|
||||
checkingAcct_.get(guard).Withdraw(amount);
|
||||
savingsAcct_.get(guard).Deposit(amount);
|
||||
}
|
||||
//]
|
||||
|
||||
//#if DO_NOT_COMPILE
|
||||
////[AMoreComplicatedChecking2Savings_DO_NOT_COMPILE
|
||||
//void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
// unique_lock<AccountManager> guard(*this);
|
||||
// if (some_condition()) {
|
||||
// guard.lock();
|
||||
// }
|
||||
// checkingAcct_.get(guard).Withdraw(amount);
|
||||
// savingsAcct_.get(guard).Deposit(amount);
|
||||
// guard1.unlock();
|
||||
//}
|
||||
////]
|
||||
//#elif DO_NOT_COMPILE_2
|
||||
////[AMoreComplicatedChecking2Savings_DO_NOT_COMPILE2
|
||||
//void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
// unique_lock<AccountManager> guard1(*this);
|
||||
// if (some_condition()) {
|
||||
// guard1.lock();
|
||||
// }
|
||||
// {
|
||||
// strict_lock<AccountManager> guard(guard1);
|
||||
// checkingAcct_.get(guard).Withdraw(amount);
|
||||
// savingsAcct_.get(guard).Deposit(amount);
|
||||
// }
|
||||
// guard1.unlock();
|
||||
//}
|
||||
////]
|
||||
//#else
|
||||
////[AMoreComplicatedChecking2Savings
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard1(*this);
|
||||
if (some_condition()) {
|
||||
guard1.lock();
|
||||
}
|
||||
{
|
||||
nested_strict_lock<unique_lock<AccountManager> > guard(guard1);
|
||||
checkingAcct_.get(guard).Withdraw(amount);
|
||||
savingsAcct_.get(guard).Deposit(amount);
|
||||
}
|
||||
guard1.unlock();
|
||||
}
|
||||
////]
|
||||
//#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
AccountManager mgr;
|
||||
mgr.Checking2Savings(100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include "../test/remove_error_code_unused_warning.hpp"
|
||||
|
||||
class bounded_buffer : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef boost::unique_lock<boost::mutex> lock;
|
||||
typedef boost::mutex::scoped_lock lock;
|
||||
|
||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
|
||||
@@ -39,10 +38,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
int begin, end;
|
||||
std::vector<int>::size_type buffered;
|
||||
int begin, end, buffered;
|
||||
std::vector<int> circular_buf;
|
||||
boost::condition_variable_any buffer_not_full, buffer_not_empty;
|
||||
boost::condition buffer_not_full, buffer_not_empty;
|
||||
boost::mutex monitor;
|
||||
};
|
||||
|
||||
@@ -56,7 +54,7 @@ void sender() {
|
||||
buf.send(n);
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::unique_lock<boost::mutex> io_lock(io_mutex);
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
}
|
||||
++n;
|
||||
@@ -70,7 +68,7 @@ void receiver() {
|
||||
n = buf.receive();
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::unique_lock<boost::mutex> io_lock(io_mutex);
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
//#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
return 123;
|
||||
}
|
||||
|
||||
int p2(boost::future<int>& f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(&p1);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << f2.get() << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int p1() { return 5; }
|
||||
|
||||
boost::future<int> compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_future(0);
|
||||
if (x < 0) return boost::make_future(-1);
|
||||
//boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, p1);
|
||||
return boost::move(f1);
|
||||
}
|
||||
boost::shared_future<int> shared_compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_shared_future(0);
|
||||
if (x < 0) return boost::make_shared_future(-1);
|
||||
//boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
boost::shared_future<int> f1 = boost::async(p1).share();
|
||||
return boost::move(f1);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::future<int> f = compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
boost::shared_future<int> f = shared_compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -20,7 +20,7 @@ template <typename M>
|
||||
class buffer_t
|
||||
{
|
||||
public:
|
||||
typedef boost::unique_lock<M> scoped_lock;
|
||||
typedef typename M::scoped_lock scoped_lock;
|
||||
|
||||
buffer_t(int n)
|
||||
: p(0), c(0), full(0), buf(n)
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
for (int n = 0; n < ITERS; ++n)
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(io_mutex);
|
||||
boost::mutex::scoped_lock lock(io_mutex);
|
||||
std::cout << "sending: " << n << std::endl;
|
||||
}
|
||||
get_buffer().send(n);
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
{
|
||||
int n = get_buffer().receive();
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(io_mutex);
|
||||
boost::mutex::scoped_lock lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
|
||||
private:
|
||||
M mutex;
|
||||
boost::condition_variable_any cond;
|
||||
boost::condition cond;
|
||||
unsigned int p, c, full;
|
||||
std::vector<int> buf;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
counter() : count(0) { }
|
||||
|
||||
int increment() {
|
||||
boost::unique_lock<boost::mutex> scoped_lock(mutex);
|
||||
boost::mutex::scoped_lock scoped_lock(mutex);
|
||||
return ++count;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ counter c;
|
||||
void change_count()
|
||||
{
|
||||
int i = c.increment();
|
||||
boost::unique_lock<boost::mutex> scoped_lock(io_mutex);
|
||||
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
||||
std::cout << "count == " << i << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// (C) Copyright 2012 Howard Hinnant
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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)
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
|
||||
void use_cerr(boost::externally_locked_stream<std::ostream> &mcerr)
|
||||
{
|
||||
using namespace boost;
|
||||
auto tf = chrono::steady_clock::now() + chrono::seconds(10);
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
mcerr << "logging data to cerr\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
|
||||
void use_cout(boost::externally_locked_stream<std::ostream> &mcout)
|
||||
{
|
||||
using namespace boost;
|
||||
auto tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
mcout << "logging data to cout\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
recursive_mutex terminal_mutex;
|
||||
|
||||
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
|
||||
scoped_thread<> t1(thread(use_cerr, boost::ref(mcerr)));
|
||||
scoped_thread<> t2(thread(use_cout, boost::ref(mcout)));
|
||||
this_thread::sleep_for(chrono::seconds(2));
|
||||
std::string nm;
|
||||
{
|
||||
strict_lock<recursive_mutex> lk(terminal_mutex);
|
||||
auto& gcout = mcout.hold(lk);
|
||||
auto& gcin = mcin.hold(lk);
|
||||
gcout << "Enter name: ";
|
||||
//gcin >> nm;
|
||||
}
|
||||
t1.join();
|
||||
t2.join();
|
||||
mcout << nm << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
// (C) Copyright 2012 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)
|
||||
//
|
||||
// This performance test is based on the performance test provided by maxim.yegorushkin
|
||||
// at https://svn.boost.org/trac/boost/ticket/7422
|
||||
|
||||
#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/chrono/stopwatches/simple_stopwatch.hpp>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// class Stopwatch
|
||||
// {
|
||||
// public:
|
||||
// typedef long long rep;
|
||||
//
|
||||
// static rep now()
|
||||
// {
|
||||
// timespec ts;
|
||||
// if (clock_gettime(CLOCK_MONOTONIC, &ts)) abort();
|
||||
// return ts.tv_sec * rep(1000000000) + ts.tv_nsec;
|
||||
// }
|
||||
//
|
||||
// Stopwatch() :
|
||||
// start_(now())
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// rep elapsed() const
|
||||
// {
|
||||
// return now() - start_;
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// rep start_;
|
||||
// };
|
||||
|
||||
typedef boost::chrono::simple_stopwatch<> Stopwatch;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct BoostTypes
|
||||
{
|
||||
typedef boost::condition_variable condition_variable;
|
||||
typedef boost::mutex mutex;
|
||||
typedef boost::mutex::scoped_lock scoped_lock;
|
||||
};
|
||||
|
||||
struct StdTypes
|
||||
{
|
||||
typedef std::condition_variable condition_variable;
|
||||
typedef std::mutex mutex;
|
||||
typedef std::unique_lock<std::mutex> scoped_lock;
|
||||
};
|
||||
|
||||
template <class Types>
|
||||
struct SharedData: Types
|
||||
{
|
||||
unsigned const iterations;
|
||||
unsigned counter;
|
||||
unsigned semaphore;
|
||||
typename Types::condition_variable cnd;
|
||||
typename Types::mutex mtx;
|
||||
Stopwatch::rep producer_time;
|
||||
|
||||
SharedData(unsigned iterations, unsigned consumers) :
|
||||
iterations(iterations), counter(), semaphore(consumers) // Initialize to the number of consumers. (*)
|
||||
, producer_time()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class S>
|
||||
void producer_thread(S* shared_data)
|
||||
{
|
||||
Stopwatch sw;
|
||||
|
||||
unsigned const consumers = shared_data->semaphore; // (*)
|
||||
for (unsigned i = shared_data->iterations; i--;)
|
||||
{
|
||||
{
|
||||
typename S::scoped_lock lock(shared_data->mtx);
|
||||
// Wait till all consumers signal.
|
||||
while (consumers != shared_data->semaphore)
|
||||
{
|
||||
shared_data->cnd.wait(lock);
|
||||
}
|
||||
shared_data->semaphore = 0;
|
||||
// Signal consumers.
|
||||
++shared_data->counter;
|
||||
}
|
||||
shared_data->cnd.notify_all();
|
||||
}
|
||||
|
||||
shared_data->producer_time = sw.elapsed().count();
|
||||
}
|
||||
|
||||
template <class S>
|
||||
void consumer_thread(S* shared_data)
|
||||
{
|
||||
unsigned counter = 0;
|
||||
while (counter != shared_data->iterations)
|
||||
{
|
||||
{
|
||||
typename S::scoped_lock lock(shared_data->mtx);
|
||||
// Wait till the producer signals.
|
||||
while (counter == shared_data->counter)
|
||||
{
|
||||
shared_data->cnd.wait(lock);
|
||||
}
|
||||
counter = shared_data->counter;
|
||||
// Signal the producer.
|
||||
++shared_data->semaphore;
|
||||
}
|
||||
shared_data->cnd.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class Types>
|
||||
Stopwatch::rep benchmark_ping_pong(unsigned consumer_count)
|
||||
{
|
||||
typedef SharedData<Types> S;
|
||||
|
||||
auto best_producer_time = std::numeric_limits<Stopwatch::rep>::max();
|
||||
|
||||
std::vector<std::thread> consumers
|
||||
{ consumer_count };
|
||||
|
||||
// Run the benchmark 10 times and report the best time.
|
||||
for (int times = 10; times--;)
|
||||
{
|
||||
S shared_data
|
||||
{ 100000, consumer_count };
|
||||
|
||||
// Start the consumers.
|
||||
for (unsigned i = 0; i < consumer_count; ++i)
|
||||
consumers[i] = std::thread
|
||||
{ consumer_thread<S> , &shared_data };
|
||||
// Start the producer and wait till it finishes.
|
||||
std::thread
|
||||
{ producer_thread<S> , &shared_data }.join();
|
||||
// Wait till consumers finish.
|
||||
for (unsigned i = 0; i < consumer_count; ++i)
|
||||
consumers[i].join();
|
||||
|
||||
best_producer_time = std::min(best_producer_time, shared_data.producer_time);
|
||||
|
||||
}
|
||||
|
||||
return best_producer_time;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// sudo chrt -f 99 /usr/bin/time -f "\n***\ntime: %E\ncontext switches: %c\nwaits: %w" /home/max/otsquant/build/Linux-x86_64-64.g++-release/test/test
|
||||
|
||||
/*
|
||||
|
||||
Producer-consumer ping-pong tests. It aims to benchmark condition variables with and without
|
||||
thread cancellation support by comparing the time it took to complete the benchmark.
|
||||
|
||||
Condition variable with thread cancellation support is boost::condition_variable from
|
||||
boost-1.51. Without - std::condition_variable that comes with gcc-4.7.2.
|
||||
|
||||
One producer, one to CONSUMER_MAX consumers. The benchmark calls
|
||||
condition_variable::notify_all() without holding a mutex to maximize contention within this
|
||||
function. Each benchmark for a number of consumers is run three times and the best time is
|
||||
picked to get rid of outliers.
|
||||
|
||||
The results are reported for each benchmark for a number of consumers. The most important number
|
||||
is (std - boost) / std * 100. Positive numbers are when boost::condition_variable is faster,
|
||||
negative it is slower.
|
||||
|
||||
*/
|
||||
|
||||
int main()
|
||||
{
|
||||
std::printf("MAIN\n");
|
||||
enum
|
||||
{
|
||||
CONSUMER_MAX = 2
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
Stopwatch::rep boost, std;
|
||||
} best_times[CONSUMER_MAX] = {};
|
||||
|
||||
for (unsigned i = 1; i <= CONSUMER_MAX; ++i)
|
||||
{
|
||||
auto& b = best_times[i - 1];
|
||||
std::printf("STD: %d\n", i);
|
||||
b.std = benchmark_ping_pong<StdTypes> (i);
|
||||
std::printf("BOOST: %d\n", i);
|
||||
b.boost = benchmark_ping_pong<BoostTypes> (i);
|
||||
|
||||
std::printf("consumers: %4d\n", i);
|
||||
std::printf("best std producer time: %15.9fsec\n", b.std * 1e-9);
|
||||
std::printf("best boost producer time: %15.9fsec\n", b.boost * 1e-9);
|
||||
std::printf("(std - boost) / std: %7.2f%%\n", (b.std - b.boost) * 100. / b.std);
|
||||
}
|
||||
|
||||
printf("\ncsv:\n\n");
|
||||
printf("consumers,(std-boost)/std,std,boost\n");
|
||||
for (unsigned i = 1; i <= CONSUMER_MAX; ++i)
|
||||
{
|
||||
auto& b = best_times[i - 1];
|
||||
printf("%d,%f,%lld,%lld\n", i, (b.std - b.boost) * 100. / b.std, b.std, b.boost);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
@@ -14,12 +14,12 @@ public:
|
||||
counter() : count(0) { }
|
||||
|
||||
int add(int val) {
|
||||
boost::unique_lock<boost::recursive_mutex> scoped_lock(mutex);
|
||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||
count += val;
|
||||
return count;
|
||||
}
|
||||
int increment() {
|
||||
boost::unique_lock<boost::recursive_mutex> scoped_lock(mutex);
|
||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||
return add(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
// (C) Copyright 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 3
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
void do_something(int& i)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
int& i;
|
||||
|
||||
func(int& i_) :
|
||||
i(i_)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
for (unsigned j = 0; j < 1000000; ++j)
|
||||
{
|
||||
do_something(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void do_something_in_current_thread()
|
||||
{
|
||||
}
|
||||
|
||||
//void do_something_with_current_thread(boost::thread&& th)
|
||||
//{
|
||||
// th.join();
|
||||
//}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
int some_local_state;
|
||||
boost::strict_scoped_thread<> t( (boost::thread(func(some_local_state))));
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state;
|
||||
boost::thread t(( func(some_local_state) ));
|
||||
boost::strict_scoped_thread<> g( (boost::move(t)) );
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
// {
|
||||
// int some_local_state;
|
||||
// boost::thread t(( func(some_local_state) ));
|
||||
// boost::strict_scoped_thread<> g( (boost::move(t)) );
|
||||
//
|
||||
// do_something_in_current_thread();
|
||||
// do_something_with_current_thread(boost::thread(g));
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <iostream>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#if defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
#include <iostream>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <vector>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
// 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 BOOST_THREAD_VERSION 2
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -25,18 +23,18 @@ public:
|
||||
|
||||
void get(int id)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
while (m_chickens == 0)
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << id <<
|
||||
": wot, no chickens? I'll WAIT ..." << std::endl;
|
||||
}
|
||||
m_condition.wait(lock);
|
||||
}
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << id <<
|
||||
": those chickens look good ... one please ..." << std::endl;
|
||||
}
|
||||
@@ -44,20 +42,20 @@ public:
|
||||
}
|
||||
void put(int value)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(iomx);
|
||||
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_);
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 3;
|
||||
boost::thread::sleep(xt);
|
||||
m_chickens += value;
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() <<
|
||||
") Chef: more chickens ... " << m_chickens <<
|
||||
" now available ... NOTIFYING ..." << std::endl;
|
||||
@@ -77,21 +75,21 @@ void chef()
|
||||
{
|
||||
const int chickens = 4;
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
|
||||
}
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 2;
|
||||
boost::thread::sleep(xt);
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||
<< " chickens, ready-to-go ..." << std::endl;
|
||||
}
|
||||
@@ -104,7 +102,7 @@ struct phil
|
||||
phil(int id) : m_id(id) { }
|
||||
void run() {
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": starting ..." << std::endl;
|
||||
}
|
||||
@@ -113,18 +111,18 @@ struct phil
|
||||
if (m_id > 0)
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 3;
|
||||
boost::thread::sleep(xt);
|
||||
}
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": gotta eat ..." << std::endl;
|
||||
}
|
||||
g_canteen.get(m_id);
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(iomx);
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": mmm ... that's good ..." << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_traits.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
BOOST_STATIC_ASSERT(boost::is_strict_lock<boost::strict_lock<boost::mutex> >::value);
|
||||
BOOST_CONCEPT_ASSERT(( boost::BasicLockable<boost::mutex> ));
|
||||
BOOST_CONCEPT_ASSERT(( boost::StrictLock<boost::strict_lock<boost::mutex> > ));
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::mutex mtx;
|
||||
boost::strict_lock<boost::mutex> lk(mtx);
|
||||
std::cout << __FILE__ << std::endl;
|
||||
}
|
||||
{
|
||||
boost::timed_mutex mtx;
|
||||
boost::unique_lock<boost::timed_mutex> lk(mtx);
|
||||
boost::nested_strict_lock<boost::unique_lock<boost::timed_mutex> > nlk(lk);
|
||||
std::cout << __FILE__ << std::endl;
|
||||
}
|
||||
{
|
||||
boost::mutex mtx;
|
||||
boost::unique_lock<boost::mutex> lk(mtx, boost::defer_lock);
|
||||
boost::nested_strict_lock<boost::unique_lock<boost::mutex> > nlk(lk);
|
||||
std::cout << __FILE__ << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/thread/synchronized_value.hpp>
|
||||
|
||||
//class SafePerson {
|
||||
//public:
|
||||
// std::string GetName() const {
|
||||
// const_unique_access<std::string> name(nameGuard);
|
||||
// return *name;
|
||||
// }
|
||||
// void SetName(const std::string& newName) {
|
||||
// unique_access<std::string> name(nameGuard);
|
||||
// *name = newName;
|
||||
// }
|
||||
//private:
|
||||
// unique_access_guard<std::string> nameGuard;
|
||||
//};
|
||||
|
||||
class SafePerson {
|
||||
public:
|
||||
std::string GetName() const {
|
||||
return *name;
|
||||
}
|
||||
void SetName(const std::string& newName) {
|
||||
*name = newName;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::synchronized_value<std::string> name;
|
||||
};
|
||||
|
||||
class Person {
|
||||
public:
|
||||
std::string GetName() const {
|
||||
return name;
|
||||
}
|
||||
void SetName(const std::string& newName) {
|
||||
name = newName;
|
||||
}
|
||||
private:
|
||||
std::string name;
|
||||
};
|
||||
typedef boost::synchronized_value<Person> Person_ts;
|
||||
|
||||
|
||||
//class SafeMemberPerson {
|
||||
//public:
|
||||
// SafeMemberPerson(unsigned int age) :
|
||||
// memberGuard(age)
|
||||
// { }
|
||||
// std::string GetName() const {
|
||||
// const_unique_access<Member> member(memberGuard);
|
||||
// return member->name;
|
||||
// }
|
||||
// void SetName(const std::string& newName) {
|
||||
// unique_access<Member> member(memberGuard);
|
||||
// member->name = newName;
|
||||
// }
|
||||
//private:
|
||||
// struct Member
|
||||
// {
|
||||
// Member(unsigned int age) :
|
||||
// age(age)
|
||||
// { }
|
||||
// std::string name;
|
||||
// unsigned int age;
|
||||
// };
|
||||
// unique_access_guard<Member> memberGuard;
|
||||
//};
|
||||
|
||||
class SafeMemberPerson {
|
||||
public:
|
||||
SafeMemberPerson(unsigned int age) :
|
||||
member(Member(age))
|
||||
{ }
|
||||
std::string GetName() const {
|
||||
return member->name;
|
||||
}
|
||||
void SetName(const std::string& newName) {
|
||||
member->name = newName;
|
||||
}
|
||||
private:
|
||||
struct Member {
|
||||
Member(unsigned int age) :
|
||||
age(age)
|
||||
{ }
|
||||
std::string name;
|
||||
unsigned int age;
|
||||
};
|
||||
boost::synchronized_value<Member> member;
|
||||
};
|
||||
|
||||
|
||||
class Person2 {
|
||||
public:
|
||||
Person2(unsigned int age) : age_(age)
|
||||
{}
|
||||
std::string GetName() const {
|
||||
return name_;
|
||||
}
|
||||
void SetName(const std::string& newName) {
|
||||
name_ = newName;
|
||||
}
|
||||
unsigned int GetAge() const {
|
||||
return age_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned int age_;
|
||||
};
|
||||
typedef boost::synchronized_value<Person2> Person2_ts;
|
||||
|
||||
//===================
|
||||
|
||||
//class HelperPerson {
|
||||
//public:
|
||||
// HelperPerson(unsigned int age) :
|
||||
// memberGuard(age)
|
||||
// { }
|
||||
// std::string GetName() const {
|
||||
// const_unique_access<Member> member(memberGuard);
|
||||
// Invariant(member);
|
||||
// return member->name;
|
||||
// }
|
||||
// void SetName(const std::string& newName) {
|
||||
// unique_access<Member> member(memberGuard);
|
||||
// Invariant(member);
|
||||
// member->name = newName;
|
||||
// }
|
||||
//private:
|
||||
// void Invariant(const_unique_access<Member>& member) const {
|
||||
// if (member->age < 0) throw std::runtime_error("Age cannot be negative");
|
||||
// }
|
||||
// struct Member {
|
||||
// Member(unsigned int age) :
|
||||
// age(age)
|
||||
// { }
|
||||
// std::string name;
|
||||
// unsigned int age;
|
||||
// };
|
||||
// unique_access_guard<Member> memberGuard;
|
||||
//};
|
||||
|
||||
class HelperPerson {
|
||||
public:
|
||||
HelperPerson(unsigned int age) :
|
||||
member(age)
|
||||
{ }
|
||||
std::string GetName() const {
|
||||
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
||||
auto memberSync = member.synchronize();
|
||||
#else
|
||||
boost::const_strict_lock_ptr<Member> memberSync = member.synchronize();
|
||||
#endif
|
||||
Invariant(memberSync);
|
||||
return memberSync->name;
|
||||
}
|
||||
void SetName(const std::string& newName) {
|
||||
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
||||
auto memberSync = member.synchronize();
|
||||
#else
|
||||
boost::strict_lock_ptr<Member> memberSync = member.synchronize();
|
||||
#endif
|
||||
Invariant(memberSync);
|
||||
memberSync->name = newName;
|
||||
}
|
||||
private:
|
||||
struct Member {
|
||||
Member(unsigned int age) :
|
||||
age(age)
|
||||
{ }
|
||||
std::string name;
|
||||
unsigned int age;
|
||||
};
|
||||
void Invariant(boost::const_strict_lock_ptr<Member> & mbr) const
|
||||
{
|
||||
if (mbr->age < 1) throw std::runtime_error("Age cannot be negative");
|
||||
}
|
||||
boost::synchronized_value<Member> member;
|
||||
};
|
||||
|
||||
class Person3 {
|
||||
public:
|
||||
Person3(unsigned int age) :
|
||||
age_(age)
|
||||
{ }
|
||||
std::string GetName() const {
|
||||
Invariant();
|
||||
return name_;
|
||||
}
|
||||
void SetName(const std::string& newName) {
|
||||
Invariant();
|
||||
name_ = newName;
|
||||
}
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned int age_;
|
||||
void Invariant() const {
|
||||
if (age_ < 1) throw std::runtime_error("Age cannot be negative");
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::synchronized_value<Person3> Person3_ts;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
SafePerson p;
|
||||
p.SetName("Vicente");
|
||||
}
|
||||
{
|
||||
Person_ts p;
|
||||
p->SetName("Vicente");
|
||||
}
|
||||
{
|
||||
SafeMemberPerson p(1);
|
||||
p.SetName("Vicente");
|
||||
}
|
||||
{
|
||||
Person2_ts p(1);
|
||||
p->SetName("Vicente");
|
||||
}
|
||||
{
|
||||
HelperPerson p(1);
|
||||
p.SetName("Vicente");
|
||||
}
|
||||
{
|
||||
Person3_ts p(1);
|
||||
p->SetName("Vicente");
|
||||
}
|
||||
{
|
||||
Person3_ts p1(1);
|
||||
Person3_ts p2(2);
|
||||
Person3_ts p3(3);
|
||||
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
||||
auto lk1 = p1.unique_synchronize(boost::defer_lock);
|
||||
auto lk2 = p2.unique_synchronize(boost::defer_lock);
|
||||
auto lk3 = p3.unique_synchronize(boost::defer_lock);
|
||||
#else
|
||||
boost::unique_lock_ptr<Person3> lk1 = p1.unique_synchronize(boost::defer_lock);
|
||||
boost::unique_lock_ptr<Person3> lk2 = p2.unique_synchronize(boost::defer_lock);
|
||||
boost::unique_lock_ptr<Person3> lk3 = p3.unique_synchronize(boost::defer_lock);
|
||||
#endif
|
||||
boost::lock(lk1,lk2,lk3);
|
||||
|
||||
lk1->SetName("Carmen");
|
||||
lk2->SetName("Javier");
|
||||
lk3->SetName("Matias");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
// (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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 BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/thread/synchronized_value.hpp>
|
||||
|
||||
void addTrailingSlashIfMissing(boost::synchronized_value<std::string> & path)
|
||||
{
|
||||
boost::strict_lock_ptr<std::string> u=path.synchronize();
|
||||
|
||||
if(u->empty() || (*u->rbegin()!='/'))
|
||||
{
|
||||
*u+='/';
|
||||
}
|
||||
}
|
||||
|
||||
void f(const boost::synchronized_value<int> &v) {
|
||||
std::cout<<"v="<<*v<<std::endl;
|
||||
}
|
||||
|
||||
void g(const boost::const_strict_lock_ptr<int> &v) {
|
||||
std::cout<<"v="<<*v<<std::endl;
|
||||
}
|
||||
|
||||
bool checkIfMissingTrailingSlash(boost::synchronized_value<std::string> & path)
|
||||
{
|
||||
boost::strict_lock_ptr<std::string> u=path.synchronize();
|
||||
|
||||
return (u->empty() || (*u->rbegin()!='/'));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::synchronized_value<int> v1;
|
||||
*v1=42;
|
||||
std::cout<<"v1="<<*v1<<std::endl;
|
||||
f(v1);
|
||||
int i=*v1;
|
||||
std::cout<<"i="<<i<<std::endl;
|
||||
|
||||
{
|
||||
boost::strict_lock_ptr<int> u=v1.synchronize();
|
||||
|
||||
*u+=43;
|
||||
std::cout<<"v1="<<*u<<std::endl;
|
||||
g(u);
|
||||
}
|
||||
boost::synchronized_value<int> v2(2);
|
||||
std::cout<<"v2="<<*v2<<std::endl;
|
||||
v2 = 3;
|
||||
std::cout<<"v2="<<*v2<<std::endl;
|
||||
|
||||
boost::synchronized_value<int> v3(v2);
|
||||
std::cout<<"v3="<<*v3<<std::endl;
|
||||
v3 = v1;
|
||||
std::cout<<"v3="<<*v3<<std::endl;
|
||||
|
||||
std::cout<<"v2="<<*v3<<std::endl;
|
||||
std::cout<<"v3="<<*v3<<std::endl;
|
||||
swap(v3,v2);
|
||||
v1.swap(v2);
|
||||
std::cout<<"v3="<<*v3<<std::endl;
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<std::string> s;
|
||||
addTrailingSlashIfMissing(s);
|
||||
std::cout<<"s="<<std::string(*s)<<std::endl;
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<std::string> s;
|
||||
s->append("foo/");
|
||||
s.synchronize()->append("foo");
|
||||
addTrailingSlashIfMissing(s);
|
||||
std::cout<<"s="<<std::string(*s)<<std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
@@ -41,7 +41,7 @@ char* player_name(int state)
|
||||
|
||||
void player(void* param)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
|
||||
int active = (int)param;
|
||||
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
|
||||
@@ -104,11 +104,11 @@ int main(int argc, char* argv[])
|
||||
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
|
||||
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "---Noise ON..." << std::endl;
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ int main(int argc, char* argv[])
|
||||
cond.notify_all();
|
||||
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "---Noise OFF..." << std::endl;
|
||||
state = GAME_OVER;
|
||||
cond.notify_all();
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
// 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 BOOST_THREAD_VERSION 2
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
@@ -16,7 +14,7 @@ struct thread_alarm
|
||||
void operator()()
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += m_secs;
|
||||
|
||||
boost::thread::sleep(xt);
|
||||
|
||||
@@ -6,67 +6,20 @@
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
int count = 0;
|
||||
boost::mutex mutex;
|
||||
|
||||
void increment_count()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
std::cout << "count = " << ++count << std::endl;
|
||||
}
|
||||
|
||||
boost::thread_group threads2;
|
||||
boost::thread* th2 = 0;
|
||||
|
||||
void increment_count_2()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
BOOST_TEST(threads2.is_this_thread_in());
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "count = " << ++count << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
for (int i = 0; i < 10; ++i)
|
||||
threads.create_thread(&increment_count);
|
||||
threads.join_all();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
threads.create_thread(&increment_count);
|
||||
threads.interrupt_all();
|
||||
threads.join_all();
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::thread_group threads;
|
||||
boost::thread* th = new boost::thread(&increment_count);
|
||||
threads.add_thread(th);
|
||||
BOOST_TEST(! threads.is_this_thread_in());
|
||||
threads.join_all();
|
||||
}
|
||||
{
|
||||
boost::thread_group threads;
|
||||
boost::thread* th = new boost::thread(&increment_count);
|
||||
threads.add_thread(th);
|
||||
BOOST_TEST(threads.is_thread_in(th));
|
||||
threads.remove_thread(th);
|
||||
BOOST_TEST(! threads.is_thread_in(th));
|
||||
th->join();
|
||||
}
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
boost::thread* th2 = new boost::thread(&increment_count_2);
|
||||
threads2.add_thread(th2);
|
||||
}
|
||||
threads2.join_all();
|
||||
}
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// (C) Copyright 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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 <string>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_guard.hpp>
|
||||
|
||||
void do_something(int& i)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
int& i;
|
||||
|
||||
func(int& i_):i(i_){}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
for(unsigned j=0;j<1000000;++j)
|
||||
{
|
||||
do_something(i);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
func& operator=(func const&);
|
||||
|
||||
};
|
||||
|
||||
void do_something_in_current_thread()
|
||||
{}
|
||||
|
||||
|
||||
void f()
|
||||
{
|
||||
int some_local_state;
|
||||
func my_func(some_local_state);
|
||||
boost::thread t(my_func);
|
||||
boost::thread_guard<> g(t);
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
f();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
// 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 BOOST_THREAD_VERSION 2
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt); // Sleep for 1 second
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
@@ -34,7 +33,7 @@ namespace boost
|
||||
|
||||
bool wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_HPP
|
||||
#define BOOST_THREAD_CONDITION_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (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)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_CONDITION
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -18,4 +14,3 @@ namespace boost
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
// Copyright (C) 2012 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)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
// The async_func code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
#define BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/utility/result_of.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
template <class Fp, class... Args>
|
||||
class async_func
|
||||
{
|
||||
std::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
|
||||
typedef typename result_of<Fp(Args...)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(Fp&& f, Args&&... args)
|
||||
: f_(boost::move(f), boost::move(args)...) {}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(async_func&& f) : f_(boost::move(f.f_)) {}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index;
|
||||
return execute(Index());
|
||||
}
|
||||
private:
|
||||
template <size_t ...Indices>
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke(boost::move(std::get<0>(f_)), boost::move(std::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
#else
|
||||
template <class Fp>
|
||||
class async_func
|
||||
{
|
||||
Fp f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func)
|
||||
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
: f_(boost::move(f)) {}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_FWD_REF(async_func) f) : f_(boost::move(f.f_)) {}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return execute();
|
||||
}
|
||||
private:
|
||||
result_type
|
||||
execute()
|
||||
{
|
||||
return f_();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -8,283 +8,120 @@
|
||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
|
||||
// Force SIG_ATOMIC_MAX to be defined
|
||||
//#ifndef __STDC_LIMIT_MACROS
|
||||
//#define __STDC_LIMIT_MACROS
|
||||
//#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if ! defined BOOST_THREAD_NOEXCEPT_OR_THROW
|
||||
#ifdef BOOST_NO_CXX11_NOEXCEPT
|
||||
# define BOOST_THREAD_NOEXCEPT_OR_THROW throw()
|
||||
#else
|
||||
# define BOOST_THREAD_NOEXCEPT_OR_THROW noexcept
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \
|
||||
if (EXPR) {} else boost::throw_exception(EX)
|
||||
#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \
|
||||
if (EXPR) {} else boost::throw_exception(EX)
|
||||
#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \
|
||||
boost::throw_exception(EX)
|
||||
#else
|
||||
#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX)
|
||||
#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \
|
||||
(void)(EXPR)
|
||||
#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \
|
||||
return (RET)
|
||||
#endif
|
||||
|
||||
// This compiler doesn't support Boost.Chrono
|
||||
#if defined __IBMCPP__ && (__IBMCPP__ < 1100) \
|
||||
&& ! defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#if defined __IBMCPP__ && (__IBMCPP__ < 1100)
|
||||
#define BOOST_THREAD_DONT_USE_CHRONO
|
||||
#if ! defined BOOST_THREAD_USE_DATE
|
||||
#define BOOST_THREAD_USE_DATE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This compiler doesn't support Boost.Move
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) \
|
||||
&& ! defined BOOST_THREAD_DONT_USE_MOVE
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
#define BOOST_THREAD_DONT_USE_MOVE
|
||||
#endif
|
||||
|
||||
// This compiler doesn't support Boost.Container Allocators files
|
||||
#if defined __SUNPRO_CC \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#if defined __SUNPRO_CC
|
||||
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
|
||||
#if defined _WIN32_WCE && _WIN32_WCE==0x501 \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#if defined _WIN32_WCE && _WIN32_WCE==0x501
|
||||
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
|
||||
|
||||
#if defined BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX || defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
#define BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
#define BOOST_THREAD_NO_MAKE_LOCK_GUARD
|
||||
#define BOOST_THREAD_NO_MAKE_STRICT_LOCK
|
||||
#define BOOST_THREAD_NO_MAKE_NESTED_STRICT_LOCK
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS
|
||||
#elif defined _MSC_VER && _MSC_VER <= 1600
|
||||
// C++ features supported by VC++ 10 (aka 2010)
|
||||
#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS
|
||||
#endif
|
||||
|
||||
/// BASIC_THREAD_ID
|
||||
// todo to be removed for 1.54
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID
|
||||
#define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#endif
|
||||
|
||||
/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
|
||||
#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
|
||||
#endif
|
||||
|
||||
// Default version
|
||||
// Default version is 2
|
||||
#if !defined BOOST_THREAD_VERSION
|
||||
#define BOOST_THREAD_VERSION 2
|
||||
#else
|
||||
#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 && BOOST_THREAD_VERSION!=4
|
||||
#error "BOOST_THREAD_VERSION must be 2, 3 or 4"
|
||||
#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3
|
||||
#error "BOOST_THREAD_VERSION must be 2 or 3"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// CHRONO
|
||||
// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO
|
||||
#if ! defined BOOST_THREAD_DONT_USE_CHRONO \
|
||||
&& ! defined BOOST_THREAD_USES_CHRONO
|
||||
// Uses Boost.System by default if not stated the opposite defining BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#if ! defined BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#define BOOST_THREAD_USES_SYSTEM
|
||||
#endif
|
||||
|
||||
// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO or BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#define BOOST_THREAD_USES_CHRONO
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION==2
|
||||
|
||||
// PROVIDE_PROMISE_LAZY
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
|
||||
#define BOOST_THREAD_PROVIDES_PROMISE_LAZY
|
||||
#endif
|
||||
|
||||
// PROVIDE_THREAD_EQ
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_EQ \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION>=3
|
||||
|
||||
// ONCE_CXX11
|
||||
// fixme BOOST_THREAD_PROVIDES_ONCE_CXX11 doesn't works when thread.cpp is compiled BOOST_THREAD_VERSION 3
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#define BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11
|
||||
#endif
|
||||
|
||||
// THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#endif
|
||||
|
||||
// THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#endif
|
||||
|
||||
// PROVIDE_FUTURE
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_FUTURE
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE
|
||||
#endif
|
||||
|
||||
// FUTURE_CTOR_ALLOCATORS
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
|
||||
// SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#endif
|
||||
|
||||
// PROVIDE_EXPLICIT_LOCK_CONVERSION
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#endif
|
||||
|
||||
// GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#endif
|
||||
|
||||
// USE_MOVE
|
||||
#if ! defined BOOST_THREAD_DONT_USE_MOVE \
|
||||
&& ! defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_USES_MOVE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// deprecated since version 4
|
||||
#if BOOST_THREAD_VERSION < 4
|
||||
|
||||
// NESTED_LOCKS
|
||||
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS
|
||||
#define BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
#endif
|
||||
|
||||
// CONDITION
|
||||
#if ! defined BOOST_THREAD_PROVIDES_CONDITION \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION
|
||||
#define BOOST_THREAD_PROVIDES_CONDITION
|
||||
#endif
|
||||
|
||||
// USE_DATETIME
|
||||
#if ! defined BOOST_THREAD_DONT_USE_DATETIME \
|
||||
&& ! defined BOOST_THREAD_USES_DATETIME
|
||||
#define BOOST_THREAD_USES_DATETIME
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION>=4
|
||||
|
||||
// SIGNATURE_PACKAGED_TASK
|
||||
#if ! defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK
|
||||
#define BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
|
||||
#endif
|
||||
|
||||
// VARIADIC_THREAD
|
||||
#if ! defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD
|
||||
|
||||
#if ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// FUTURE_CONTINUATION
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
#endif
|
||||
|
||||
// FUTURE_INVALID_AFTER_GET
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
|
||||
#endif
|
||||
|
||||
// NESTED_LOCKS
|
||||
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS
|
||||
#define BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS
|
||||
#endif
|
||||
|
||||
// CONDITION
|
||||
#if ! defined BOOST_THREAD_PROVIDES_CONDITION \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION
|
||||
#define BOOST_THREAD_DONT_PROVIDE_CONDITION
|
||||
#endif
|
||||
|
||||
#endif // BOOST_THREAD_VERSION>=4
|
||||
|
||||
// INTERRUPTIONS
|
||||
#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#endif
|
||||
|
||||
// CORRELATIONS
|
||||
|
||||
// EXPLICIT_LOCK_CONVERSION.
|
||||
// Don't provided by default in version 1.
|
||||
#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit
|
||||
#else
|
||||
#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION
|
||||
#endif
|
||||
|
||||
|
||||
// Uses Boost.Move by default if not stated the opposite defining BOOST_THREAD_DONT_USE_MOVE
|
||||
#if ! defined BOOST_THREAD_DONT_USE_MOVE
|
||||
#if ! defined BOOST_THREAD_USES_MOVE
|
||||
//#define BOOST_THREAD_USES_MOVE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION==2
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY
|
||||
#define BOOST_THREAD_PROMISE_LAZY
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION==3
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11
|
||||
#define BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION
|
||||
#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_USE_MOVE
|
||||
#if ! defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_USES_MOVE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \
|
||||
&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#endif
|
||||
|
||||
// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52
|
||||
// BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
|
||||
#if ! defined BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
@@ -294,18 +131,11 @@
|
||||
# pragma warn -8066 // Unreachable code
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#else
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP) || defined(BOOST_HAS_NANOSLEEP)
|
||||
# define BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
# endif
|
||||
#endif
|
||||
#include "platform.hpp"
|
||||
|
||||
// provided for backwards compatibility, since this
|
||||
// macro was used for several releases by mistake.
|
||||
#if defined(BOOST_THREAD_DYN_DLL) && ! defined BOOST_THREAD_DYN_LINK
|
||||
#if defined(BOOST_THREAD_DYN_DLL)
|
||||
# define BOOST_THREAD_DYN_LINK
|
||||
#endif
|
||||
|
||||
|
||||
@@ -8,21 +8,14 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
/**
|
||||
* BOOST_THREAD_DELETE_COPY_CTOR deletes the copy constructor when the compiler supports it or
|
||||
* makes it private.
|
||||
*
|
||||
* BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or
|
||||
* makes it private.
|
||||
*/
|
||||
#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#ifndef BOOST_NO_DELETED_FUNCTIONS
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
CLASS(CLASS const&) = delete; \
|
||||
|
||||
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
|
||||
CLASS& operator=(CLASS const&) = delete;
|
||||
|
||||
#else // BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#else // BOOST_NO_DELETED_FUNCTIONS
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
private: \
|
||||
CLASS(CLASS&); \
|
||||
@@ -32,12 +25,8 @@
|
||||
private: \
|
||||
CLASS& operator=(CLASS&); \
|
||||
public:
|
||||
#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#endif // BOOST_NO_DELETED_FUNCTIONS
|
||||
|
||||
/**
|
||||
* BOOST_THREAD_NO_COPYABLE deletes the copy constructor and assignment when the compiler supports it or
|
||||
* makes them private.
|
||||
*/
|
||||
#define BOOST_THREAD_NO_COPYABLE(CLASS) \
|
||||
BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS)
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (C) 2012 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)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
// The invoke code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_INVOKE_HPP
|
||||
#define BOOST_THREAD_DETAIL_INVOKE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
// // bullets 1 and 2
|
||||
|
||||
template <class Fp, class A0, class ...Args>
|
||||
inline
|
||||
auto
|
||||
invoke(Fp&& f, A0&& a0, Args&& ...args)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Fp, class A0, class ...Args>
|
||||
inline
|
||||
auto
|
||||
invoke(Fp&& f, A0&& a0, Args&& ...args)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// bullets 3 and 4
|
||||
|
||||
template <class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(Fp&& f, A0&& a0)
|
||||
-> decltype(boost::forward<A0>(a0).*f)
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
|
||||
template <class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(Fp&& f, A0&& a0)
|
||||
-> decltype((*boost::forward<A0>(a0)).*f)
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
// bullet 5
|
||||
|
||||
template <class Fp, class ...Args>
|
||||
inline
|
||||
auto invoke(Fp&& f, Args&& ...args)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -1,48 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP
|
||||
#define BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP
|
||||
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
template <typename T1, typename T2>
|
||||
struct is_convertible : boost::is_convertible<T1,T2> {};
|
||||
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
#if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION <= 1300)
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
template <typename T1, typename T2>
|
||||
struct is_convertible<
|
||||
rv<T1> &,
|
||||
rv<rv<T2> > &
|
||||
> : false_type {};
|
||||
#endif
|
||||
|
||||
#elif defined __GNUC__ && (__GNUC__ < 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ <= 4 ))
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct is_convertible<T1&, T2&> : boost::is_convertible<T1, T2> {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
@@ -1,45 +0,0 @@
|
||||
// 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 2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP
|
||||
#define BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
#include <initializer_list>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
namespace thread_detail
|
||||
{
|
||||
template <typename Mutex>
|
||||
struct lockable_wrapper
|
||||
{
|
||||
Mutex* m;
|
||||
explicit lockable_wrapper(Mutex& m_) :
|
||||
m(&m_)
|
||||
{}
|
||||
};
|
||||
template <typename Mutex>
|
||||
struct lockable_adopt_wrapper
|
||||
{
|
||||
Mutex* m;
|
||||
explicit lockable_adopt_wrapper(Mutex& m_) :
|
||||
m(&m_)
|
||||
{}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -1,83 +0,0 @@
|
||||
// Copyright (C) 2012 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)
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_LOG_HPP
|
||||
#define BOOST_THREAD_DETAIL_LOG_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_USES_LOG
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/thread.hpp>
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
inline boost::recursive_mutex& terminal_mutex()
|
||||
{
|
||||
static boost::recursive_mutex mtx;
|
||||
return mtx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#define BOOST_THREAD_LOG \
|
||||
{ \
|
||||
boost::lock_guard<boost::recursive_mutex> _lk_(boost::thread_detail::terminal_mutex()); \
|
||||
std::cout << boost::this_thread::get_id() << " - "<<__FILE__<<"["<<__LINE__<<"] " <<std::dec
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_LOG \
|
||||
{ \
|
||||
boost::lock_guard<boost::recursive_mutex> _lk_(boost::thread_detail::terminal_mutex()); \
|
||||
std::cout << __FILE__<<"["<<__LINE__<<"] " <<std::dec
|
||||
|
||||
#endif
|
||||
#define BOOST_THREAD_END_LOG \
|
||||
std::dec << std::endl; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
struct dummy_stream_t
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline dummy_stream_t const& operator<<(dummy_stream_t const& os, T)
|
||||
{
|
||||
return os;
|
||||
}
|
||||
|
||||
inline dummy_stream_t const& operator<<(dummy_stream_t const& os, dummy_stream_t const&)
|
||||
{
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST dummy_stream_t dummy_stream = {};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_THREAD_LOG if (true) {} else boost::thread_detail::dummy_stream
|
||||
#define BOOST_THREAD_END_LOG boost::thread_detail::dummy_stream
|
||||
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_TRACE BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
|
||||
|
||||
#endif // header
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright (C) 2012 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)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
// The make_tuple_indices code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP
|
||||
#define BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
// make_tuple_indices
|
||||
|
||||
template <std::size_t...> struct tuple_indices
|
||||
{};
|
||||
|
||||
template <std::size_t Sp, class IntTuple, std::size_t Ep>
|
||||
struct make_indices_imp;
|
||||
|
||||
template <std::size_t Sp, std::size_t ...Indices, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<Indices...>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<Indices..., Sp>, Ep>::type type;
|
||||
};
|
||||
|
||||
template <std::size_t Ep, std::size_t ...Indices>
|
||||
struct make_indices_imp<Ep, tuple_indices<Indices...>, Ep>
|
||||
{
|
||||
typedef tuple_indices<Indices...> type;
|
||||
};
|
||||
|
||||
template <std::size_t Ep, std::size_t Sp = 0>
|
||||
struct make_tuple_indices
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error");
|
||||
typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -11,15 +11,9 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
#define BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -33,7 +27,7 @@ namespace boost
|
||||
typedef typename alloc_traits::pointer pointer;
|
||||
typedef typename alloc_traits::size_type size_type;
|
||||
private:
|
||||
_Alloc alloc_;
|
||||
_Alloc& alloc_;
|
||||
size_type s_;
|
||||
public:
|
||||
allocator_destructor(_Alloc& a, size_type s)BOOST_NOEXCEPT
|
||||
@@ -41,115 +35,19 @@ namespace boost
|
||||
{}
|
||||
void operator()(pointer p)BOOST_NOEXCEPT
|
||||
{
|
||||
alloc_traits::destroy(alloc_, p);
|
||||
alloc_traits::deallocate(alloc_, p, s_);
|
||||
}
|
||||
};
|
||||
} //namespace thread_detail
|
||||
|
||||
typedef container::allocator_arg_t allocator_arg_t;
|
||||
BOOST_CONSTEXPR_OR_CONST allocator_arg_t allocator_arg = {};
|
||||
BOOST_CONSTEXPR allocator_arg_t allocator_arg = {};
|
||||
|
||||
template <class T, class Alloc>
|
||||
struct uses_allocator: public container::uses_allocator<T, Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Ptr>
|
||||
struct pointer_traits
|
||||
{
|
||||
typedef Ptr pointer;
|
||||
// typedef <details> element_type;
|
||||
// typedef <details> difference_type;
|
||||
|
||||
// template <class U> using rebind = <details>;
|
||||
//
|
||||
// static pointer pointer_to(<details>);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct pointer_traits<T*>
|
||||
{
|
||||
typedef T* pointer;
|
||||
typedef T element_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
// template <class U> using rebind = U*;
|
||||
//
|
||||
// static pointer pointer_to(<details>) noexcept;
|
||||
};
|
||||
|
||||
|
||||
namespace thread_detail {
|
||||
template <class _Ptr1, class _Ptr2,
|
||||
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
|
||||
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
|
||||
>::value
|
||||
>
|
||||
struct same_or_less_cv_qualified_imp
|
||||
: is_convertible<_Ptr1, _Ptr2> {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
|
||||
: false_type {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
|
||||
!is_pointer<_Ptr1>::value>
|
||||
struct same_or_less_cv_qualified
|
||||
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2> {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
|
||||
: false_type {};
|
||||
|
||||
}
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U>&,
|
||||
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (T* ptr) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U[]>&,
|
||||
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (U* ptr,
|
||||
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete [] ptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/move/utility.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -26,7 +26,7 @@ namespace boost
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct enable_move_utility_emulation_dummy_specialization;
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization;
|
||||
template<typename T>
|
||||
struct thread_move_t
|
||||
{
|
||||
@@ -49,7 +49,6 @@ namespace boost
|
||||
};
|
||||
}
|
||||
|
||||
#if !defined BOOST_THREAD_USES_MOVE
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename T>
|
||||
@@ -64,14 +63,11 @@ namespace boost
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
#endif //#if !defined BOOST_THREAD_USES_MOVE
|
||||
}
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if ! defined BOOST_NO_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
|
||||
#define BOOST_THREAD_RV(V) V
|
||||
@@ -81,17 +77,16 @@ namespace boost
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, false> \
|
||||
: integral_constant<bool, true> \
|
||||
{}; \
|
||||
}
|
||||
|
||||
#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_MSVC
|
||||
#elif ! defined BOOST_NO_RVALUE_REFERENCES && defined BOOST_MSVC
|
||||
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
|
||||
#define BOOST_THREAD_RV(V) V
|
||||
@@ -101,10 +96,10 @@ namespace boost
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, false> \
|
||||
: integral_constant<bool, true> \
|
||||
{}; \
|
||||
}
|
||||
|
||||
@@ -112,7 +107,6 @@ namespace boost
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
|
||||
#define BOOST_THREAD_RV(V) V
|
||||
@@ -121,10 +115,10 @@ namespace boost
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, false> \
|
||||
: integral_constant<bool, true> \
|
||||
{}; \
|
||||
}
|
||||
|
||||
@@ -138,19 +132,17 @@ namespace boost
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE(TYPE) \
|
||||
template <> \
|
||||
struct enable_move_utility_emulation< TYPE > \
|
||||
{ \
|
||||
static const bool value = false; \
|
||||
};
|
||||
struct has_move_emulation_enabled_aux< TYPE > \
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \
|
||||
{};
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation<
|
||||
struct has_move_emulation_enabled_aux<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
{ \
|
||||
static const bool value = false; \
|
||||
};
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \
|
||||
{};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -184,7 +176,7 @@ namespace detail
|
||||
#endif
|
||||
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if ! defined BOOST_NO_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE)
|
||||
|
||||
@@ -235,26 +227,19 @@ namespace detail
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
namespace boost
|
||||
{ namespace thread_detail
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
decay_copy(T&& t)
|
||||
{
|
||||
return boost::forward<T>(t);
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
decay_copy(BOOST_THREAD_FWD_REF(T) t)
|
||||
{
|
||||
return boost::forward<T>(t);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// choose platform
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define BOOST_THREAD_LINUX
|
||||
//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000)
|
||||
# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
# define BOOST_THREAD_BSD
|
||||
#elif defined(sun) || defined(__sun)
|
||||
@@ -36,7 +36,7 @@
|
||||
# define BOOST_THREAD_BEOS
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_MACOS
|
||||
//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000)
|
||||
# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000)
|
||||
#elif defined(__IBMCPP__) || defined(_AIX)
|
||||
# define BOOST_THREAD_AIX
|
||||
#elif defined(__amigaos__)
|
||||
|
||||
@@ -3,24 +3,18 @@
|
||||
// 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-2010 Anthony Williams
|
||||
// (C) Copyright 20011-2012 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2007-10 Anthony Williams
|
||||
// (C) Copyright 20011-12 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
#include <ostream>
|
||||
#endif
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/thread/detail/is_convertible.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
@@ -40,9 +34,6 @@
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#include <tuple>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
@@ -55,45 +46,13 @@ namespace boost
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
template<typename F, class ...ArgTypes>
|
||||
class thread_data:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_):
|
||||
fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...)
|
||||
{}
|
||||
#endif
|
||||
template <std::size_t ...Indices>
|
||||
void run2(tuple_indices<Indices...>)
|
||||
{
|
||||
|
||||
invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
|
||||
}
|
||||
void run()
|
||||
{
|
||||
typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type;
|
||||
|
||||
run2(index_type());
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp;
|
||||
};
|
||||
#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
template<typename F>
|
||||
class thread_data:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
thread_data(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(boost::forward<F>(f_))
|
||||
{}
|
||||
@@ -110,13 +69,10 @@ namespace boost
|
||||
f(f_)
|
||||
{}
|
||||
#endif
|
||||
//thread_data() {}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
|
||||
private:
|
||||
F f;
|
||||
};
|
||||
@@ -154,7 +110,6 @@ namespace boost
|
||||
f();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
class BOOST_THREAD_DECL thread
|
||||
@@ -165,55 +120,24 @@ namespace boost
|
||||
BOOST_THREAD_MOVABLE_ONLY(thread)
|
||||
private:
|
||||
|
||||
struct dummy;
|
||||
|
||||
void release_handle();
|
||||
|
||||
detail::thread_data_ptr thread_info;
|
||||
|
||||
private:
|
||||
bool start_thread_noexcept();
|
||||
bool start_thread_noexcept(const attributes& attr);
|
||||
public:
|
||||
void start_thread()
|
||||
{
|
||||
if (!start_thread_noexcept())
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
}
|
||||
void start_thread(const attributes& attr)
|
||||
{
|
||||
if (!start_thread_noexcept(attr))
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
}
|
||||
void start_thread();
|
||||
void start_thread(const attributes& attr);
|
||||
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
template<typename F, class ...ArgTypes>
|
||||
static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<
|
||||
detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...>
|
||||
>(
|
||||
boost::forward<F>(f), boost::forward<ArgTypes>(args)...
|
||||
)
|
||||
);
|
||||
}
|
||||
#else
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
|
||||
boost::forward<F>(f)));
|
||||
}
|
||||
#endif
|
||||
static inline detail::thread_data_ptr make_thread_info(void (*f)())
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
|
||||
@@ -221,12 +145,7 @@ namespace boost
|
||||
}
|
||||
#else
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F f
|
||||
, typename disable_if_c<
|
||||
//boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value ||
|
||||
is_same<typename decay<F>::type, thread>::value,
|
||||
dummy* >::type=0
|
||||
)
|
||||
static inline detail::thread_data_ptr make_thread_info(F f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
|
||||
}
|
||||
@@ -237,6 +156,7 @@ namespace boost
|
||||
}
|
||||
|
||||
#endif
|
||||
struct dummy;
|
||||
public:
|
||||
#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
@@ -246,7 +166,6 @@ namespace boost
|
||||
thread() BOOST_NOEXCEPT;
|
||||
~thread()
|
||||
{
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
if (joinable()) {
|
||||
std::terminate();
|
||||
@@ -255,12 +174,12 @@ namespace boost
|
||||
detach();
|
||||
#endif
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template <
|
||||
class F
|
||||
>
|
||||
explicit thread(BOOST_THREAD_RV_REF(F) f
|
||||
//, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
|
||||
, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
|
||||
):
|
||||
thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{
|
||||
@@ -269,7 +188,7 @@ namespace boost
|
||||
template <
|
||||
class F
|
||||
>
|
||||
thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f):
|
||||
thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f):
|
||||
thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{
|
||||
start_thread(attrs);
|
||||
@@ -284,7 +203,7 @@ namespace boost
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(attributes const& attrs, F f):
|
||||
thread(attributes& attrs, F f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread(attrs);
|
||||
@@ -292,19 +211,15 @@ namespace boost
|
||||
#else
|
||||
template <class F>
|
||||
explicit thread(F f
|
||||
, typename disable_if_c<
|
||||
boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
|
||||
//|| is_same<typename decay<F>::type, thread>::value
|
||||
, dummy* >::type=0
|
||||
):
|
||||
// todo Disable also if Or is_same<typename decay<F>::type, thread>
|
||||
, typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(attributes const& attrs, F f
|
||||
, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
|
||||
):
|
||||
thread(attributes& attrs, F f
|
||||
, typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread(attrs);
|
||||
@@ -314,22 +229,14 @@ namespace boost
|
||||
explicit thread(BOOST_THREAD_RV_REF(F) f
|
||||
, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
|
||||
):
|
||||
#ifdef BOOST_THREAD_USES_MOVE
|
||||
thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
|
||||
#else
|
||||
thread_info(make_thread_info(f)) // todo : Add forward
|
||||
#endif
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f):
|
||||
#ifdef BOOST_THREAD_USES_MOVE
|
||||
thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
|
||||
#else
|
||||
thread_info(make_thread_info(f)) // todo : Add forward
|
||||
#endif
|
||||
thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread(attrs);
|
||||
}
|
||||
@@ -360,32 +267,8 @@ namespace boost
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
template <class F, class Arg, class ...Args>
|
||||
thread(F&& f, Arg&& arg, Args&&... args) :
|
||||
thread_info(make_thread_info(
|
||||
thread_detail::decay_copy(boost::forward<F>(f)),
|
||||
thread_detail::decay_copy(boost::forward<Arg>(arg)),
|
||||
thread_detail::decay_copy(boost::forward<Args>(args))...)
|
||||
)
|
||||
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F, class Arg, class ...Args>
|
||||
thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) :
|
||||
thread_info(make_thread_info(
|
||||
thread_detail::decay_copy(boost::forward<F>(f)),
|
||||
thread_detail::decay_copy(boost::forward<Arg>(arg)),
|
||||
thread_detail::decay_copy(boost::forward<Args>(args))...)
|
||||
)
|
||||
|
||||
{
|
||||
start_thread(attrs);
|
||||
}
|
||||
#else
|
||||
template <class F,class A1>
|
||||
thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0):
|
||||
thread(F f,A1 a1,typename disable_if<boost::is_convertible<F&,thread_attributes >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
|
||||
{
|
||||
start_thread();
|
||||
@@ -445,26 +328,18 @@ namespace boost
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(thread& x) BOOST_NOEXCEPT
|
||||
{
|
||||
thread_info.swap(x.thread_info);
|
||||
}
|
||||
|
||||
class id;
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
inline id get_id() const BOOST_NOEXCEPT;
|
||||
#else
|
||||
class BOOST_SYMBOL_VISIBLE id;
|
||||
id get_id() const BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
bool joinable() const BOOST_NOEXCEPT;
|
||||
private:
|
||||
bool join_noexcept();
|
||||
public:
|
||||
inline void join();
|
||||
|
||||
void join();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -488,57 +363,44 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
private:
|
||||
bool do_try_join_until_noexcept(uintmax_t milli, bool& res);
|
||||
inline bool do_try_join_until(uintmax_t milli);
|
||||
public:
|
||||
bool timed_join(const system_time& abs_time);
|
||||
//{
|
||||
// return do_try_join_until(get_milliseconds_until(wait_until));
|
||||
//}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
return do_try_join_until(rel_time.count());
|
||||
}
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
#else
|
||||
private:
|
||||
bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res);
|
||||
inline bool do_try_join_until(struct timespec const &timeout);
|
||||
public:
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_join(const system_time& abs_time)
|
||||
{
|
||||
struct timespec const ts=detail::to_timespec(abs_time);
|
||||
struct timespec const ts=detail::get_timespec(abs_time);
|
||||
return do_try_join_until(ts);
|
||||
}
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts = boost::detail::to_timespec(d);
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
return do_try_join_until(ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
private:
|
||||
bool do_try_join_until(struct timespec const &timeout);
|
||||
public:
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#endif
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline bool timed_join(TimeDuration const& rel_time)
|
||||
{
|
||||
return timed_join(get_system_time()+rel_time);
|
||||
}
|
||||
#endif
|
||||
void detach();
|
||||
|
||||
void detach() BOOST_NOEXCEPT;
|
||||
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
|
||||
|
||||
@@ -546,13 +408,12 @@ namespace boost
|
||||
typedef detail::thread_data_base::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
// Use thread::id when comparisions are needed
|
||||
// backwards compatibility
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
#endif
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
static inline void yield() BOOST_NOEXCEPT
|
||||
{
|
||||
this_thread::yield();
|
||||
@@ -562,13 +423,10 @@ namespace boost
|
||||
{
|
||||
this_thread::sleep(xt);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// extensions
|
||||
void interrupt();
|
||||
bool interruption_requested() const BOOST_NOEXCEPT;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT
|
||||
@@ -576,7 +434,7 @@ namespace boost
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
inline thread&& move(thread& t) BOOST_NOEXCEPT
|
||||
{
|
||||
return static_cast<thread&&>(t);
|
||||
@@ -587,24 +445,16 @@ namespace boost
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
inline thread::id get_id() BOOST_NOEXCEPT;
|
||||
#else
|
||||
thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
|
||||
bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
|
||||
{
|
||||
sleep(system_time(abs_time));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread::id
|
||||
@@ -640,7 +490,11 @@ namespace boost
|
||||
public:
|
||||
id() BOOST_NOEXCEPT:
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
thread_data(0)
|
||||
#else
|
||||
thread_data(0)
|
||||
#endif
|
||||
#else
|
||||
thread_data()
|
||||
#endif
|
||||
@@ -718,61 +572,6 @@ namespace boost
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
thread::id thread::get_id() const BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
return const_cast<thread*>(this)->native_handle();
|
||||
#else
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
return (local_thread_info? id(local_thread_info) : id());
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
inline thread::id get_id() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
return pthread_self();
|
||||
#else
|
||||
boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
|
||||
return (thread_info?thread::id(thread_info->shared_from_this()):thread::id());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void thread::join() {
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
|
||||
BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(),
|
||||
thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
bool thread::do_try_join_until(struct timespec const &timeout)
|
||||
#else
|
||||
bool thread::do_try_join_until(uintmax_t timeout)
|
||||
#endif
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
bool res;
|
||||
if (do_try_join_until_noexcept(timeout, res))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_THREAD_THROW_ELSE_RETURN(
|
||||
(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template<class charT, class traits>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -783,7 +582,6 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_EQ
|
||||
inline bool thread::operator==(const thread& other) const
|
||||
{
|
||||
return get_id()==other.get_id();
|
||||
@@ -793,7 +591,6 @@ namespace boost
|
||||
{
|
||||
return get_id()!=other.get_id();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <list>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -23,7 +22,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
thread_group(thread_group const&);
|
||||
thread_group& operator=(thread_group const&);
|
||||
thread_group& operator=(thread_group const&);
|
||||
public:
|
||||
thread_group() {}
|
||||
~thread_group()
|
||||
@@ -36,41 +35,6 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
bool is_this_thread_in()
|
||||
{
|
||||
thread::id id = this_thread::get_id();
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
if ((*it)->get_id() == id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_thread_in(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
thread::id id = thrd->get_id();
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
if ((*it)->get_id() == id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
@@ -79,20 +43,16 @@ namespace boost
|
||||
threads.push_back(new_thread.get());
|
||||
return new_thread.release();
|
||||
}
|
||||
|
||||
|
||||
void add_thread(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) ,
|
||||
thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying to add a duplicated thread")
|
||||
);
|
||||
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
threads.push_back(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void remove_thread(thread* thrd)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
@@ -102,28 +62,23 @@ namespace boost
|
||||
threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void join_all()
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() ,
|
||||
thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying joining itself")
|
||||
);
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
if ((*it)->joinable())
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
|
||||
void interrupt_all()
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
@@ -131,14 +86,13 @@ namespace boost
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::list<thread*> threads;
|
||||
mutable shared_mutex m;
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace this_thread
|
||||
@@ -35,5 +33,4 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#endif // header
|
||||
#endif
|
||||
|
||||
@@ -28,10 +28,8 @@
|
||||
namespace boost
|
||||
{
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
class BOOST_SYMBOL_VISIBLE thread_interrupted
|
||||
{};
|
||||
#endif
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_exception:
|
||||
public system::system_error
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
// (C) Copyright 2012 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)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_HPP
|
||||
#define BOOST_THREAD_EXTERNALLY_LOCKED_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/lock_concepts.hpp>
|
||||
#include <boost/thread/lock_traits.hpp>
|
||||
#include <boost/thread/lockable_concepts.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/utility/swap.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* externally_locked cloaks an object of type T, and actually provides full
|
||||
* access to that object through the get and set member functions, provided you
|
||||
* pass a reference to a strict lock object
|
||||
*/
|
||||
|
||||
//[externally_locked
|
||||
template <typename T, typename MutexType = boost::mutex>
|
||||
class externally_locked
|
||||
{
|
||||
//BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));
|
||||
|
||||
public:
|
||||
typedef MutexType mutex_type;
|
||||
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked )
|
||||
/**
|
||||
* Requires: T is a model of CopyConstructible.
|
||||
* Effects: Constructs an externally locked object copying the cloaked type.
|
||||
*/
|
||||
BOOST_CONSTEXPR externally_locked(mutex_type& mtx, const T& obj) :
|
||||
obj_(obj), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires: T is a model of Movable.
|
||||
* Effects: Constructs an externally locked object by moving the cloaked type.
|
||||
*/
|
||||
BOOST_CONSTEXPR externally_locked(mutex_type& mtx, BOOST_THREAD_RV_REF(T) obj) :
|
||||
obj_(move(obj)), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires: T is a model of DefaultConstructible.
|
||||
* Effects: Constructs an externally locked object initializing the cloaked type with the default constructor.
|
||||
*/
|
||||
externally_locked(mutex_type& mtx) :
|
||||
obj_(), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Move constructor
|
||||
*/
|
||||
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) :
|
||||
obj_(move(rhs.obj_)), mtx_(rhs.mtx_)
|
||||
{
|
||||
rhs.mtx_=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires: The lk parameter must be locking the associated mtx.
|
||||
*
|
||||
* Returns: The address of the cloaked object..
|
||||
*
|
||||
* Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
|
||||
*/
|
||||
T& get(strict_lock<mutex_type>& lk)
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return obj_;
|
||||
}
|
||||
|
||||
const T& get(strict_lock<mutex_type>& lk) const
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return obj_;
|
||||
}
|
||||
|
||||
template <class Lock>
|
||||
T& get(nested_strict_lock<Lock>& lk)
|
||||
{
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return obj_;
|
||||
}
|
||||
|
||||
template <class Lock>
|
||||
const T& get(nested_strict_lock<Lock>& lk) const
|
||||
{
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return obj_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires: The lk parameter must be locking the associated mtx.
|
||||
* Returns: The address of the cloaked object..
|
||||
*
|
||||
* Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
|
||||
*/
|
||||
template <class Lock>
|
||||
T& get(Lock& lk)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( StrictLock<Lock> ));
|
||||
BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(), lock_error() ); /*< run time check throw if no locked >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
|
||||
return obj_;
|
||||
}
|
||||
|
||||
mutex_type* mutex()
|
||||
{
|
||||
return mtx_;
|
||||
}
|
||||
|
||||
// modifiers
|
||||
|
||||
void lock()
|
||||
{
|
||||
mtx_->lock();
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
mtx_->unlock();
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
return mtx_->try_lock();
|
||||
}
|
||||
// todo add time related functions
|
||||
|
||||
private:
|
||||
T obj_;
|
||||
mutex_type* mtx_;
|
||||
};
|
||||
//]
|
||||
|
||||
/**
|
||||
* externally_locked<T&,M> specialization for T& that cloaks an reference to an object of type T, and actually
|
||||
* provides full access to that object through the get and set member functions, provided you
|
||||
* pass a reference to a strict lock object.
|
||||
*/
|
||||
|
||||
//[externally_locked_ref
|
||||
template <typename T, typename MutexType>
|
||||
class externally_locked<T&, MutexType>
|
||||
{
|
||||
//BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));
|
||||
|
||||
public:
|
||||
typedef MutexType mutex_type;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY( externally_locked )
|
||||
|
||||
/**
|
||||
* Effects: Constructs an externally locked object storing the cloaked reference object.
|
||||
*/
|
||||
externally_locked(T& obj, mutex_type& mtx) :
|
||||
obj_(&obj), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
/// move constructor
|
||||
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) :
|
||||
obj_(rhs.obj_), mtx_(rhs.mtx_)
|
||||
{
|
||||
rhs.obj_=0;
|
||||
rhs.mtx_=0;
|
||||
}
|
||||
|
||||
void swap(externally_locked& rhs)
|
||||
{
|
||||
swap(obj_, rhs.obj_);
|
||||
swap(mtx_, rhs.mtx_);
|
||||
}
|
||||
/**
|
||||
* Requires: The lk parameter must be locking the associated mtx.
|
||||
*
|
||||
* Returns: The address of the cloaked object..
|
||||
*
|
||||
* Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
|
||||
*/
|
||||
T& get(strict_lock<mutex_type> const& lk)
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return *obj_;
|
||||
}
|
||||
|
||||
const T& get(strict_lock<mutex_type> const& lk) const
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return *obj_;
|
||||
}
|
||||
|
||||
template <class Lock>
|
||||
T& get(nested_strict_lock<Lock> const& lk)
|
||||
{
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return *obj_;
|
||||
}
|
||||
|
||||
template <class Lock>
|
||||
const T& get(nested_strict_lock<Lock> const& lk) const
|
||||
{
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return *obj_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires: The lk parameter must be locking the associated mtx.
|
||||
* Returns: The address of the cloaked object..
|
||||
*
|
||||
* Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
|
||||
*/
|
||||
template <class Lock>
|
||||
T& get(Lock const& lk)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( StrictLock<Lock> ));
|
||||
BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
//BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(), lock_error() ); /*< run time check throw if no locked >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return *obj_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires: The lk parameter must be locking the associated mtx.
|
||||
* Returns: The address of the cloaked object..
|
||||
*
|
||||
* Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
|
||||
*/
|
||||
template <class Lock>
|
||||
T const& get(Lock const& lk) const
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( StrictLock<Lock> ));
|
||||
BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/
|
||||
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/
|
||||
//BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(), lock_error() ); /*< run time check throw if no locked >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
|
||||
return *obj_;
|
||||
}
|
||||
mutex_type* mutex()
|
||||
{
|
||||
return mtx_;
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
mtx_->lock();
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
mtx_->unlock();
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
return mtx_->try_lock();
|
||||
}
|
||||
// todo add time related functions
|
||||
|
||||
protected:
|
||||
T* obj_;
|
||||
mutex_type* mtx_;
|
||||
};
|
||||
//]
|
||||
|
||||
template <typename T, typename MutexType>
|
||||
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -1,169 +0,0 @@
|
||||
// (C) Copyright 2012 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)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_STREAM_HPP
|
||||
#define BOOST_THREAD_EXTERNALLY_LOCKED_STREAM_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/thread/externally_locked.hpp>
|
||||
#include <boost/thread/lock_traits.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// inline static recursive_mutex& terminal_mutex()
|
||||
// {
|
||||
// static recursive_mutex mtx;
|
||||
// return mtx;
|
||||
// }
|
||||
|
||||
template <typename Stream, typename RecursiveMutex=recursive_mutex>
|
||||
class externally_locked_stream;
|
||||
|
||||
template <class Stream, typename RecursiveMutex=recursive_mutex>
|
||||
class stream_guard
|
||||
{
|
||||
|
||||
friend class externally_locked_stream<Stream, RecursiveMutex> ;
|
||||
public:
|
||||
typedef typename externally_locked_stream<Stream, RecursiveMutex>::mutex_type mutex_type;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY( stream_guard)
|
||||
|
||||
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx) :
|
||||
mtx_(&mtx)
|
||||
{
|
||||
mtx.lock();
|
||||
}
|
||||
|
||||
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx, adopt_lock_t) :
|
||||
mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
stream_guard(BOOST_THREAD_RV_REF(stream_guard) rhs)
|
||||
: mtx_(rhs.mtx_)
|
||||
{
|
||||
rhs.mtx_= 0;
|
||||
}
|
||||
|
||||
~stream_guard()
|
||||
{
|
||||
if (mtx_ != 0) mtx_->unlock();
|
||||
}
|
||||
|
||||
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT
|
||||
{
|
||||
return l == mtx_->mutex();
|
||||
}
|
||||
|
||||
Stream& get() const
|
||||
{
|
||||
return mtx_->get(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
externally_locked_stream<Stream, RecursiveMutex>* mtx_;
|
||||
};
|
||||
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
struct is_strict_lock_sur_parolle<stream_guard<Stream, RecursiveMutex> > : true_type
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* externally_locked_stream cloaks a reference to an stream of type Stream, and actually
|
||||
* provides full access to that object through the get and set member functions, provided you
|
||||
* pass a reference to a strict lock object.
|
||||
*/
|
||||
|
||||
//[externally_locked_stream
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
class externally_locked_stream: public externally_locked<Stream&, RecursiveMutex>
|
||||
{
|
||||
typedef externally_locked<Stream&, RecursiveMutex> base_type;
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( externally_locked_stream)
|
||||
|
||||
/**
|
||||
* Effects: Constructs an externally locked object storing the cloaked reference object.
|
||||
*/
|
||||
externally_locked_stream(Stream& stream, RecursiveMutex& mtx) :
|
||||
base_type(stream, mtx)
|
||||
{
|
||||
}
|
||||
|
||||
stream_guard<Stream, RecursiveMutex> hold()
|
||||
{
|
||||
return stream_guard<Stream, RecursiveMutex> (*this);
|
||||
}
|
||||
|
||||
Stream& hold(strict_lock<RecursiveMutex>& lk)
|
||||
{
|
||||
return this->get(lk);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
inline const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, T arg)
|
||||
{
|
||||
lck.get() << arg;
|
||||
return lck;
|
||||
}
|
||||
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
inline const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, Stream& (*arg)(Stream&))
|
||||
{
|
||||
lck.get() << arg;
|
||||
return lck;
|
||||
}
|
||||
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
inline const stream_guard<Stream, RecursiveMutex>& operator>>(const stream_guard<Stream, RecursiveMutex>& lck, T& arg)
|
||||
{
|
||||
lck.get() >> arg;
|
||||
return lck;
|
||||
}
|
||||
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
inline stream_guard<Stream, RecursiveMutex> operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, T arg)
|
||||
{
|
||||
stream_guard<Stream, RecursiveMutex> lk(mtx);
|
||||
mtx.get(lk) << arg;
|
||||
return boost::move(lk);
|
||||
}
|
||||
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
inline stream_guard<Stream, RecursiveMutex> operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, Stream& (*arg)(Stream&))
|
||||
{
|
||||
stream_guard<Stream, RecursiveMutex> lk(mtx);
|
||||
mtx.get(lk) << arg;
|
||||
return boost::move(lk);
|
||||
}
|
||||
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
inline stream_guard<Stream, RecursiveMutex> operator>>(externally_locked_stream<Stream, RecursiveMutex>& mtx, T& arg)
|
||||
{
|
||||
stream_guard<Stream, RecursiveMutex> lk(mtx);
|
||||
mtx.get(lk) >> arg;
|
||||
return boost::move(lk);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
||||
// (C) Copyright 2008-10 Anthony Williams
|
||||
// (C) Copyright 2011-2012 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)
|
||||
|
||||
#ifndef BOOST_THREAD_FUTURE_ERROR_CODE_HPP
|
||||
#define BOOST_THREAD_FUTURE_ERROR_CODE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/detail/scoped_enum_emulation.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//enum class future_errc
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
|
||||
{
|
||||
broken_promise = 1,
|
||||
future_already_retrieved,
|
||||
promise_already_satisfied,
|
||||
no_state
|
||||
}
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
|
||||
|
||||
namespace system
|
||||
{
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type {};
|
||||
|
||||
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
|
||||
#endif
|
||||
} // system
|
||||
|
||||
BOOST_THREAD_DECL
|
||||
const system::error_category& future_category() BOOST_NOEXCEPT;
|
||||
|
||||
namespace system
|
||||
{
|
||||
inline
|
||||
error_code
|
||||
make_error_code(future_errc e) BOOST_NOEXCEPT
|
||||
{
|
||||
return error_code(underlying_cast<int>(e), boost::future_category());
|
||||
}
|
||||
|
||||
inline
|
||||
error_condition
|
||||
make_error_condition(future_errc e) BOOST_NOEXCEPT
|
||||
{
|
||||
return error_condition(underlying_cast<int>(e), future_category());
|
||||
}
|
||||
} // system
|
||||
} // boost
|
||||
|
||||
#endif // header
|
||||
@@ -1,39 +0,0 @@
|
||||
// (C) Copyright 2012 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)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP
|
||||
#define BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename Lockable>
|
||||
class testable_mutex;
|
||||
|
||||
/**
|
||||
* Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise.
|
||||
*
|
||||
* This function is used usually to assert the pre-condition when the function can only be called when the mutex
|
||||
* must be locked by the current thread.
|
||||
*/
|
||||
template <typename Lockable>
|
||||
bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
|
||||
{
|
||||
return mtx.is_locked();
|
||||
}
|
||||
template <typename Lockable>
|
||||
bool is_locked_by_this_thread(Lockable const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -1,468 +0,0 @@
|
||||
// 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 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LOCK_ALGORITHMS_HPP
|
||||
#define BOOST_THREAD_LOCK_ALGORITHMS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/lockable_traits.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock);
|
||||
if (!l1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (!m2.try_lock())
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3>
|
||||
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock);
|
||||
if (!l1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (unsigned const failed_lock=try_lock_internal(m2,m3))
|
||||
{
|
||||
return failed_lock + 1;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
|
||||
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock);
|
||||
if (!l1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (unsigned const failed_lock=try_lock_internal(m2,m3,m4))
|
||||
{
|
||||
return failed_lock + 1;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
|
||||
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock);
|
||||
if (!l1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5))
|
||||
{
|
||||
return failed_lock + 1;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
unsigned lock_helper(MutexType1& m1, MutexType2& m2)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1);
|
||||
if (!m2.try_lock())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3>
|
||||
unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1);
|
||||
if (unsigned const failed_lock=try_lock_internal(m2,m3))
|
||||
{
|
||||
return failed_lock;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
|
||||
unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1);
|
||||
if (unsigned const failed_lock=try_lock_internal(m2,m3,m4))
|
||||
{
|
||||
return failed_lock;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
|
||||
unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5)
|
||||
{
|
||||
boost::unique_lock<MutexType1> l1(m1);
|
||||
if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5))
|
||||
{
|
||||
return failed_lock;
|
||||
}
|
||||
l1.release();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <bool x>
|
||||
struct is_mutex_type_wrapper
|
||||
{
|
||||
};
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
void lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper<true> )
|
||||
{
|
||||
unsigned const lock_count = 2;
|
||||
unsigned lock_first = 0;
|
||||
for (;;)
|
||||
{
|
||||
switch (lock_first)
|
||||
{
|
||||
case 0:
|
||||
lock_first = detail::lock_helper(m1, m2);
|
||||
if (!lock_first) return;
|
||||
break;
|
||||
case 1:
|
||||
lock_first = detail::lock_helper(m2, m1);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 1) % lock_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> );
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
void lock(MutexType1& m1, MutexType2& m2)
|
||||
{
|
||||
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
void lock(const MutexType1& m1, MutexType2& m2)
|
||||
{
|
||||
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
void lock(MutexType1& m1, const MutexType2& m2)
|
||||
{
|
||||
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
void lock(const MutexType1& m1, const MutexType2& m2)
|
||||
{
|
||||
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3>
|
||||
void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3)
|
||||
{
|
||||
unsigned const lock_count = 3;
|
||||
unsigned lock_first = 0;
|
||||
for (;;)
|
||||
{
|
||||
switch (lock_first)
|
||||
{
|
||||
case 0:
|
||||
lock_first = detail::lock_helper(m1, m2, m3);
|
||||
if (!lock_first) return;
|
||||
break;
|
||||
case 1:
|
||||
lock_first = detail::lock_helper(m2, m3, m1);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 1) % lock_count;
|
||||
break;
|
||||
case 2:
|
||||
lock_first = detail::lock_helper(m3, m1, m2);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 2) % lock_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
|
||||
void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
|
||||
{
|
||||
unsigned const lock_count = 4;
|
||||
unsigned lock_first = 0;
|
||||
for (;;)
|
||||
{
|
||||
switch (lock_first)
|
||||
{
|
||||
case 0:
|
||||
lock_first = detail::lock_helper(m1, m2, m3, m4);
|
||||
if (!lock_first) return;
|
||||
break;
|
||||
case 1:
|
||||
lock_first = detail::lock_helper(m2, m3, m4, m1);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 1) % lock_count;
|
||||
break;
|
||||
case 2:
|
||||
lock_first = detail::lock_helper(m3, m4, m1, m2);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 2) % lock_count;
|
||||
break;
|
||||
case 3:
|
||||
lock_first = detail::lock_helper(m4, m1, m2, m3);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 3) % lock_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
|
||||
void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5)
|
||||
{
|
||||
unsigned const lock_count = 5;
|
||||
unsigned lock_first = 0;
|
||||
for (;;)
|
||||
{
|
||||
switch (lock_first)
|
||||
{
|
||||
case 0:
|
||||
lock_first = detail::lock_helper(m1, m2, m3, m4, m5);
|
||||
if (!lock_first) return;
|
||||
break;
|
||||
case 1:
|
||||
lock_first = detail::lock_helper(m2, m3, m4, m5, m1);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 1) % lock_count;
|
||||
break;
|
||||
case 2:
|
||||
lock_first = detail::lock_helper(m3, m4, m5, m1, m2);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 2) % lock_count;
|
||||
break;
|
||||
case 3:
|
||||
lock_first = detail::lock_helper(m4, m5, m1, m2, m3);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 3) % lock_count;
|
||||
break;
|
||||
case 4:
|
||||
lock_first = detail::lock_helper(m5, m1, m2, m3, m4);
|
||||
if (!lock_first) return;
|
||||
lock_first = (lock_first + 4) % lock_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Mutex, bool x = is_mutex_type<Mutex>::value>
|
||||
struct try_lock_impl_return
|
||||
{
|
||||
typedef int type;
|
||||
};
|
||||
|
||||
template <typename Iterator>
|
||||
struct try_lock_impl_return<Iterator, false>
|
||||
{
|
||||
typedef Iterator type;
|
||||
};
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
int try_lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper<true> )
|
||||
{
|
||||
return ((int) detail::try_lock_internal(m1, m2)) - 1;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> );
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1, MutexType2& m2)
|
||||
{
|
||||
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1, MutexType2& m2)
|
||||
{
|
||||
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1, const MutexType2& m2)
|
||||
{
|
||||
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2>
|
||||
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1, const MutexType2& m2)
|
||||
{
|
||||
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3>
|
||||
int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3)
|
||||
{
|
||||
return ((int) detail::try_lock_internal(m1, m2, m3)) - 1;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
|
||||
int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
|
||||
{
|
||||
return ((int) detail::try_lock_internal(m1, m2, m3, m4)) - 1;
|
||||
}
|
||||
|
||||
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
|
||||
int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5)
|
||||
{
|
||||
return ((int) detail::try_lock_internal(m1, m2, m3, m4, m5)) - 1;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Iterator>
|
||||
struct range_lock_guard
|
||||
{
|
||||
Iterator begin;
|
||||
Iterator end;
|
||||
|
||||
range_lock_guard(Iterator begin_, Iterator end_) :
|
||||
begin(begin_), end(end_)
|
||||
{
|
||||
boost::lock(begin, end);
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
begin = end;
|
||||
}
|
||||
|
||||
~range_lock_guard()
|
||||
{
|
||||
for (; begin != end; ++begin)
|
||||
{
|
||||
begin->unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Iterator>
|
||||
Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> )
|
||||
|
||||
{
|
||||
if (begin == end)
|
||||
{
|
||||
return end;
|
||||
}
|
||||
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
|
||||
unique_lock<lock_type> guard(*begin, try_to_lock);
|
||||
|
||||
if (!guard.owns_lock())
|
||||
{
|
||||
return begin;
|
||||
}
|
||||
Iterator const failed = boost::try_lock(++begin, end);
|
||||
if (failed == end)
|
||||
{
|
||||
guard.release();
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Iterator>
|
||||
void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> )
|
||||
{
|
||||
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
|
||||
|
||||
if (begin == end)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool start_with_begin = true;
|
||||
Iterator second = begin;
|
||||
++second;
|
||||
Iterator next = second;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unique_lock<lock_type> begin_lock(*begin, defer_lock);
|
||||
if (start_with_begin)
|
||||
{
|
||||
begin_lock.lock();
|
||||
Iterator const failed_lock = boost::try_lock(next, end);
|
||||
if (failed_lock == end)
|
||||
{
|
||||
begin_lock.release();
|
||||
return;
|
||||
}
|
||||
start_with_begin = false;
|
||||
next = failed_lock;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::range_lock_guard<Iterator> guard(next, end);
|
||||
if (begin_lock.try_lock())
|
||||
{
|
||||
Iterator const failed_lock = boost::try_lock(second, next);
|
||||
if (failed_lock == next)
|
||||
{
|
||||
begin_lock.release();
|
||||
guard.release();
|
||||
return;
|
||||
}
|
||||
start_with_begin = false;
|
||||
next = failed_lock;
|
||||
}
|
||||
else
|
||||
{
|
||||
start_with_begin = true;
|
||||
next = second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,197 +0,0 @@
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_LOCK_CONCEPTS_HPP
|
||||
#define BOOST_THREAD_LOCK_CONCEPTS_HPP
|
||||
|
||||
#include <boost/thread/lock_traits.hpp>
|
||||
#include <boost/thread/lock_options.hpp>
|
||||
#include <boost/thread/lockable_concepts.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* BasicLock object supports the basic features
|
||||
* required to delimit a critical region
|
||||
* Supports the basic lock, unlock and try_lock functions and
|
||||
* defines the lock traits
|
||||
*/
|
||||
|
||||
template <typename Lk>
|
||||
struct BasicLock
|
||||
{
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
void cvt_mutex_ptr(mutex_type*);
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(BasicLock)
|
||||
{
|
||||
const Lk l1(mtx);
|
||||
Lk l2(mtx, defer_lock);
|
||||
Lk l3(mtx, adopt_lock);
|
||||
Lk l4(( Lk()));
|
||||
Lk l5(( boost::move(l2)));
|
||||
cvt_mutex_ptr(l1.mutex());
|
||||
if (l1.owns_lock()) return;
|
||||
if (l1) return;
|
||||
if (!l1) return;
|
||||
|
||||
l2.lock();
|
||||
l2.unlock();
|
||||
l2.release();
|
||||
|
||||
}
|
||||
BasicLock() :
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
BasicLock operator=(BasicLock const&);
|
||||
mutex_type& mtx;
|
||||
}
|
||||
;
|
||||
|
||||
template <typename Lk>
|
||||
struct Lock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( BasicLock<Lk> ));
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
BOOST_CONCEPT_ASSERT(( Lockable<mutex_type> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(Lock)
|
||||
{
|
||||
Lk l1(mtx, try_to_lock);
|
||||
if (l1.try_lock()) return;
|
||||
}
|
||||
Lock() :
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
Lock operator=(Lock const&);
|
||||
mutex_type& mtx;
|
||||
};
|
||||
|
||||
template <typename Lk>
|
||||
struct TimedLock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( Lock<Lk> ));
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
BOOST_CONCEPT_ASSERT(( TimedLockable<mutex_type> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(TimedLock)
|
||||
{
|
||||
const Lk l1(mtx, t);
|
||||
Lk l2(mtx, d);
|
||||
if (l1.try_lock_until(t)) return;
|
||||
if (l1.try_lock_for(d)) return;
|
||||
}
|
||||
TimedLock() :
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
TimedLock operator=(TimedLock const&);
|
||||
mutex_type& mtx;
|
||||
boost::chrono::system_clock::time_point t;
|
||||
boost::chrono::system_clock::duration d;
|
||||
};
|
||||
|
||||
template <typename Lk>
|
||||
struct UniqueLock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( TimedLock<Lk> ));
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
|
||||
BOOST_CONCEPT_USAGE(UniqueLock)
|
||||
{
|
||||
|
||||
}
|
||||
UniqueLock() :
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
UniqueLock operator=(UniqueLock const&);
|
||||
mutex_type& mtx;
|
||||
};
|
||||
|
||||
template <typename Lk>
|
||||
struct SharedLock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( TimedLock<Lk> ));
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
|
||||
BOOST_CONCEPT_USAGE(SharedLock)
|
||||
{
|
||||
}
|
||||
SharedLock() :
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
SharedLock operator=(SharedLock const&);
|
||||
mutex_type& mtx;
|
||||
|
||||
};
|
||||
|
||||
template <typename Lk>
|
||||
struct UpgradeLock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( SharedLock<Lk> ));
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
|
||||
BOOST_CONCEPT_USAGE(UpgradeLock)
|
||||
{
|
||||
}
|
||||
UpgradeLock() :
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
UpgradeLock operator=(UpgradeLock const&);
|
||||
mutex_type& mtx;
|
||||
};
|
||||
|
||||
/**
|
||||
* An StrictLock is a scoped lock guard ensuring the mutex is locked on the
|
||||
* scope of the lock, by locking the mutex on construction and unlocking it on
|
||||
* destruction.
|
||||
*
|
||||
* Essentially, a StrictLock's role is only to live on the stack as an
|
||||
* automatic variable. strict_lock must adhere to a non-copy and non-alias
|
||||
* policy. StrictLock disables copying by making the copy constructor and the
|
||||
* assignment operator private. While we're at it, let's disable operator new
|
||||
* and operator delete; strict locks are not intended to be allocated on the
|
||||
* heap. StrictLock avoids aliasing by using a slightly less orthodox and
|
||||
* less well-known technique: disable address taking.
|
||||
*/
|
||||
|
||||
template <typename Lk>
|
||||
struct StrictLock
|
||||
{
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> ));
|
||||
BOOST_STATIC_ASSERT(( is_strict_lock<Lk>::value ));
|
||||
|
||||
BOOST_CONCEPT_USAGE( StrictLock)
|
||||
{
|
||||
if (l1.owns_lock(&mtx)) return;
|
||||
}
|
||||
StrictLock() :
|
||||
l1(*static_cast<Lk*>(0)),
|
||||
mtx(*static_cast<mutex_type*>(0))
|
||||
{}
|
||||
private:
|
||||
StrictLock operator=(StrictLock const&);
|
||||
|
||||
Lk const& l1;
|
||||
mutex_type const& mtx;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
// 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 2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LOCK_FACTORIES_HPP
|
||||
#define BOOST_THREAD_LOCK_FACTORIES_HPP
|
||||
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
|
||||
#include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics.
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename Lockable>
|
||||
unique_lock<Lockable> make_unique_lock(Lockable& mtx)
|
||||
{
|
||||
return unique_lock<Lockable> (mtx);
|
||||
}
|
||||
|
||||
template <typename Lockable>
|
||||
unique_lock<Lockable> make_unique_lock(Lockable& mtx, adopt_lock_t)
|
||||
{
|
||||
return unique_lock<Lockable> (mtx, adopt_lock);
|
||||
}
|
||||
|
||||
template <typename Lockable>
|
||||
unique_lock<Lockable> make_unique_lock(Lockable& mtx, defer_lock_t)
|
||||
{
|
||||
return unique_lock<Lockable> (mtx, defer_lock);
|
||||
}
|
||||
|
||||
template <typename Lockable>
|
||||
unique_lock<Lockable> make_unique_lock(Lockable& mtx, try_to_lock_t)
|
||||
{
|
||||
return unique_lock<Lockable> (mtx, try_to_lock);
|
||||
}
|
||||
#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template <typename ...Lockable>
|
||||
std::tuple<unique_lock<Lockable> ...> make_unique_locks(Lockable& ...mtx)
|
||||
{
|
||||
boost::lock(mtx...);
|
||||
return std::tuple<unique_lock<Lockable> ...>(unique_lock<Lockable>(mtx, adopt_lock)...);
|
||||
}
|
||||
#else
|
||||
template <typename L1, typename L2>
|
||||
std::tuple<unique_lock<L1>, unique_lock<L2> > make_unique_locks(L1& m1, L2& m2)
|
||||
{
|
||||
boost::lock(m1, m2);
|
||||
return std::tuple<unique_lock<L1>,unique_lock<L2> >(
|
||||
unique_lock<L1>(m1, adopt_lock),
|
||||
unique_lock<L2>(m2, adopt_lock)
|
||||
);
|
||||
}
|
||||
template <typename L1, typename L2, typename L3>
|
||||
std::tuple<unique_lock<L1>, unique_lock<L2>, unique_lock<L3> > make_unique_locks(L1& m1, L2& m2, L3& m3)
|
||||
{
|
||||
boost::lock(m1, m2, m3);
|
||||
return std::tuple<unique_lock<L1>,unique_lock<L2>,unique_lock<L3> >(
|
||||
unique_lock<L1>(m1, adopt_lock),
|
||||
unique_lock<L2>(m2, adopt_lock),
|
||||
unique_lock<L3>(m3, adopt_lock)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
#endif
|
||||
@@ -1,88 +0,0 @@
|
||||
// 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 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LOCK_GUARD_HPP
|
||||
#define BOOST_THREAD_LOCK_GUARD_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/lockable_wrapper.hpp>
|
||||
#include <boost/thread/lock_options.hpp>
|
||||
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
#include <boost/thread/is_locked_by_this_thread.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename Mutex>
|
||||
class lock_guard
|
||||
{
|
||||
private:
|
||||
Mutex& m;
|
||||
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
BOOST_THREAD_NO_COPYABLE( lock_guard )
|
||||
|
||||
explicit lock_guard(Mutex& m_) :
|
||||
m(m_)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
lock_guard(Mutex& m_, adopt_lock_t) :
|
||||
m(m_)
|
||||
{
|
||||
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
BOOST_ASSERT(is_locked_by_this_thread(m));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
lock_guard(std::initializer_list<thread_detail::lockable_wrapper<Mutex> > l_) :
|
||||
m(*(const_cast<thread_detail::lockable_wrapper<Mutex>*>(l_.begin())->m))
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
|
||||
lock_guard(std::initializer_list<thread_detail::lockable_adopt_wrapper<Mutex> > l_) :
|
||||
m(*(const_cast<thread_detail::lockable_adopt_wrapper<Mutex>*>(l_.begin())->m))
|
||||
{
|
||||
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
BOOST_ASSERT(is_locked_by_this_thread(m));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
~lock_guard()
|
||||
{
|
||||
m.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_MAKE_LOCK_GUARD
|
||||
template <typename Lockable>
|
||||
lock_guard<Lockable> make_lock_guard(Lockable& mtx)
|
||||
{
|
||||
return { thread_detail::lockable_wrapper<Lockable>(mtx) };
|
||||
}
|
||||
template <typename Lockable>
|
||||
lock_guard<Lockable> make_lock_guard(Lockable& mtx, adopt_lock_t)
|
||||
{
|
||||
return { thread_detail::lockable_adopt_wrapper<Lockable>(mtx) };
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
// 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 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LOCK_OPTIONS_HPP
|
||||
#define BOOST_THREAD_LOCK_OPTIONS_HPP
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct defer_lock_t
|
||||
{
|
||||
};
|
||||
struct try_to_lock_t
|
||||
{
|
||||
};
|
||||
struct adopt_lock_t
|
||||
{
|
||||
};
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST defer_lock_t defer_lock = {};
|
||||
BOOST_CONSTEXPR_OR_CONST try_to_lock_t try_to_lock = {};
|
||||
BOOST_CONSTEXPR_OR_CONST adopt_lock_t adopt_lock = {};
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
// 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 2009-2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LOCK_TRAITS_HPP
|
||||
#define BOOST_THREAD_LOCK_TRAITS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
//#include <boost/thread/detail/move.hpp>
|
||||
//#include <boost/thread/exceptions.hpp>
|
||||
//
|
||||
//#ifdef BOOST_THREAD_USES_CHRONO
|
||||
//#include <boost/chrono/time_point.hpp>
|
||||
//#include <boost/chrono/duration.hpp>
|
||||
//#endif
|
||||
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* An strict lock is a lock ensuring the mutex is locked on the scope of the lock
|
||||
* There is no single way to define a strict lock as the strict_lock and
|
||||
* nesteed_strict_lock shows. So we need a metafunction that states if a
|
||||
* lock is a strict lock "sur parolle".
|
||||
*/
|
||||
|
||||
template <typename Lock>
|
||||
struct is_strict_lock_sur_parolle : false_type {};
|
||||
|
||||
|
||||
template <typename Lock>
|
||||
struct is_strict_lock : is_strict_lock_sur_parolle<Lock> {};
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,226 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_LOCKABLE_ADAPTER_HPP
|
||||
#define BOOST_THREAD_LOCKABLE_ADAPTER_HPP
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//[basic_lockable_adapter
|
||||
template <typename BasicLockable>
|
||||
class basic_lockable_adapter
|
||||
{
|
||||
public:
|
||||
typedef BasicLockable mutex_type;
|
||||
|
||||
protected:
|
||||
mutex_type& lockable() const
|
||||
{
|
||||
return lockable_;
|
||||
}
|
||||
mutable mutex_type lockable_; /*< mutable so that it can be modified by const functions >*/
|
||||
public:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( basic_lockable_adapter) /*< no copyable >*/
|
||||
|
||||
basic_lockable_adapter()
|
||||
{}
|
||||
|
||||
void lock()
|
||||
{
|
||||
lockable().lock();
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
lockable().unlock();
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
//[lockable_adapter
|
||||
template <typename Lockable>
|
||||
class lockable_adapter : public basic_lockable_adapter<Lockable>
|
||||
{
|
||||
public:
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return this->lockable().try_lock();
|
||||
}
|
||||
};
|
||||
//]
|
||||
|
||||
//[timed_lockable_adapter
|
||||
template <typename TimedLock>
|
||||
class timed_lockable_adapter: public lockable_adapter<TimedLock>
|
||||
{
|
||||
public:
|
||||
typedef TimedLock mutex_type;
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return this->lockable().try_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return this->lockable().try_lock_for(rel_time);
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
//[shared_lockable_adapter
|
||||
template <typename SharableLock>
|
||||
class shared_lockable_adapter: public timed_lockable_adapter<SharableLock>
|
||||
{
|
||||
public:
|
||||
typedef SharableLock mutex_type;
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
this->lockable().lock_shared();
|
||||
}
|
||||
bool try_lock_shared()
|
||||
{
|
||||
return this->lockable().try_lock_shared();
|
||||
}
|
||||
void unlock_shared()
|
||||
{
|
||||
this->lockable().unlock_shared();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return this->lockable().try_lock_shared_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return this->lockable().try_lock_shared_for(rel_time);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//]
|
||||
|
||||
//[upgrade_lockable_adapter
|
||||
template <typename UpgradableLock>
|
||||
class upgrade_lockable_adapter: public shared_lockable_adapter<UpgradableLock>
|
||||
{
|
||||
public:
|
||||
typedef UpgradableLock mutex_type;
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
this->lockable().lock_upgrade();
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
return this->lockable().try_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
this->lockable().unlock_upgrade();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return this->lockable().try_lock_upgrade_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return this->lockable().try_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
this->lockable().unlock_and_lock_shared();
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
this->lockable().unlock_and_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
this->lockable().unlock_upgrade_and_lock();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock();
|
||||
}
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
this->lockable().unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,157 +0,0 @@
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_LOCKABLE_CONCEPTS_HPP
|
||||
#define BOOST_THREAD_LOCKABLE_CONCEPTS_HPP
|
||||
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
#include <boost/concept_check.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* BasicLockable object supports the basic features
|
||||
* required to delimit a critical region
|
||||
* Supports the basic lock and unlock functions.
|
||||
*/
|
||||
|
||||
//[BasicLockable
|
||||
template <typename Mutex>
|
||||
struct BasicLockable
|
||||
{
|
||||
|
||||
BOOST_CONCEPT_USAGE(BasicLockable)
|
||||
{
|
||||
l.lock();
|
||||
l.unlock();
|
||||
}
|
||||
BasicLockable() : l(*static_cast<Mutex*>(0)) {}
|
||||
private:
|
||||
BasicLockable operator=(BasicLockable const&);
|
||||
|
||||
Mutex& l;
|
||||
}
|
||||
;
|
||||
//]
|
||||
/**
|
||||
* Lockable extends BasicLockable
|
||||
* with try_lock functions.
|
||||
*/
|
||||
|
||||
//[Lockable
|
||||
template <typename Mutex>
|
||||
struct Lockable
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<Mutex> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(Lockable)
|
||||
{
|
||||
if (l.try_lock()) return;
|
||||
}
|
||||
Lockable() : l(*static_cast<Mutex*>(0)) {}
|
||||
private:
|
||||
Lockable operator=(Lockable const&);
|
||||
Mutex& l;
|
||||
};
|
||||
//]
|
||||
|
||||
/**
|
||||
* TimedLockable object extends Lockable
|
||||
* with timed lock functions: try_lock_until and try_lock_for and the exception based lock_until and lock_for
|
||||
*/
|
||||
|
||||
//[TimedLockable
|
||||
template <typename Mutex>
|
||||
struct TimedLockable
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( Lockable<Mutex> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(TimedLockable)
|
||||
{
|
||||
if (l.try_lock_until(t)) return;
|
||||
if (l.try_lock_for(d)) return;
|
||||
}
|
||||
TimedLockable() : l(*static_cast<Mutex*>(0)) {}
|
||||
private:
|
||||
TimedLockable operator=(TimedLockable const&);
|
||||
Mutex& l;
|
||||
chrono::system_clock::time_point t;
|
||||
chrono::system_clock::duration d;
|
||||
};
|
||||
//]
|
||||
|
||||
/**
|
||||
* SharedLockable object extends TimedLockable
|
||||
* with the lock_shared, lock_shared_until, lock_shared_for, try_lock_shared_until, try_lock_shared
|
||||
* and unlock_shared functions
|
||||
*/
|
||||
//[SharedLockable
|
||||
template <typename Mutex>
|
||||
struct SharedLockable
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( TimedLockable<Mutex> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(SharedLockable)
|
||||
{
|
||||
l.lock_shared();
|
||||
l.unlock_shared();
|
||||
if (l.try_lock_shared()) return;
|
||||
if (l.try_lock_shared_until(t)) return;
|
||||
if (l.try_lock_shared_for(d)) return;
|
||||
}
|
||||
SharedLockable() : l(*static_cast<Mutex*>(0)) {}
|
||||
private:
|
||||
SharedLockable operator=(SharedLockable const&);
|
||||
Mutex& l;
|
||||
chrono::system_clock::time_point t;
|
||||
chrono::system_clock::duration d;
|
||||
};
|
||||
//]
|
||||
|
||||
/**
|
||||
* UpgradeLockable object extends SharedLockable
|
||||
* with the lock_upgrade, lock_upgrade_until, unlock_upgrade_and_lock,
|
||||
* unlock_and_lock_shared and unlock_upgrade_and_lock_shared functions
|
||||
*/
|
||||
|
||||
//[UpgradeLockable
|
||||
template <typename Mutex>
|
||||
struct UpgradeLockable
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( SharedLockable<Mutex> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(UpgradeLockable)
|
||||
{
|
||||
l.lock_upgrade();
|
||||
l.unlock_upgrade();
|
||||
if (l.try_lock_upgrade()) return;
|
||||
if (l.try_lock_upgrade_until(t)) return;
|
||||
if (l.try_lock_upgrade_for(d)) return;
|
||||
if (l.try_unlock_shared_and_lock()) return;
|
||||
if (l.try_unlock_shared_and_lock_until(t)) return;
|
||||
if (l.try_unlock_shared_and_lock_for(d)) return;
|
||||
l.unlock_and_lock_shared();
|
||||
if (l.try_unlock_shared_and_lock_upgrade()) return;
|
||||
if (l.try_unlock_shared_and_lock_upgrade_until(t)) return;
|
||||
if (l.try_unlock_shared_and_lock_upgrade_for(d)) return;
|
||||
l.unlock_and_lock_upgrade();
|
||||
l.unlock_upgrade_and_lock();
|
||||
if (l.try_unlock_upgrade_and_lock()) return;
|
||||
if (l.try_unlock_upgrade_and_lock_until(t)) return;
|
||||
if (l.try_unlock_upgrade_and_lock_for(d)) return;
|
||||
l.unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
UpgradeLockable() : l(*static_cast<Mutex*>(0)) {}
|
||||
private:
|
||||
UpgradeLockable operator=(UpgradeLockable const&);
|
||||
Mutex& l;
|
||||
chrono::system_clock::time_point t;
|
||||
chrono::system_clock::duration d;
|
||||
};
|
||||
//]
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,202 +0,0 @@
|
||||
// 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 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LOCKABLE_TRAITS_HPP
|
||||
#define BOOST_THREAD_LOCKABLE_TRAITS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
// todo make use of integral_constant, true_type and false_type
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
|
||||
#if defined(BOOST_NO_SFINAE) || \
|
||||
BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \
|
||||
BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
|
||||
#if ! defined BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
namespace detail
|
||||
{
|
||||
#define BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(member_name) \
|
||||
template<typename T, bool=boost::is_class<T>::value> \
|
||||
struct has_member_called_##member_name \
|
||||
{ \
|
||||
BOOST_STATIC_CONSTANT(bool, value=false); \
|
||||
}; \
|
||||
\
|
||||
template<typename T> \
|
||||
struct has_member_called_##member_name<T,true> \
|
||||
{ \
|
||||
typedef char true_type; \
|
||||
struct false_type \
|
||||
{ \
|
||||
true_type dummy[2]; \
|
||||
}; \
|
||||
\
|
||||
struct fallback { int member_name; }; \
|
||||
struct derived: \
|
||||
T, fallback \
|
||||
{ \
|
||||
derived(); \
|
||||
}; \
|
||||
\
|
||||
template<int fallback::*> struct tester; \
|
||||
\
|
||||
template<typename U> \
|
||||
static false_type has_member(tester<&U::member_name>*); \
|
||||
template<typename U> \
|
||||
static true_type has_member(...); \
|
||||
\
|
||||
BOOST_STATIC_CONSTANT( \
|
||||
bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \
|
||||
}
|
||||
|
||||
BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock)
|
||||
; BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock);
|
||||
BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock);
|
||||
|
||||
template<typename T,bool=has_member_called_lock<T>::value >
|
||||
struct has_member_lock
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_member_lock<T,true>
|
||||
{
|
||||
typedef char true_type;
|
||||
struct false_type
|
||||
{
|
||||
true_type dummy[2];
|
||||
};
|
||||
|
||||
template<typename U,typename V>
|
||||
static true_type has_member(V (U::*)());
|
||||
template<typename U>
|
||||
static false_type has_member(U);
|
||||
|
||||
BOOST_STATIC_CONSTANT(
|
||||
bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type));
|
||||
};
|
||||
|
||||
template<typename T,bool=has_member_called_unlock<T>::value >
|
||||
struct has_member_unlock
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_member_unlock<T,true>
|
||||
{
|
||||
typedef char true_type;
|
||||
struct false_type
|
||||
{
|
||||
true_type dummy[2];
|
||||
};
|
||||
|
||||
template<typename U,typename V>
|
||||
static true_type has_member(V (U::*)());
|
||||
template<typename U>
|
||||
static false_type has_member(U);
|
||||
|
||||
BOOST_STATIC_CONSTANT(
|
||||
bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type));
|
||||
};
|
||||
|
||||
template<typename T,bool=has_member_called_try_lock<T>::value >
|
||||
struct has_member_try_lock
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_member_try_lock<T,true>
|
||||
{
|
||||
typedef char true_type;
|
||||
struct false_type
|
||||
{
|
||||
true_type dummy[2];
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
static true_type has_member(bool (U::*)());
|
||||
template<typename U>
|
||||
static false_type has_member(U);
|
||||
|
||||
BOOST_STATIC_CONSTANT(
|
||||
bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct is_basic_lockable
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
|
||||
detail::has_member_unlock<T>::value);
|
||||
};
|
||||
template<typename T>
|
||||
struct is_lockable
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
is_basic_lockable<T>::value &&
|
||||
detail::has_member_try_lock<T>::value);
|
||||
};
|
||||
|
||||
#else
|
||||
template<typename T>
|
||||
struct is_basic_lockable
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
template<typename T>
|
||||
struct is_lockable
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
struct is_recursive_mutex_sur_parolle
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
template<typename T>
|
||||
struct is_recursive_basic_lockable
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable<T>::value &&
|
||||
is_recursive_mutex_sur_parolle<T>::value);
|
||||
};
|
||||
template<typename T>
|
||||
struct is_recursive_lockable
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = is_lockable<T>::value &&
|
||||
is_recursive_mutex_sur_parolle<T>::value);
|
||||
};
|
||||
}
|
||||
template<typename T>
|
||||
struct is_mutex_type
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable<T>::value);
|
||||
};
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
|
||||
// mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -18,36 +18,4 @@
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/thread/lockable_traits.hpp>
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
template<>
|
||||
struct is_basic_lockable<mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_lockable<mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_basic_lockable<timed_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_lockable<timed_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_NULL_MUTEX_HPP
|
||||
#define BOOST_THREAD_NULL_MUTEX_HPP
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
|
||||
/// \file
|
||||
/// Describes null_mutex class
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/// Implements a mutex that simulates a mutex without doing any operation and
|
||||
/// simulates a successful operation.
|
||||
class null_mutex
|
||||
{
|
||||
public:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( null_mutex) /*< no copyable >*/
|
||||
|
||||
/// Simulates a mutex lock() operation. Empty function.
|
||||
void lock()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock() operation.
|
||||
/// Equivalent to "return true;"
|
||||
bool try_lock()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex unlock() operation.
|
||||
/// Empty function.
|
||||
void unlock()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
/// Simulates a mutex try_lock_until() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock_for() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Simulates a mutex lock_shared() operation.
|
||||
/// Empty function.
|
||||
void lock_shared()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock_shared() operation.
|
||||
/// Equivalent to "return true;"
|
||||
bool try_lock_shared()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex unlock_shared() operation.
|
||||
/// Empty function.
|
||||
void unlock_shared()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock_shared_until() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
/// Simulates a mutex try_lock_shared_for() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex lock_upgrade() operation.
|
||||
/// Empty function.
|
||||
void lock_upgrade()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock_upgrade() operation.
|
||||
/// Equivalent to "return true;"
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex unlock_upgrade() operation.
|
||||
/// Empty function.
|
||||
void unlock_upgrade()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock_upgrade_until() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_lock_upgrade_for() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_unlock_shared_and_lock() operation.
|
||||
/// Equivalent to "return true;"
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
/// Simulates a mutex try_unlock_shared_and_lock_until() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_unlock_shared_and_lock_for() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Simulates unlock_and_lock_shared().
|
||||
/// Empty function.
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_unlock_shared_and_lock_upgrade() operation.
|
||||
/// Equivalent to "return true;"
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
/// Simulates a mutex try_unlock_shared_and_lock_upgrade_until() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_unlock_shared_and_lock_upgrade_for() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Simulates unlock_and_lock_upgrade().
|
||||
/// Empty function.
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates unlock_upgrade_and_lock().
|
||||
/// Empty function.
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_unlock_upgrade_and_lock() operation.
|
||||
/// Equivalent to "return true;"
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
/// Simulates a mutex try_unlock_upgrade_and_lock_until() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Simulates a mutex try_unlock_upgrade_and_lock_for() operation.
|
||||
/// Equivalent to "return true;"
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Simulates unlock_upgrade_and_lock_shared().
|
||||
/// Empty function.
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} //namespace boost {
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_POLY_LOCKABLE_HPP
|
||||
#define BOOST_THREAD_POLY_LOCKABLE_HPP
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//[basic_poly_lockable
|
||||
class basic_poly_lockable
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~basic_poly_lockable() = 0;
|
||||
|
||||
virtual void lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
//[poly_lockable
|
||||
class poly_lockable : public basic_poly_lockable<Lockable>
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~poly_lockable() = 0;
|
||||
virtual bool try_lock() = 0;
|
||||
};
|
||||
//]
|
||||
|
||||
//[timed_poly_lockable
|
||||
class timed_poly_lockable: public poly_lockable<TimedLock>
|
||||
{
|
||||
public:
|
||||
virtual ~timed_poly_lockable()=0;
|
||||
|
||||
virtual bool try_lock_until(chrono::system_clock::time_point const & abs_time)=0;
|
||||
virtual bool try_lock_until(chrono::steady_clock::time_point const & abs_time)=0;
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return try_lock_until(time_point_cast<Clock::time_point>(abs_time));
|
||||
}
|
||||
|
||||
virtual bool try_lock_for(chrono::nanoseconds const & relative_time)=0;
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return try_lock_for(duration_cast<Clock::duration>(rel_time));
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,89 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_POLY_LOCKABLE_ADAPTER_HPP
|
||||
#define BOOST_THREAD_POLY_LOCKABLE_ADAPTER_HPP
|
||||
|
||||
#include <boost/thread/poly_lockable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//[poly_basic_lockable_adapter
|
||||
template <typename Mutex, typename Base=poly_basic_lockable>
|
||||
class poly_basic_lockable_adapter : public Base
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
protected:
|
||||
mutex_type& mtx() const
|
||||
{
|
||||
return mtx_;
|
||||
}
|
||||
mutable mutex_type mtx_; /*< mutable so that it can be modified by const functions >*/
|
||||
public:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( poly_basic_lockable_adapter) /*< no copyable >*/
|
||||
|
||||
poly_basic_lockable_adapter()
|
||||
{}
|
||||
|
||||
void lock()
|
||||
{
|
||||
mtx().lock();
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
mtx().unlock();
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
//[poly_lockable_adapter
|
||||
template <typename Mutex, typename Base=poly_lockable>
|
||||
class poly_lockable_adapter : public poly_basic_lockable_adapter<Mutex, Base>
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return this->mtx().try_lock();
|
||||
}
|
||||
};
|
||||
//]
|
||||
|
||||
//[poly_timed_lockable_adapter
|
||||
template <typename Mutex, typename Base=poly_timed_lockable>
|
||||
class poly_timed_lockable_adapter: public poly_lockable_adapter<Mutex, Base>
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
bool try_lock_until(chrono::system_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_lock_until(abs_time);
|
||||
}
|
||||
bool try_lock_until(chrono::steady_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_lock_until(abs_time);
|
||||
}
|
||||
bool try_lock_for(chrono::nanoseconds const & rel_time)
|
||||
{
|
||||
return this->mtx().try_lock_for(rel_time);
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,135 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_POLY_SHARED_LOCKABLE_HPP
|
||||
#define BOOST_THREAD_POLY_SHARED_LOCKABLE_HPP
|
||||
|
||||
#include <boost/thread/poly_lockable.hpp>
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
|
||||
//[shared_poly_lockable
|
||||
class shared_poly_lockable: public timed_poly_lockable
|
||||
{
|
||||
public:
|
||||
virtual ~shared_poly_lockable() = 0;
|
||||
|
||||
virtual void lock_shared() = 0;
|
||||
virtual bool try_lock_shared() = 0;
|
||||
virtual void unlock_shared() = 0;
|
||||
|
||||
virtual bool try_lock_shared_until(chrono::system_clock::time_point const & abs_time)=0;
|
||||
virtual bool try_lock_shared_until(chrono::steady_clock::time_point const & abs_time)=0;
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return try_lock_shared_until(time_point_cast<Clock::time_point>(abs_time));
|
||||
}
|
||||
|
||||
virtual bool try_lock_shared_for(chrono::nanoseconds const & relative_time)=0;
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return try_lock_shared_for(duration_cast<Clock::duration>(rel_time));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//]
|
||||
|
||||
//[upgrade_poly_lockable
|
||||
class upgrade_poly_lockable: public shared_poly_lockable
|
||||
{
|
||||
public:
|
||||
virtual ~upgrade_poly_lockable() = 0;
|
||||
|
||||
virtual void lock_upgrade() = 0;
|
||||
virtual bool try_lock_upgrade() = 0;
|
||||
virtual void unlock_upgrade() = 0;
|
||||
|
||||
virtual bool try_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)=0;
|
||||
virtual bool try_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)=0;
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return try_lock_upgrade_until(time_point_cast<Clock::time_point>(abs_time));
|
||||
}
|
||||
|
||||
virtual bool try_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0;
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return try_lock_upgrade_for(duration_cast<Clock::duration>(rel_time));
|
||||
}
|
||||
|
||||
virtual bool try_unlock_shared_and_lock() = 0;
|
||||
|
||||
virtual bool try_unlock_shared_and_lock_until(chrono::system_clock::time_point const & abs_time)=0;
|
||||
virtual bool try_unlock_shared_and_lock_until(chrono::steady_clock::time_point const & abs_time)=0;
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_until(time_point_cast<Clock::time_point>(abs_time));
|
||||
}
|
||||
|
||||
virtual bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & relative_time)=0;
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_for(duration_cast<Clock::duration>(rel_time));
|
||||
}
|
||||
|
||||
virtual void unlock_and_lock_shared() = 0;
|
||||
virtual bool try_unlock_shared_and_lock_upgrade() = 0;
|
||||
|
||||
virtual bool try_unlock_shared_and_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)=0;
|
||||
virtual bool try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)=0;
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_upgrade_until(time_point_cast<Clock::time_point>(abs_time));
|
||||
}
|
||||
|
||||
virtual bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0;
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_upgrade_for(duration_cast<Clock::duration>(rel_time));
|
||||
}
|
||||
|
||||
virtual void unlock_and_lock_upgrade() = 0;
|
||||
virtual void unlock_upgrade_and_lock() = 0;
|
||||
virtual bool try_unlock_upgrade_and_lock() = 0;
|
||||
|
||||
virtual bool try_unlock_upgrade_and_lock_until(chrono::system_clock::time_point const & abs_time)=0;
|
||||
virtual bool try_unlock_upgrade_and_lock_until(chrono::steady_clock::time_point const & abs_time)=0;
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
{
|
||||
return try_unlock_upgrade_and_lock_until(time_point_cast<Clock::time_point>(abs_time));
|
||||
}
|
||||
|
||||
virtual bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & relative_time)=0;
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
{
|
||||
return try_unlock_upgrade_and_lock_for(duration_cast<Clock::duration>(rel_time));
|
||||
}
|
||||
|
||||
virtual void unlock_upgrade_and_lock_shared() = 0;
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,170 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. 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)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_POLY_SHARED_LOCKABLE_ADAPTER_HPP
|
||||
#define BOOST_THREAD_POLY_SHARED_LOCKABLE_ADAPTER_HPP
|
||||
|
||||
#include <boost/thread/poly_lockable_adapter.hpp>
|
||||
#include <boost/thread/poly_shared_lockable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//[shared_lockable_adapter
|
||||
template <typename Mutex, typename Base=poly_shared_lockable>
|
||||
class poly_shared_lockable_adapter: public poly_timed_lockable_adapter<Mutex, Base>
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
this->mtx().lock_shared();
|
||||
}
|
||||
bool try_lock_shared()
|
||||
{
|
||||
return this->mtx().try_lock_shared();
|
||||
}
|
||||
void unlock_shared()
|
||||
{
|
||||
this->mtx().unlock_shared();
|
||||
}
|
||||
|
||||
bool try_lock_shared_until(chrono::system_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_lock_shared_until(abs_time);
|
||||
}
|
||||
bool try_lock_shared_until(chrono::steady_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_lock_shared_until(abs_time);
|
||||
}
|
||||
bool try_lock_shared_for(chrono::nanoseconds const & rel_time)
|
||||
{
|
||||
return this->mtx().try_lock_shared_for(rel_time);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//]
|
||||
|
||||
//[upgrade_lockable_adapter
|
||||
template <typename Mutex, typename Base=poly_shared_lockable>
|
||||
class upgrade_lockable_adapter: public shared_lockable_adapter<Mutex, Base>
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
this->mtx().lock_upgrade();
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
return this->mtx().try_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
this->mtx().unlock_upgrade();
|
||||
}
|
||||
|
||||
bool try_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_lock_upgrade_until(abs_time);
|
||||
}
|
||||
bool try_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_lock_upgrade_until(abs_time);
|
||||
}
|
||||
bool try_lock_upgrade_for(chrono::nanoseconds const & rel_time)
|
||||
{
|
||||
return this->mtx().try_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock();
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock_until(chrono::system_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_until(abs_time);
|
||||
}
|
||||
bool try_unlock_shared_and_lock_until(chrono::steady_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & rel_time)
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
this->mtx().unlock_and_lock_shared();
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_upgrade();
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_upgrade_until(abs_time);
|
||||
}
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_upgrade_until(abs_time);
|
||||
}
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & rel_time)
|
||||
{
|
||||
return this->mtx().try_unlock_shared_and_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
this->mtx().unlock_and_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
this->mtx().unlock_upgrade_and_lock();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
return this->mtx().try_unlock_upgrade_and_lock();
|
||||
}
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::system_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_unlock_upgrade_and_lock_until(abs_time);
|
||||
}
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::steady_clock::time_point const & abs_time)
|
||||
{
|
||||
return this->mtx().try_unlock_upgrade_and_lock_until(abs_time);
|
||||
}
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & rel_time)
|
||||
{
|
||||
return this->mtx().try_unlock_upgrade_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
this->mtx().unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -4,13 +4,11 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-10 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2011 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#endif
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
@@ -22,12 +20,10 @@
|
||||
|
||||
namespace boost
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace thread_cv_detail
|
||||
{
|
||||
@@ -57,88 +53,57 @@ namespace boost
|
||||
|
||||
inline void condition_variable::wait(unique_lock<mutex>& m)
|
||||
{
|
||||
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if(! m.owns_lock())
|
||||
{
|
||||
boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned"));
|
||||
}
|
||||
#endif
|
||||
int res=0;
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
do {
|
||||
res = pthread_cond_wait(&cond,&internal_mutex);
|
||||
} while (res == EINTR);
|
||||
#else
|
||||
//boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
|
||||
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
|
||||
do {
|
||||
res = pthread_cond_wait(&cond,the_mutex);
|
||||
} while (res == EINTR);
|
||||
#endif
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
this_thread::interruption_point();
|
||||
#endif
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait"));
|
||||
boost::throw_exception(condition_error(res, "boost:: condition_variable constructor failed in pthread_cond_wait"));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool condition_variable::do_wait_until(
|
||||
inline bool condition_variable::do_timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
struct timespec const &timeout)
|
||||
{
|
||||
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if (!m.owns_lock())
|
||||
{
|
||||
boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned"));
|
||||
}
|
||||
#endif
|
||||
boost::throw_exception(condition_error(EPERM, "condition_variable do_timed_wait: mutex not locked"));
|
||||
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
int cond_res;
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
#else
|
||||
//boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
|
||||
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
|
||||
cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
|
||||
#endif
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
this_thread::interruption_point();
|
||||
#endif
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(cond_res)
|
||||
{
|
||||
boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait"));
|
||||
boost::throw_exception(condition_error(cond_res, "condition_variable failed in pthread_cond_timedwait"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_one() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
#endif
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_all() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
#endif
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
|
||||
@@ -154,13 +119,13 @@ namespace boost
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init"));
|
||||
boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_mutex_init"));
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
|
||||
boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_cond_init"));
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
@@ -175,20 +140,14 @@ namespace boost
|
||||
int res=0;
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<lock_type> guard;
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
#else
|
||||
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
|
||||
#endif
|
||||
guard.activate(m);
|
||||
res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
this_thread::interruption_point();
|
||||
#endif
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait"));
|
||||
boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_wait"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,12 +157,11 @@ namespace boost
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
struct timespec const timeout=detail::to_timespec(wait_until);
|
||||
return do_wait_until(m, timeout);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
return do_timed_wait(m, timeout);
|
||||
}
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until)
|
||||
@@ -239,7 +197,7 @@ namespace boost
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class lock_type,class Duration>
|
||||
cv_status
|
||||
@@ -307,26 +265,26 @@ namespace boost
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred)
|
||||
{
|
||||
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
|
||||
// while (!pred())
|
||||
// {
|
||||
// if (wait_for(lock, d) == cv_status::timeout)
|
||||
// return pred();
|
||||
// }
|
||||
// return true;
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_for(lock, d) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class lock_type>
|
||||
cv_status wait_until(
|
||||
inline void wait_until(
|
||||
lock_type& lk,
|
||||
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts = boost::detail::to_timespec(d);
|
||||
if (do_wait_until(lk, ts)) return cv_status::no_timeout;
|
||||
else return cv_status::timeout;
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
do_timed_wait(lk, ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -344,31 +302,25 @@ namespace boost
|
||||
private: // used by boost::thread::try_join_until
|
||||
|
||||
template <class lock_type>
|
||||
inline bool do_wait_until(
|
||||
inline bool do_timed_wait(
|
||||
lock_type& m,
|
||||
struct timespec const &timeout)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<lock_type> guard;
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
#else
|
||||
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
|
||||
#endif
|
||||
guard.activate(m);
|
||||
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
this_thread::interruption_point();
|
||||
#endif
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait"));
|
||||
boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_timedwait"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,26 +4,22 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2011 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/thread/cv_status.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -32,58 +28,33 @@ namespace boost
|
||||
class condition_variable
|
||||
{
|
||||
private:
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
pthread_mutex_t internal_mutex;
|
||||
#endif
|
||||
pthread_cond_t cond;
|
||||
|
||||
public:
|
||||
//private: // used by boost::thread::try_join_until
|
||||
|
||||
inline bool do_wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
struct timespec const &timeout);
|
||||
|
||||
bool do_wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
struct timespec const &timeout)
|
||||
{
|
||||
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now()));
|
||||
}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(condition_variable)
|
||||
condition_variable()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init"));
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: condition_variable constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
#endif
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
#endif
|
||||
boost::throw_exception(thread_resource_error(res2, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init"));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost:: condition_variable constructor failed in pthread_cond_init"));
|
||||
}
|
||||
}
|
||||
~condition_variable()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
int ret;
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
do {
|
||||
ret = pthread_mutex_destroy(&internal_mutex);
|
||||
} while (ret == EINTR);
|
||||
BOOST_ASSERT(!ret);
|
||||
#endif
|
||||
do {
|
||||
ret = pthread_cond_destroy(&cond);
|
||||
} while (ret == EINTR);
|
||||
BOOST_ASSERT(!ret);
|
||||
BOOST_VERIFY(!ret);
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& m);
|
||||
@@ -95,17 +66,16 @@ namespace boost
|
||||
}
|
||||
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until)
|
||||
{
|
||||
#if defined BOOST_THREAD_WAIT_BUG
|
||||
struct timespec const timeout=detail::to_timespec(wait_until + BOOST_THREAD_WAIT_BUG);
|
||||
return do_wait_until(m, timeout);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until + BOOST_THREAD_WAIT_BUG);
|
||||
return do_timed_wait(m, timeout);
|
||||
#else
|
||||
struct timespec const timeout=detail::to_timespec(wait_until);
|
||||
return do_wait_until(m, timeout);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
return do_timed_wait(m, timeout);
|
||||
#endif
|
||||
}
|
||||
bool timed_wait(
|
||||
@@ -151,7 +121,6 @@ namespace boost
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
@@ -221,14 +190,12 @@ namespace boost
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred)
|
||||
{
|
||||
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
|
||||
|
||||
// while (!pred())
|
||||
// {
|
||||
// if (wait_for(lock, d) == cv_status::timeout)
|
||||
// return pred();
|
||||
// }
|
||||
// return true;
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_for(lock, d) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -243,24 +210,27 @@ namespace boost
|
||||
void notify_all() BOOST_NOEXCEPT;
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
inline cv_status wait_until(
|
||||
inline void wait_until(
|
||||
unique_lock<mutex>& lk,
|
||||
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts = boost::detail::to_timespec(d);
|
||||
if (do_wait_until(lk, ts)) return cv_status::no_timeout;
|
||||
else return cv_status::timeout;
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
do_timed_wait(lk, ts);
|
||||
}
|
||||
#endif
|
||||
//private: // used by boost::thread::try_join_until
|
||||
|
||||
inline bool do_timed_wait(
|
||||
unique_lock<mutex>& lock,
|
||||
struct timespec const &timeout);
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,13 +6,10 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#endif
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
@@ -74,15 +71,12 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int res;
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_unlock(&m);
|
||||
} while (res == EINTR);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_lock"));
|
||||
}
|
||||
ret = pthread_mutex_unlock(&m);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
@@ -92,8 +86,12 @@ namespace boost
|
||||
{
|
||||
res = pthread_mutex_trylock(&m);
|
||||
} while (res == EINTR);
|
||||
if (res==EBUSY)
|
||||
if(res && (res!=EBUSY))
|
||||
{
|
||||
// The following throw_exception has been replaced by an assertion and just return false,
|
||||
// as this is an internal error and the user can do nothing with the exception.
|
||||
//boost::throw_exception(lock_error(res,"boost: mutex try_lock failed in pthread_mutex_trylock"));
|
||||
BOOST_ASSERT_MSG(false ,"boost: mutex try_lock failed in pthread_mutex_trylock");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -107,10 +105,8 @@ namespace boost
|
||||
return &m;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
@@ -150,7 +146,6 @@ namespace boost
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
@@ -160,47 +155,23 @@ namespace boost
|
||||
{
|
||||
return timed_lock(system_time(absolute_time));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_lock(&m);
|
||||
} while (res == EINTR);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_unlock(&m);
|
||||
} while (res == EINTR);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_lock"));
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_trylock(&m);
|
||||
} while (res == EINTR);
|
||||
if (res==EBUSY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !res;
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,13 +232,12 @@ namespace boost
|
||||
public:
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const ts=boost::detail::to_timespec(abs_time);
|
||||
struct timespec const ts=detail::get_timespec(abs_time);
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -291,9 +261,12 @@ namespace boost
|
||||
}
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
//using namespace chrono;
|
||||
chrono::nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts = boost::detail::to_timespec(d);
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
#endif
|
||||
@@ -305,11 +278,9 @@ namespace boost
|
||||
return &m;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -12,34 +12,19 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <pthread.h>
|
||||
#include <csignal>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
|
||||
|
||||
namespace thread_detail
|
||||
{
|
||||
//#ifdef SIG_ATOMIC_MAX
|
||||
// typedef sig_atomic_t uintmax_atomic_t;
|
||||
// #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C SIG_ATOMIC_MAX
|
||||
//#else
|
||||
typedef unsigned long uintmax_atomic_t;
|
||||
#define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##ul
|
||||
#define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0)
|
||||
//#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
@@ -49,7 +34,7 @@ namespace boost
|
||||
: epoch(BOOST_ONCE_INITIAL_FLAG_VALUE)
|
||||
{}
|
||||
private:
|
||||
volatile thread_detail::uintmax_atomic_t epoch;
|
||||
boost::uintmax_t epoch;
|
||||
template<typename Function>
|
||||
friend
|
||||
void call_once(once_flag& flag,Function f);
|
||||
@@ -59,7 +44,7 @@ namespace boost
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
volatile thread_detail::uintmax_atomic_t epoch;
|
||||
boost::uintmax_t epoch;
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
|
||||
@@ -67,8 +52,8 @@ namespace boost
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL thread_detail::uintmax_atomic_t& get_once_per_thread_epoch();
|
||||
BOOST_THREAD_DECL extern thread_detail::uintmax_atomic_t once_global_epoch;
|
||||
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
|
||||
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
|
||||
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
|
||||
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
|
||||
}
|
||||
@@ -78,10 +63,10 @@ namespace boost
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
|
||||
static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
|
||||
thread_detail::uintmax_atomic_t const epoch=flag.epoch;
|
||||
thread_detail::uintmax_atomic_t& this_thread_epoch=detail::get_once_per_thread_epoch();
|
||||
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
|
||||
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
|
||||
boost::uintmax_t const epoch=flag.epoch;
|
||||
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
@@ -92,18 +77,21 @@ namespace boost
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
|
||||
f();
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
catch(...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
throw;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
#endif
|
||||
flag.epoch=--detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
#include <pthread.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#endif
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifndef _WIN32
|
||||
@@ -112,7 +110,7 @@ namespace boost
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock() BOOST_NOEXCEPT
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
@@ -169,10 +167,8 @@ namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
@@ -236,13 +232,11 @@ namespace boost
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
void lock()
|
||||
@@ -300,7 +294,7 @@ namespace boost
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock() BOOST_NOEXCEPT
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && !pthread_equal(owner,pthread_self()))
|
||||
@@ -340,13 +334,12 @@ namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const ts=detail::to_timespec(abs_time);
|
||||
struct timespec const ts=detail::get_timespec(abs_time);
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -370,9 +363,12 @@ namespace boost
|
||||
}
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
//using namespace chrono;
|
||||
chrono::nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts = boost::detail::to_timespec(d);
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
#endif
|
||||
@@ -384,11 +380,9 @@ namespace boost
|
||||
return &m;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
@@ -65,10 +63,8 @@ namespace boost
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
@@ -79,7 +75,7 @@ namespace boost
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
@@ -92,13 +88,10 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
@@ -116,7 +109,6 @@ namespace boost
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -126,10 +118,8 @@ namespace boost
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
@@ -144,7 +134,7 @@ namespace boost
|
||||
#endif
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
@@ -165,10 +155,8 @@ namespace boost
|
||||
|
||||
void lock()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
@@ -178,13 +166,10 @@ namespace boost
|
||||
state.exclusive=true;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
@@ -209,7 +194,7 @@ namespace boost
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -219,10 +204,8 @@ namespace boost
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
@@ -245,7 +228,7 @@ namespace boost
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
@@ -261,7 +244,7 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
@@ -269,10 +252,8 @@ namespace boost
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
@@ -281,13 +262,10 @@ namespace boost
|
||||
state.upgrade=true;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
@@ -309,7 +287,7 @@ namespace boost
|
||||
{
|
||||
return timed_lock_upgrade(get_system_time()+relative_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -319,10 +297,8 @@ namespace boost
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
|
||||
@@ -341,7 +317,7 @@ namespace boost
|
||||
#endif
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
@@ -356,7 +332,7 @@ namespace boost
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
@@ -372,10 +348,8 @@ namespace boost
|
||||
// Upgrade <-> Exclusive
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
--state.shared_count;
|
||||
while(state.shared_count)
|
||||
{
|
||||
@@ -387,7 +361,7 @@ namespace boost
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
@@ -397,7 +371,7 @@ namespace boost
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& state.upgrade
|
||||
@@ -424,10 +398,8 @@ namespace boost
|
||||
try_unlock_upgrade_and_lock_until(
|
||||
const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if (state.shared_count != 1)
|
||||
{
|
||||
for (;;)
|
||||
@@ -450,7 +422,7 @@ namespace boost
|
||||
// Shared <-> Exclusive
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
@@ -460,7 +432,7 @@ namespace boost
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& !state.upgrade
|
||||
@@ -486,10 +458,8 @@ namespace boost
|
||||
try_unlock_shared_and_lock_until(
|
||||
const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if (state.shared_count != 1)
|
||||
{
|
||||
for (;;)
|
||||
@@ -513,7 +483,7 @@ namespace boost
|
||||
// Shared <-> Upgrade
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
@@ -522,7 +492,7 @@ namespace boost
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& !state.upgrade
|
||||
@@ -547,10 +517,8 @@ namespace boost
|
||||
try_unlock_shared_and_lock_upgrade_until(
|
||||
const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( state.exclusive
|
||||
|| state.exclusive_waiting_blocked
|
||||
|| state.upgrade
|
||||
|
||||
@@ -8,30 +8,18 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
#include <map>
|
||||
#include <unistd.h>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <asm/page.h> // http://code.google.com/p/android/issues/detail?id=39983
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -82,7 +70,6 @@ namespace boost
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct future_object_base;
|
||||
struct tss_cleanup_function;
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node
|
||||
@@ -113,55 +100,27 @@ namespace boost
|
||||
bool joined;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
std::map<void const*,boost::detail::tss_data_node> tss_data;
|
||||
|
||||
pthread_mutex_t* cond_mutex;
|
||||
pthread_cond_t* current_cond;
|
||||
typedef std::vector<std::pair<condition_variable*, mutex*>
|
||||
//, hidden_allocator<std::pair<condition_variable*, mutex*> >
|
||||
> notify_list_t;
|
||||
notify_list_t notify;
|
||||
|
||||
typedef std::vector<shared_ptr<future_object_base> > async_states_t;
|
||||
async_states_t async_states_;
|
||||
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// These data must be at the end so that the access to the other fields doesn't change
|
||||
// when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined.
|
||||
// Another option is to have them always
|
||||
bool interrupt_enabled;
|
||||
bool interrupt_requested;
|
||||
//#endif
|
||||
pthread_mutex_t* cond_mutex;
|
||||
pthread_cond_t* current_cond;
|
||||
|
||||
thread_data_base():
|
||||
done(false),join_started(false),joined(false),
|
||||
thread_exit_callbacks(0),
|
||||
current_cond(0),
|
||||
notify(),
|
||||
async_states_()
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
, interrupt_enabled(true)
|
||||
, interrupt_requested(false)
|
||||
//#endif
|
||||
interrupt_enabled(true),
|
||||
interrupt_requested(false),
|
||||
current_cond(0)
|
||||
{}
|
||||
virtual ~thread_data_base();
|
||||
|
||||
typedef pthread_t native_handle_type;
|
||||
|
||||
virtual void run()=0;
|
||||
virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m)
|
||||
{
|
||||
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
|
||||
}
|
||||
|
||||
void make_ready_at_thread_exit(shared_ptr<future_object_base> as)
|
||||
{
|
||||
async_states_.push_back(as);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
class interruption_checker
|
||||
{
|
||||
thread_data_base* const thread_info;
|
||||
@@ -170,13 +129,11 @@ namespace boost
|
||||
|
||||
void check_for_interruption()
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected
|
||||
throw thread_interrupted();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator=(interruption_checker&);
|
||||
@@ -213,47 +170,35 @@ namespace boost
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
|
||||
inline
|
||||
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
|
||||
{
|
||||
return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns));
|
||||
}
|
||||
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns);
|
||||
#endif
|
||||
#endif // BOOST_THREAD_USES_CHRONO
|
||||
|
||||
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#ifdef __DECXXX
|
||||
/// Workaround of DECCXX issue of incorrect template substitution
|
||||
template<>
|
||||
#endif
|
||||
inline void sleep(system_time const& abs_time)
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
return boost::this_thread::hiden::sleep_until(boost::detail::to_timespec(abs_time));
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
template<>
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
#else
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
#endif // BOOST_THREAD_USES_DATETIME
|
||||
} // this_thread
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace boost
|
||||
return new T();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ namespace boost
|
||||
{
|
||||
return heap_new_impl<T,A1&>(a1);
|
||||
}
|
||||
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2)
|
||||
{
|
||||
@@ -218,8 +218,8 @@ namespace boost
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
inline void heap_delete(T* data)
|
||||
{
|
||||
|
||||
@@ -1,118 +1,34 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_TIMESPEC_MAC_API
|
||||
#include <sys/time.h> //for gettimeofday and timeval
|
||||
#else
|
||||
#include <time.h> // for clock_gettime
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline struct timespec to_timespec(boost::system_time const& abs_time)
|
||||
namespace detail
|
||||
{
|
||||
struct timespec timeout = { 0,0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
timeout.tv_sec=time_since_epoch.total_seconds();
|
||||
timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
|
||||
return timeout;
|
||||
inline struct timespec get_timespec(boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec timeout={0,0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
timeout.tv_sec=time_since_epoch.total_seconds();
|
||||
timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
inline timespec to_timespec(chrono::nanoseconds const& ns)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = static_cast<long>(chrono::duration_cast<chrono::seconds>(ns).count());
|
||||
ts.tv_nsec = static_cast<long>((ns - chrono::duration_cast<chrono::seconds>(ns)).count());
|
||||
return ts;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline timespec to_timespec(boost::intmax_t const& ns)
|
||||
{
|
||||
boost::intmax_t s = ns / 1000000000l;
|
||||
struct timespec ts;
|
||||
ts.tv_sec = static_cast<long> (s);
|
||||
ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
|
||||
return ts;
|
||||
}
|
||||
inline boost::intmax_t to_nanoseconds_int_max(timespec const& ts)
|
||||
{
|
||||
return static_cast<boost::intmax_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
|
||||
}
|
||||
inline bool timespec_ge_zero(timespec const& ts)
|
||||
{
|
||||
return (ts.tv_sec >= 0) || (ts.tv_nsec >= 0);
|
||||
}
|
||||
inline timespec timespec_now()
|
||||
{
|
||||
timespec ts;
|
||||
|
||||
#if defined(BOOST_THREAD_TIMESPEC_MAC_API)
|
||||
timeval tv;
|
||||
::gettimeofday(&tv, 0);
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
#else
|
||||
if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
|
||||
}
|
||||
#endif
|
||||
return ts;
|
||||
}
|
||||
inline timespec timespec_zero()
|
||||
{
|
||||
timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
return ts;
|
||||
}
|
||||
inline timespec timespec_plus(timespec const& lhs, timespec const& rhs)
|
||||
{
|
||||
return to_timespec(to_nanoseconds_int_max(lhs) + to_nanoseconds_int_max(rhs));
|
||||
}
|
||||
inline timespec timespec_minus(timespec const& lhs, timespec const& rhs)
|
||||
{
|
||||
return to_timespec(to_nanoseconds_int_max(lhs) - to_nanoseconds_int_max(rhs));
|
||||
}
|
||||
inline bool timespec_gt(timespec const& lhs, timespec const& rhs)
|
||||
{
|
||||
return to_nanoseconds_int_max(lhs) > to_nanoseconds_int_max(rhs);
|
||||
}
|
||||
inline bool timespec_ge(timespec const& lhs, timespec const& rhs)
|
||||
{
|
||||
return to_nanoseconds_int_max(lhs) >= to_nanoseconds_int_max(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -18,47 +18,4 @@
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/thread/lockable_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
|
||||
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
template<>
|
||||
struct is_basic_lockable<recursive_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_lockable<recursive_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_basic_lockable<recursive_timed_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_lockable<recursive_timed_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct is_recursive_mutex_sur_parolle<recursive_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_recursive_mutex_sur_parolle<recursive_timed_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
#ifndef BOOST_THREAD_REVERSE_LOCK_HPP
|
||||
#define BOOST_THREAD_REVERSE_LOCK_HPP
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/lockable_traits.hpp>
|
||||
#include <boost/thread/lock_options.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -17,6 +15,7 @@ namespace boost
|
||||
template<typename Lock>
|
||||
class reverse_lock
|
||||
{
|
||||
|
||||
public:
|
||||
typedef typename Lock::mutex_type mutex_type;
|
||||
BOOST_THREAD_NO_COPYABLE(reverse_lock)
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
// 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 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
|
||||
// Based on the Anthony's idea of scoped_thread in CCiA
|
||||
|
||||
#ifndef BOOST_THREAD_SCOPED_THREAD_HPP
|
||||
#define BOOST_THREAD_SCOPED_THREAD_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/thread_functors.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
*
|
||||
* CallableThread: A callable void(thread&) .
|
||||
* The default is a join_if_joinable.
|
||||
*
|
||||
* thread std/boost::thread destructor terminates the program if the thread is not joinable.
|
||||
* Having a wrapper that can join the thread before destroying it seems a natural need.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* boost::strict_scoped_thread<> t((boost::thread(F)));
|
||||
*
|
||||
*/
|
||||
template <class CallableThread = join_if_joinable>
|
||||
class strict_scoped_thread
|
||||
{
|
||||
thread t_;
|
||||
public:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable
|
||||
|
||||
/**
|
||||
* Constructor from the thread to own.
|
||||
*
|
||||
* @param t: the thread to own.
|
||||
*
|
||||
* Effects: move the thread to own @c t.
|
||||
*/
|
||||
explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT :
|
||||
t_(boost::move(t))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
* Effects: Call the CallableThread functor before destroying the owned thread.
|
||||
* Remark: The CallableThread should not throw when joining the thread as the scoped variable is on a scope outside the thread function.
|
||||
*/
|
||||
~strict_scoped_thread()
|
||||
{
|
||||
CallableThread on_destructor;
|
||||
|
||||
on_destructor(t_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
*
|
||||
* CallableThread: A callable void(thread&) .
|
||||
* The default is join_if_joinable.
|
||||
*
|
||||
* thread std::thread destructor terminates the program if the thread is not joinable.
|
||||
* Having a wrapper that can join the thread before destroying it seems a natural need.
|
||||
*
|
||||
* Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type.
|
||||
* Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the
|
||||
* same non-deprecated interface with the exception of the construction.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* boost::scoped_thread<> t((boost::thread(F)));
|
||||
* t.interrupt();
|
||||
*
|
||||
*/
|
||||
template <class CallableThread = join_if_joinable>
|
||||
class scoped_thread
|
||||
{
|
||||
thread t_;
|
||||
public:
|
||||
|
||||
typedef thread::id id;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Effects: wraps a not-a-thread.
|
||||
*/
|
||||
scoped_thread() BOOST_NOEXCEPT:
|
||||
t_()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from the thread to own.
|
||||
*
|
||||
* @param t: the thread to own.
|
||||
*
|
||||
* Effects: move the thread to own @c t.
|
||||
*/
|
||||
explicit scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT :
|
||||
t_(boost::move(t))
|
||||
{
|
||||
}
|
||||
|
||||
// explicit operator thread()
|
||||
// {
|
||||
// return boost::move(t_);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Move constructor.
|
||||
*/
|
||||
scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT :
|
||||
t_(boost::move(x.t_))
|
||||
{}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* Effects: Call the CallableThread functor before destroying the owned thread.
|
||||
*/
|
||||
~scoped_thread()
|
||||
{
|
||||
CallableThread on_destructor;
|
||||
|
||||
on_destructor(t_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move assignment.
|
||||
*/
|
||||
scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x)
|
||||
{
|
||||
t_ = boost::move(x.t_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void swap(scoped_thread& x) BOOST_NOEXCEPT
|
||||
{
|
||||
t_.swap(x.t_);
|
||||
}
|
||||
|
||||
// forwarded thread functions
|
||||
inline thread::id get_id() const BOOST_NOEXCEPT
|
||||
{
|
||||
return t_.get_id();
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
t_.detach();
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
t_.join();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return t_.try_join_for(rel_time);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
return t_.try_join_until(abs_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
thread::native_handle_type native_handle()BOOST_NOEXCEPT
|
||||
{
|
||||
return t_.native_handle();
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void interrupt()
|
||||
{
|
||||
t_.interrupt();
|
||||
}
|
||||
|
||||
bool interruption_requested() const BOOST_NOEXCEPT
|
||||
{
|
||||
return t_.interruption_requested();
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned hardware_concurrency()BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Effects: swaps the contents of two scoped threads.
|
||||
*/
|
||||
template <class Destroyer>
|
||||
void swap(scoped_thread<Destroyer>& lhs, scoped_thread<Destroyer>& rhs)
|
||||
BOOST_NOEXCEPT {
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -6,8 +6,7 @@
|
||||
#ifndef BOOST_THREAD_SHARED_LOCK_GUARD_HPP
|
||||
#define BOOST_THREAD_SHARED_LOCK_GUARD_HPP
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
//#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/lock_options.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
namespace boost
|
||||
|
||||
@@ -23,26 +23,4 @@
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/thread/lockable_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
template<>
|
||||
struct is_basic_lockable<shared_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<>
|
||||
struct is_lockable<shared_mutex>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
// 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 2008-2009,2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_STRICT_LOCK_HPP
|
||||
#define BOOST_THREAD_STRICT_LOCK_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/lockable_wrapper.hpp>
|
||||
#include <boost/thread/lock_options.hpp>
|
||||
#include <boost/thread/lock_traits.hpp>
|
||||
#include <boost/thread/lockable_traits.hpp>
|
||||
#include <boost/thread/lockable_concepts.hpp>
|
||||
#include <boost/thread/lock_concepts.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
|
||||
//[strict_lock
|
||||
template <typename Lockable>
|
||||
class strict_lock
|
||||
{
|
||||
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<Lockable> ));
|
||||
public:
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
// construct/copy/destroy:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( strict_lock)
|
||||
|
||||
/**
|
||||
* Constructor from a mutex reference.
|
||||
*
|
||||
* @param mtx the mutex to lock.
|
||||
*
|
||||
* __Effects: Stores a reference to the mutex to lock and locks it.
|
||||
* __Throws: Any exception BasicMutex::lock() can throw.
|
||||
*/
|
||||
explicit strict_lock(mutex_type& mtx) :
|
||||
mtx_(mtx)
|
||||
{
|
||||
mtx.lock();
|
||||
} /*< locks on construction >*/
|
||||
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
strict_lock(std::initializer_list<thread_detail::lockable_wrapper<Lockable> > l_) :
|
||||
mtx_(*(const_cast<thread_detail::lockable_wrapper<Lockable>*>(l_.begin())->m))
|
||||
{
|
||||
mtx_.lock();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* __Effects: unlocks the stored mutex.
|
||||
*
|
||||
* __Throws
|
||||
*/
|
||||
~strict_lock()
|
||||
{
|
||||
mtx_.unlock();
|
||||
} /*< unlocks on destruction >*/
|
||||
|
||||
|
||||
// observers
|
||||
private:
|
||||
|
||||
/**
|
||||
* @return the owned mutex.
|
||||
*/
|
||||
const mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return &mtx_;
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* @return whether this lock is locking that mutex.
|
||||
*/
|
||||
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT
|
||||
{
|
||||
return l == mutex();
|
||||
} /*< strict locks specific function >*/
|
||||
|
||||
//BOOST_ADRESS_OF_DELETE(strict_lock) /*< disable aliasing >*/
|
||||
//BOOST_HEAP_ALLOCATION_DELETE(strict_lock) /*< disable heap allocation >*/
|
||||
|
||||
/*< no possibility to unlock >*/
|
||||
|
||||
private:
|
||||
mutex_type& mtx_;
|
||||
};
|
||||
//]
|
||||
template <typename Lockable>
|
||||
struct is_strict_lock_sur_parolle<strict_lock<Lockable> > : true_type
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* A nested strict lock is a scoped lock guard ensuring the mutex is locked on its
|
||||
* scope, by taking ownership of an nesting lock, locking the mutex on construction if not already locked
|
||||
* and restoring the ownership to the nesting lock on destruction.
|
||||
*/
|
||||
//[nested_strict_lock
|
||||
template <typename Lock>
|
||||
class nested_strict_lock
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT(( BasicLock<Lock> )); /*< The Lock must be a movable lock >*/
|
||||
public:
|
||||
typedef typename Lock::mutex_type mutex_type; /*< Name the lockable type locked by Lock >*/
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( nested_strict_lock)
|
||||
|
||||
/**
|
||||
* Constructor from a nesting @c Lock.
|
||||
*
|
||||
* @param lk the nesting lock
|
||||
*
|
||||
* __Requires: <c>lk.mutex() != null_ptr</c>
|
||||
* __Effects: Stores the reference to the lock parameter and takes ownership on it.
|
||||
* If the lock doesn't owns the mutex @c mtx lock it.
|
||||
* __Postconditions: @c owns_lock(lk.mutex())
|
||||
* __StrongException
|
||||
* __Throws:
|
||||
*
|
||||
* - lock_error when BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and lk.mutex() == null_ptr
|
||||
*
|
||||
* - Any exception that @c lk.lock() can throw.
|
||||
*
|
||||
*/
|
||||
explicit nested_strict_lock(Lock& lk) :
|
||||
lk_(lk) /*< Store reference to lk >*/
|
||||
{
|
||||
/*< Define BOOST_THREAD_DONT_CHECK_PRECONDITIONS if you don't want to check lk ownership >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk.mutex() != 0,
|
||||
lock_error()
|
||||
);
|
||||
if (!lk.owns_lock()) lk.lock(); /*< ensures it is locked >*/
|
||||
tmp_lk_ = move(lk); /*< Move ownership to temporary lk >*/
|
||||
}
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
|
||||
nested_strict_lock(std::initializer_list<thread_detail::lockable_wrapper<Lock> > l_) :
|
||||
lk_(*(const_cast<thread_detail::lockable_wrapper<Lock>*>(l_.begin())->m))
|
||||
{
|
||||
/*< Define BOOST_THREAD_DONT_CHECK_PRECONDITIONS if you don't want to check lk ownership >*/
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( lk_.mutex() != 0,
|
||||
lock_error()
|
||||
);
|
||||
if (!lk_.owns_lock()) lk_.lock(); /*< ensures it is locked >*/
|
||||
tmp_lk_ = move(lk_); /*< Move ownership to temporary lk >*/
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* __Effects: Restores ownership to the nesting lock.
|
||||
*/
|
||||
~nested_strict_lock()BOOST_NOEXCEPT
|
||||
{
|
||||
lk_ = move(tmp_lk_); /*< Move ownership to nesting lock >*/
|
||||
}
|
||||
|
||||
// observers
|
||||
private:
|
||||
/**
|
||||
* return @c the owned mutex.
|
||||
*/
|
||||
const mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return tmp_lk_.mutex();
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* @return whether if this lock is locking that mutex.
|
||||
*/
|
||||
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT
|
||||
{
|
||||
return l == mutex();
|
||||
}
|
||||
|
||||
//BOOST_ADRESS_OF_DELETE(nested_strict_lock)
|
||||
//BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
|
||||
|
||||
private:
|
||||
Lock& lk_;
|
||||
Lock tmp_lk_;
|
||||
};
|
||||
//]
|
||||
|
||||
template <typename Lock>
|
||||
struct is_strict_lock_sur_parolle<nested_strict_lock<Lock> > : true_type
|
||||
{
|
||||
};
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_MAKE_STRICT_LOCK
|
||||
template <typename Lockable>
|
||||
strict_lock<Lockable> make_strict_lock(Lockable& mtx)
|
||||
{
|
||||
return { thread_detail::lockable_wrapper<Lockable>(mtx) };
|
||||
}
|
||||
template <typename Lock>
|
||||
nested_strict_lock<Lock> make_nested_strict_lock(Lock& lk)
|
||||
{
|
||||
return { thread_detail::lockable_wrapper<Lock>(lk) };
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,513 +0,0 @@
|
||||
// (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
|
||||
// (C) Copyright 2012 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)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_SYNCHRONIZED_VALUE_HPP
|
||||
#define BOOST_THREAD_SYNCHRONIZED_VALUE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#include <boost/thread/lock_factories.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
#include <boost/utility/swap.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class const_strict_lock_ptr
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
protected:
|
||||
|
||||
// this should be a strict_lock, but we need to be able to return it.
|
||||
boost::unique_lock<lockable_type> lk_;
|
||||
T const& value_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( const_strict_lock_ptr )
|
||||
|
||||
const_strict_lock_ptr(T const& value, Lockable & mtx) :
|
||||
lk_(mtx), value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other)
|
||||
: lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
|
||||
{
|
||||
}
|
||||
|
||||
~const_strict_lock_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
return &value_;
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable>
|
||||
{
|
||||
typedef const_strict_lock_ptr<T,Lockable> base_type;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( strict_lock_ptr )
|
||||
|
||||
strict_lock_ptr(T & value, Lockable & mtx) :
|
||||
base_type(value, mtx)
|
||||
{
|
||||
}
|
||||
|
||||
strict_lock_ptr(BOOST_THREAD_RV_REF(strict_lock_ptr) other)
|
||||
: base_type(boost::move(static_cast<base_type&>(other)))
|
||||
{
|
||||
}
|
||||
|
||||
~strict_lock_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
return const_cast<T*>(&this->value_);
|
||||
}
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
return const_cast<T&>(this->value_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class const_unique_lock_ptr : public unique_lock<Lockable>
|
||||
{
|
||||
typedef unique_lock<Lockable> base_type;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
protected:
|
||||
T const& value_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(const_unique_lock_ptr)
|
||||
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx)
|
||||
: base_type(mtx), value_(value)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx, adopt_lock_t)
|
||||
: base_type(mtx, adopt_lock), value_(value)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx, defer_lock_t)
|
||||
: base_type(mtx, defer_lock), value_(value)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx, try_to_lock_t)
|
||||
: base_type(mtx, try_to_lock), value_(value)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other)
|
||||
: base_type(boost::move(static_cast<base_type&>(other))), value_(BOOST_THREAD_RV(other).value_)
|
||||
{
|
||||
}
|
||||
|
||||
~const_unique_lock_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
return &value_;
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
return value_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class unique_lock_ptr : public const_unique_lock_ptr<T, Lockable>
|
||||
{
|
||||
typedef const_unique_lock_ptr<T, Lockable> base_type;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(unique_lock_ptr)
|
||||
|
||||
unique_lock_ptr(T & value, Lockable & mtx)
|
||||
: base_type(value, mtx)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t)
|
||||
: base_type(value, mtx, adopt_lock)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t)
|
||||
: base_type(value, mtx, defer_lock)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t)
|
||||
: base_type(value, mtx, try_to_lock)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other)
|
||||
: base_type(boost::move(static_cast<base_type&>(other)))
|
||||
{
|
||||
}
|
||||
|
||||
~unique_lock_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
return const_cast<T*>(&this->value_);
|
||||
}
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
return const_cast<T&>(this->value_);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class synchronized_value
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
private:
|
||||
T value_;
|
||||
mutable lockable_type mtx_;
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* Requires: T is DefaultConstructible
|
||||
*/
|
||||
synchronized_value()
|
||||
: value_()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from copy constructible value.
|
||||
*
|
||||
* Requires: T is CopyConstructible
|
||||
*/
|
||||
synchronized_value(T const& other)
|
||||
: value_(other)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Move Constructor from movable value.
|
||||
*
|
||||
* Requires: T is Movable
|
||||
*/
|
||||
synchronized_value(BOOST_THREAD_RV_REF(T) other)
|
||||
: value_(boost::move(other))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
*
|
||||
* Requires: T is DefaultConstructible and Assignable
|
||||
* Effects: Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.
|
||||
*/
|
||||
synchronized_value(synchronized_value const& rhs)
|
||||
{
|
||||
strict_lock<lockable_type> lk(rhs.mtx_);
|
||||
value_ = rhs.value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move Constructor.
|
||||
*
|
||||
*/
|
||||
synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other)
|
||||
{
|
||||
strict_lock<lockable_type> lk(other.mtx_);
|
||||
value_= boost::move(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assignment operator.
|
||||
*
|
||||
* Effects: Copies the underlying value on a scope protected by the two mutexes.
|
||||
* The mutexes are not copied. The locks are acquired using lock, so deadlock is avoided.
|
||||
* For example, there is no problem if one thread assigns a = b and the other assigns b = a.
|
||||
*
|
||||
* Return: *this
|
||||
*/
|
||||
|
||||
synchronized_value& operator=(synchronized_value const& rhs)
|
||||
{
|
||||
if(&rhs != this)
|
||||
{
|
||||
// auto _ = make_unique_locks(mtx_, rhs.mtx_);
|
||||
unique_lock<lockable_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<lockable_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
value_ = rhs.value_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Assignment operator from a T const&.
|
||||
* Effects: The operator copies the value on a scope protected by the mutex.
|
||||
* Return: *this
|
||||
*/
|
||||
synchronized_value& operator=(value_type const& value)
|
||||
{
|
||||
{
|
||||
strict_lock<lockable_type> lk(mtx_);
|
||||
value_ = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicit conversion to value type.
|
||||
*
|
||||
* Requires: T is CopyConstructible
|
||||
* Return: A copy of the protected value obtained on a scope protected by the mutex.
|
||||
*
|
||||
*/
|
||||
T get() const
|
||||
{
|
||||
strict_lock<lockable_type> lk(mtx_);
|
||||
return value_;
|
||||
}
|
||||
/**
|
||||
* Explicit conversion to value type.
|
||||
*
|
||||
* Requires: T is CopyConstructible
|
||||
* Return: A copy of the protected value obtained on a scope protected by the mutex.
|
||||
*
|
||||
*/
|
||||
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
explicit operator T() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Swap
|
||||
*
|
||||
* Effects: Swaps the data. Again, locks are acquired using lock(). The mutexes are not swapped.
|
||||
* A swap method accepts a T& and swaps the data inside a critical section.
|
||||
* This is by far the preferred method of changing the guarded datum wholesale because it keeps the lock only
|
||||
* for a short time, thus lowering the pressure on the mutex.
|
||||
*/
|
||||
void swap(synchronized_value & rhs)
|
||||
{
|
||||
if (this == &rhs) {
|
||||
return;
|
||||
}
|
||||
// auto _ = make_unique_locks(mtx_, rhs.mtx_);
|
||||
unique_lock<lockable_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<lockable_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
boost::swap(value_, rhs.value_);
|
||||
}
|
||||
/**
|
||||
* Swap with the underlying type
|
||||
*
|
||||
* Effects: Swaps the data on a scope protected by the mutex.
|
||||
*/
|
||||
void swap(value_type & rhs)
|
||||
{
|
||||
strict_lock<lockable_type> lk(mtx_);
|
||||
boost::swap(value_, rhs.value_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Essentially calling a method obj->foo(x, y, z) calls the method foo(x, y, z) inside a critical section as
|
||||
* long-lived as the call itself.
|
||||
*/
|
||||
strict_lock_ptr<T,Lockable> operator->()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
/**
|
||||
* If the synchronized_value object involved is const-qualified, then you'll only be able to call const methods
|
||||
* through operator->. So, for example, vec->push_back("xyz") won't work if vec were const-qualified.
|
||||
* The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data.
|
||||
*/
|
||||
const_strict_lock_ptr<T,Lockable> operator->() const
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
|
||||
/**
|
||||
* The synchronize() factory make easier to lock on a scope.
|
||||
* As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations.
|
||||
* With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope.
|
||||
*
|
||||
* Example
|
||||
* void fun(synchronized_value<vector<int>> & vec) {
|
||||
* auto&& vec=vec.synchronize();
|
||||
* vec.push_back(42);
|
||||
* assert(vec.back() == 42);
|
||||
* }
|
||||
*/
|
||||
strict_lock_ptr<T,Lockable> synchronize()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
const_strict_lock_ptr<T,Lockable> synchronize() const
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
|
||||
unique_lock_ptr<T,Lockable> unique_synchronize()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag)
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
|
||||
}
|
||||
const_unique_lock_ptr<T,Lockable> unique_synchronize() const
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
const_unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag) const
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
class deref_value
|
||||
{
|
||||
private:
|
||||
friend class synchronized_value;
|
||||
|
||||
boost::unique_lock<lockable_type> lk_;
|
||||
T& value_;
|
||||
|
||||
explicit deref_value(synchronized_value& outer):
|
||||
lk_(outer.mtx_),value_(outer.value_)
|
||||
{}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(deref_value)
|
||||
|
||||
deref_value(BOOST_THREAD_RV_REF(deref_value) other):
|
||||
lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
|
||||
{}
|
||||
operator T()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
deref_value& operator=(T const& newVal)
|
||||
{
|
||||
value_=newVal;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
class const_deref_value
|
||||
{
|
||||
private:
|
||||
friend class synchronized_value;
|
||||
|
||||
boost::unique_lock<lockable_type> lk_;
|
||||
const T& value_;
|
||||
|
||||
explicit const_deref_value(synchronized_value const& outer):
|
||||
lk_(outer.mtx_), value_(outer.value_)
|
||||
{}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(const_deref_value)
|
||||
|
||||
const_deref_value(BOOST_THREAD_RV_REF(const_deref_value) other):
|
||||
lk_(boost::move(BOOST_THREAD_RV(other).lk_)), value_(BOOST_THREAD_RV(other).value_)
|
||||
{}
|
||||
|
||||
operator T()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
deref_value operator*()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF(deref_value(*this));
|
||||
}
|
||||
|
||||
const_deref_value operator*() const
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T, typename L>
|
||||
inline void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -1,142 +0,0 @@
|
||||
// (C) Copyright 2012 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)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_TESTABLE_LOCKABLE_HPP
|
||||
#define BOOST_THREAD_TESTABLE_LOCKABLE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
/**
|
||||
* Based on Associate Mutexes with Data to Prevent Races, By Herb Sutter, May 13, 2010
|
||||
* http://www.drdobbs.com/windows/associate-mutexes-with-data-to-prevent-r/224701827?pgno=3
|
||||
*
|
||||
* Make our mutex testable if it isn't already.
|
||||
*
|
||||
* Many mutex services (including boost::mutex) don't provide a way to ask,
|
||||
* "Do I already hold a lock on this mutex?"
|
||||
* Sometimes it is needed to know if a method like is_held to be available.
|
||||
* This wrapper associates an arbitrary lockable type with a thread id that stores the ID of the thread that
|
||||
* currently holds the lockable. The thread id initially holds an invalid value that means no threads own the mutex.
|
||||
* When we acquire a lock, we set the thread id; and when we release a lock, we reset it back to its default no id state.
|
||||
*
|
||||
*/
|
||||
template <typename Lockable>
|
||||
class testable_mutex
|
||||
{
|
||||
Lockable mtx_;
|
||||
atomic<thread::id> id_;
|
||||
public:
|
||||
/// the type of the wrapped lockable
|
||||
typedef Lockable lockable_type;
|
||||
|
||||
/// Non copyable
|
||||
BOOST_THREAD_NO_COPYABLE(testable_mutex)
|
||||
|
||||
void lock()
|
||||
{
|
||||
mtx_.lock();
|
||||
id_ = this_thread::get_id();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_ASSERT(is_locked(mtx_));
|
||||
id_ = thread::id();
|
||||
mtx_.unlock();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
if (mtx_.try_lock())
|
||||
{
|
||||
id_ = this_thread::get_id();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
if (mtx_.try_lock_for(rel_time))
|
||||
{
|
||||
id_ = this_thread::get_id();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
if (mtx_.try_lock_until(abs_time))
|
||||
{
|
||||
id_ = this_thread::get_id();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_locked_by_this_thread()
|
||||
{
|
||||
return this_thread::get_id() == id_;
|
||||
}
|
||||
|
||||
bool get_id()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
// todo add the shared and upgrade mutex functions
|
||||
};
|
||||
|
||||
template <typename Lockable>
|
||||
struct is_testable_lockable : false_type
|
||||
{};
|
||||
|
||||
template <typename Lockable>
|
||||
struct is_testable_lockable<testable_mutex<Lockable> > : true_type
|
||||
{};
|
||||
|
||||
// /**
|
||||
// * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise.
|
||||
// *
|
||||
// * This function is used usually to assert the pre-condition when the function can only be called when the mutex
|
||||
// * must be locked by the current thread.
|
||||
// */
|
||||
// template <typename Lockable>
|
||||
// bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
|
||||
// {
|
||||
// return mtx.is_locked();
|
||||
// }
|
||||
// template <typename Lockable>
|
||||
// bool is_locked_by_this_thread(Lockable const&)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -20,9 +20,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/thread_group.hpp>
|
||||
#include <boost/thread/v2/thread.hpp>
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// 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 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
|
||||
// Based on the Anthony's idea of scoped_thread in CCiA
|
||||
|
||||
#ifndef BOOST_THREAD_THREAD_FUNCTORS_HPP
|
||||
#define BOOST_THREAD_THREAD_FUNCTORS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
struct detach
|
||||
{
|
||||
void operator()(thread& t)
|
||||
{
|
||||
t.detach();
|
||||
}
|
||||
};
|
||||
|
||||
struct join_if_joinable
|
||||
{
|
||||
void operator()(thread& t)
|
||||
{
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
struct interrupt_and_join_if_joinable
|
||||
{
|
||||
void operator()(thread& t)
|
||||
{
|
||||
t.interrupt();
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
// 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 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
|
||||
// Based on the Anthony's idea of thread_joiner in CCiA
|
||||
|
||||
#ifndef BOOST_THREAD_THREAD_GUARD_HPP
|
||||
#define BOOST_THREAD_THREAD_GUARD_HPP
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/thread_functors.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* Non-copyable RAII scoped thread guard joiner which join the thread if joinable when destroyed.
|
||||
*/
|
||||
template <class CallableThread = join_if_joinable>
|
||||
class thread_guard
|
||||
{
|
||||
thread& t_;
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( thread_guard)
|
||||
|
||||
explicit thread_guard(thread& t) :
|
||||
t_(t)
|
||||
{
|
||||
}
|
||||
~thread_guard()
|
||||
{
|
||||
CallableThread on_destructor;
|
||||
|
||||
on_destructor(t_);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user