mirror of
https://github.com/boostorg/thread.git
synced 2026-02-07 10:52:10 +00:00
Compare commits
13 Commits
boost-1.53
...
boost-1.54
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af296f2cd0 | ||
|
|
0b2c57876f | ||
|
|
ba03de1f06 | ||
|
|
100bd73f03 | ||
|
|
4d2110f5e5 | ||
|
|
e294e6bcc8 | ||
|
|
093a329c1a | ||
|
|
13141f8ada | ||
|
|
64c73fac46 | ||
|
|
22369e9d8c | ||
|
|
677dbe7688 | ||
|
|
b1a674869d | ||
|
|
f9b257e368 |
@@ -49,8 +49,8 @@ project boost/thread
|
||||
<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_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
|
||||
<library>/boost/system//boost_system
|
||||
#-pedantic -ansi -std=gnu++0x -Wextra -fpermissive
|
||||
<warnings>all
|
||||
@@ -59,12 +59,18 @@ project boost/thread
|
||||
<toolset>gcc:<cxxflags>-Wno-long-long
|
||||
#<toolset>gcc:<cxxflags>-ansi
|
||||
#<toolset>gcc:<cxxflags>-fpermissive
|
||||
<toolset>gcc:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>gcc:<cxxflags>-Wunused-local-typedefs
|
||||
<toolset>gcc:<cxxflags>-Wunused-function
|
||||
|
||||
<toolset>darwin:<cxxflags>-Wextra
|
||||
<toolset>darwin:<cxxflags>-pedantic
|
||||
#<toolset>darwin:<cxxflags>-ansi
|
||||
<toolset>darwin:<cxxflags>-fpermissive
|
||||
<toolset>darwin:<cxxflags>-Wno-long-long
|
||||
<toolset>darwin:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>darwin:<cxxflags>-Wunused-local-typedefs
|
||||
<toolset>darwin:<cxxflags>-Wunused-function
|
||||
|
||||
#<toolset>pathscale:<cxxflags>-Wextra
|
||||
<toolset>pathscale:<cxxflags>-Wno-long-long
|
||||
@@ -75,6 +81,8 @@ project boost/thread
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
<toolset>clang:<cxxflags>-Wno-variadic-macros
|
||||
|
||||
<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
@@ -82,6 +90,7 @@ project boost/thread
|
||||
<toolset>gcc-mingw-4.6.3:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.7.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.8.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc:<cxxflags>-Wno-missing-field-initializers
|
||||
|
||||
<toolset>darwin-4.6.2:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
<toolset>darwin-4.7.0:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
@@ -93,7 +102,7 @@ project boost/thread
|
||||
<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)
|
||||
@@ -104,7 +113,9 @@ project boost/thread
|
||||
<toolset>intel:<cxxflags>-wd193,304,383,444
|
||||
<toolset>intel:<cxxflags>-wd593,981
|
||||
<toolset>intel:<cxxflags>-wd1418
|
||||
<toolset>intel:<cxxflags>-wd2415
|
||||
<toolset>intel:<cxxflags>-wd2415
|
||||
|
||||
<toolset>msvc:<cxxflags>/wd4512
|
||||
|
||||
|
||||
# : default-build <threading>multi
|
||||
@@ -115,7 +126,7 @@ project boost/thread
|
||||
<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_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
<library>/boost/system//boost_system
|
||||
;
|
||||
|
||||
@@ -225,7 +236,7 @@ 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) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.1 in $(properties)
|
||||
{
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
@@ -255,6 +266,11 @@ rule requirements ( properties * )
|
||||
}
|
||||
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
|
||||
|
||||
if <toolset>pgi in $(properties) || <toolset>vacpp in $(properties)
|
||||
{
|
||||
result += <library>/boost/atomic//boost_atomic ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
@@ -263,6 +279,7 @@ alias thread_sources
|
||||
win32/thread.cpp
|
||||
win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp
|
||||
future.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>win32
|
||||
;
|
||||
@@ -271,6 +288,7 @@ alias thread_sources
|
||||
: ## pthread sources ##
|
||||
pthread/thread.cpp
|
||||
pthread/once.cpp
|
||||
future.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>pthread
|
||||
;
|
||||
@@ -278,7 +296,7 @@ alias thread_sources
|
||||
explicit thread_sources ;
|
||||
|
||||
lib boost_thread
|
||||
: thread_sources future.cpp
|
||||
: thread_sources
|
||||
: <conditional>@requirements
|
||||
:
|
||||
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
|
||||
|
||||
@@ -18,6 +18,9 @@ arrived. Once the `n`-th thread has reached the barrier, all the waiting threads
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(barrier const&) = delete;
|
||||
barrier& operator=(barrier const&) = delete;
|
||||
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
@@ -63,7 +66,10 @@ are unblocked, and the barrier is reset. ]]
|
||||
|
||||
[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
[[Notes:] [`wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -8,6 +8,53 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[/
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
|
||||
[*New Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
]
|
||||
|
||||
[heading Version 4.1.0 - boost 1.54]
|
||||
|
||||
[*New Features:]
|
||||
|
||||
* [@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/7445 #7445] Async: Add future<>.then
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7449 #7449] Synchro: Add a synchronized value class
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4878 #4878] MinGW 4.5.0 undefined reference to bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::t imeout target_time).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4882 #4882] Win32 shared_mutex does not handle timeouts correctly.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6652 #6652] Boost.Thread shared_mutex.hpp:50:99: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6843 #6843] [Intel C++] Compile Errors with '#include <atomic>'
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6966 #6966] future boost::future_category inconsistent dll linkage
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7720 #7720] exception lock_error while intensive locking/unlocking of mutex
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7755 #7755] Thread: deadlock with shared_mutex on Windows
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7980 #7980] Build error: msvc-11.0 and BOOST_THREAD_DONT_USE_DATETIME
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7982 #7982] pthread_delay_np() parm compile error on AIX
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8027 #8027] thread library fails to compile with Visual Studio 2003
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8136 #8136] boost::this_thread::sleep_for() sleeps longer than it should in Windows
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8212 #8212] Boost thread compilation error on Solaris 10
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8237 #8237] fix documentation for 'thread_group'
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8239 #8239] barrier::wait() not marked as interruption_point
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8323 #8323] boost::thread::try_join_for/try_join_until may block indefinitely due to a combination of problems in Boost.Thread and Boost.Chrono
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8337 #8337] The internal representation of "std::string(this->code()->message())" escapes, but is destroyed when it exits scope.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8371 #8371] C++11 once_flag enabled when constexpr is not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8443 #8443] Header file inclusion order may cause crashes
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8451 #8451] Missing documented function 'boost::scoped_thread::joinable'
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8530 #8530] [Coverity] Unused variable thread_handle, uninitialized variable cond_mutex in thread/pthread/thread_data.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8596 #8596] With C++0x enabled, boost::packaged_task stores a reference to function objects, instead of a copy.
|
||||
|
||||
[heading Version 4.0.0 - boost 1.53]
|
||||
|
||||
[/
|
||||
@@ -41,6 +88,7 @@ Provided when BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined (Default
|
||||
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/7285 #7285] C++11 compliance: Allow to pass movable arguments for call_once
|
||||
|
||||
* [@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):
|
||||
@@ -63,11 +111,13 @@ See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms
|
||||
* [@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/7671 #7671] Error including boost/thread.hpp header on iOS.
|
||||
* [@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.
|
||||
@@ -75,6 +125,8 @@ See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_
|
||||
* [@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>&).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7890 #7890] thread::do_try_join_until() is missing a return type.
|
||||
|
||||
|
||||
|
||||
[heading Version 3.1.0 - boost 1.52]
|
||||
@@ -344,18 +396,29 @@ 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
|
||||
|
||||
# Add some minor features, 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.
|
||||
|
||||
# Add some features based on C++ proposals, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/XXXX #XXXX] Sync: Add a completion_latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
|
||||
|
||||
# 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] or extension to them, in particular
|
||||
|
||||
* [@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/8515 #8515] Async: Add shared_future::then
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic future/shared_future::then
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
[section:cpp11 C++11 standard Thread library]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 standard]]
|
||||
|
||||
|
||||
[table C++11 standard Conformance
|
||||
[[Section] [Description] [Status] [Comments] [Ticket]]
|
||||
[[30] [Thread support library] [Partial] [-] [-]]
|
||||
[[30] [Thread support library] [Yes] [-] [-]]
|
||||
[[30.1] [General] [-] [-] [-]]
|
||||
[[30.2] [Requirements] [-] [-] [-]]
|
||||
[[30.2.1] [Template parameter names] [-] [-] [-]]
|
||||
@@ -53,16 +55,16 @@
|
||||
[[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.4] [Call once] [Yes] [-] [-]]
|
||||
[[30.4.4.1] [Struct once_flag] [Yes] [-] [-]]
|
||||
[[30.4.4.2] [Function call_once] [Partial] [interface] [#7285]]
|
||||
[[30.4.4.2] [Function call_once] [Yes] [-] [-]]
|
||||
[[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.6] [Futures] [Yes] [-] [-]]
|
||||
[[30.6.1] [Overview] [Partial] [-] [-]]
|
||||
[[30.6.2] [Error handling] [Yes] [-] [-]]
|
||||
[[30.6.3] [Class future_error] [Partial] [noexcept] [#7279]]
|
||||
[[30.6.3] [Class future_error] [-] [-] [-]]
|
||||
[[30.6.4] [Shared state] [-] [-] [-]]
|
||||
[[30.6.5] [Class template promise] [Yes] [-] [-]]
|
||||
[[30.6.6] [Class template future] [Yes] [-] [-]]
|
||||
@@ -86,24 +88,155 @@
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:shared Shared Locking extensions]
|
||||
[section:cxx14 C++14 standard Thread library - accepted changes]
|
||||
|
||||
[table Howard's Shared Locking Proposal Conformance
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.html C++14 on-going standard]]
|
||||
|
||||
|
||||
[table [@http://isocpp.org/files/papers/N3659.html N3659 Shared locking in C++ revision 2] 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] [-]]
|
||||
[[30.4.1.4] [Shared Lockables Types] [Yes] [ - ]]
|
||||
[[30.4.1.4.1] [shared_mutex class] [Yes] [ - ]]
|
||||
[[30.4.2.3] [Class template shared_lock] [Yes] [-]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:cxx1y C++1y TS Concurrency - On going proposals]
|
||||
|
||||
[section:latch C++ Latches and Barriers]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3659 C++ Latches and Barriers]]
|
||||
|
||||
[table C++ Latches and Barriers Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Class latch] [Partial] [ A new class latch has been added. The interface is a super set of the one of the proposal, taking some of the functions of the class barrier.]]
|
||||
[[X.2] [Class barrier] [No] [ Even if Boost.Thread has a class boost:barrier it doesn't provides the same kind of services. There is an experimental completion_latch that could be used instead. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:queue C++ Concurrent Queues]
|
||||
|
||||
[note [@ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html N3533 C++ Concurrent Queues]]
|
||||
|
||||
[table C++ Concurrent Queues Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Conceptual interface] [Partial] [ The interface provided has some differences respect to this proposal. All the functions having a queue_op_status are not provided. No lock-free concrete classes ]]
|
||||
[[X.1.1] [Basic Operations] [Partial] [ - ]]
|
||||
[[X.1.1.1] [push] [yes] [ - ]]
|
||||
[[X.1.1.2] [value_pop] [no] [ renamed pull with two flavors + a ptr_pull that returns a sharted_ptr<>. ]]
|
||||
[[X.1.2] [Non-waiting operations] [] [ - ]]
|
||||
[[X.1.2.1] [try_push] [Partial] [ return bool instead ]]
|
||||
[[X.1.2.2] [try_pop] [Partial] [ renamed try_pull, returns null ]]
|
||||
[[X.1.3] [Non-blocking operations] [] [ - ]]
|
||||
[[X.1.3.1] [nonblocking_push] [Partial] [ renamed try_push(no_block, ]]
|
||||
[[X.1.3.2] [nonblocking_pop] [Partial] [ renamed try_pop(no_block, ]]
|
||||
[[X.1.4] [Push-front operations] [No] [ - ]]
|
||||
[[X.1.5] [Closed queues] [Partial] [ - ]]
|
||||
[[X.1.5.1] [close] [Yes] [ - ]]
|
||||
[[X.1.5.2] [is_closed] [Yes] [ - ]]
|
||||
[[X.1.5.3] [wait_push] [Partial] [ - ]]
|
||||
[[X.1.5.4] [wait_pop] [Partial] [ - ]]
|
||||
[[X.1.5.5] [wait_push_front] [no] [ - ]]
|
||||
[[X.1.5.6] [wait_pop] [Partial] [ - ]]
|
||||
[[X.1.5.6] [open] [no] [ - ]]
|
||||
[[X.1.6] [Empty and Full Queues] [Yes] [ - ]]
|
||||
[[X.1.6.1] [is_empty] [Yes] [ - ]]
|
||||
[[X.1.6.2] [is_full] [Yes] [ Added capacity ]]
|
||||
[[X.1.7] [Queue Names] [No] [ Not considere a must for the time been. ]]
|
||||
[[X.1.8] [Element Type Requirements] [Yes?] [ - ]]
|
||||
[[X.1.9] [Exception Handling] [Yes?] [ - ]]
|
||||
[[X.1.10] [Queue Ordering] [Yes?] [ - ]]
|
||||
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Move aware. ]]
|
||||
[[X.2] [Concrete queues] [Partial] [ ]]
|
||||
[[X.2.1] [Locking Buffer Queue] [Partial] [ classes sync_queue and a sync_bounded_queue. ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ ]]
|
||||
[[X.3] [Additional Conceptual Tools] [No] [ ]]
|
||||
[[X.3.1] [Fronts and Backs] [No] [ ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ ]]
|
||||
[[X.3.3] [Storage Iterators] [No] [ ]]
|
||||
[[X.3.4] [Binary Interfaces] [No] [ ]]
|
||||
[[X.3.4] [Managed Indirection] [No] [ ]]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:executors Asynchronous Executors]
|
||||
|
||||
While Boost.Thread implementation of executors would not use dynamic polymorphism, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3378.pdf N3378 A preliminary proposal for work executors]]
|
||||
|
||||
|
||||
[table Asynchronous Executors
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.X.1] [Class executor] [No] [ - ]]
|
||||
[[30.X.1.1] [add] [No] [ renamed with a function template submit ]]
|
||||
[[30.X.1.1] [num_of_pendin_closures] [??] [ ]]
|
||||
[[30.X.2] [Class sceduled_executor] [No] [ - ]]
|
||||
[[30.X.2.1] [add_at] [No] [ renamed with a function template submit_at ]]
|
||||
[[30.X.2.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
||||
[[30.X.3] [Executor utilities functions] [No] [ - ]]
|
||||
[[30.X.3.1] [default_executor] [No] [ - ]]
|
||||
[[30.X.3.2] [set_default_executor] [No] [ - ]]
|
||||
[[30.X.3.3] [singleton_inline_executor] [No] [ - ]]
|
||||
[[30.X.4] [Concrete executor classes] [No] [ - ]]
|
||||
[[30.X.4.1] [loop_executor] [No] [ - ]]
|
||||
[[30.X.4.1] [serial_executor] [No] [ - ]]
|
||||
[[30.X.4.1] [thread_pool] [No] [ #8513 ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:async A Standardized Representation of Asynchronous Operations]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf N3558 A Standardized Representation of Asynchronous Operations]]
|
||||
|
||||
[table A Standardized Representation of Asynchronous Operations Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.6.6] [Class template future] [Partial] [ - ]]
|
||||
[[30.6.6.1] [then] [Partial] [ executor interface missing #8516 ]]
|
||||
[[30.6.6.2] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.6.3] [ready] [yes] [ is_ready ]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
|
||||
[[30.6.7.1] [then] [No] [ #8515 ]]
|
||||
[[30.6.7.2] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7.3] [ready] [Yes] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_any] [No] [ #7446 ]]
|
||||
[[30.6.X] [Function template when_all] [No] [ #7447 ]]
|
||||
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
|
||||
[[30.6.8] [Function template async ] [No] [ executor interface missing #7448 ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stream_mutex C++ Stream Mutexes]
|
||||
|
||||
While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html N3535 - C++ Stream Mutexes]]
|
||||
|
||||
[table C++ C++ Stream MutexesConformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Class template stream_mutex] [Partial] [ externally_locked_stream<> ]]
|
||||
[[X.2.1] [constructor] [Partial] [ externally_locked_stream needs a mutex in addition as argumement. ]]
|
||||
[[X.2.2] [lock] [yes] [ - ]]
|
||||
[[X.2.3] [unlock] [yes] [ - ]]
|
||||
[[X.2.4] [try_lock] [yes] [ - ]]
|
||||
[[X.2.5] [hold] [Yes] [ - ]]
|
||||
[[X.2.6] [bypass] [Yes] [ - ]]
|
||||
[[X.2] [Class template stream_guard] [Yes] [ - ]]
|
||||
[[X.2.1] [stream_guard] [Yes] [ - ]]
|
||||
[[X.2.2] [~stream_guard] [Yes] [ - ]]
|
||||
[[X.2.3] [bypass] [Yes] [ - ]]
|
||||
[[X.3] [Stream Operators] [Yes] [.]]
|
||||
[[X.4] [Predefined Objects] [No] [.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
[[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] ]
|
||||
[[USES_DATETIME] [DONT_USE_DATETIME] [YES] [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] ]
|
||||
@@ -69,8 +69,10 @@ The Boost.DateTime time related functions introduced in Boost 1.35.0, using the
|
||||
* __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.
|
||||
When `BOOST_THREAD_VERSION<=3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `BOOST_THREAD_DONT_USE_DATETIME` if you don't want to use Boost.DateTime related interfaces.
|
||||
When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `BOOST_THREAD_USES_DATETIME` if you want to use Boost.DateTime related interfaces.
|
||||
|
||||
When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_DATETIME is defined by default.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -343,7 +345,7 @@ The user can request the version 3 by defining `BOOST_THREAD_VERSION` to 3. In t
|
||||
|
||||
* 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 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:
|
||||
|
||||
@@ -354,7 +356,7 @@ The user can request the version 4 by defining `BOOST_THREAD_VERSION` to 4. In t
|
||||
* Breaking change `BOOST_THREAD_DONT_USE_DATETIME`
|
||||
|
||||
|
||||
The default value for `BOOST_THREAD_VERSION` will be changed to 4 since Boost 1.56.
|
||||
[/The default value for `BOOST_THREAD_VERSION` will be changed to 4 since Boost 1.58.]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
|
||||
void swap(__unique_future__& other) noexcept; // EXTENSION
|
||||
|
||||
@@ -686,11 +686,19 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION
|
||||
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
|
||||
|
||||
[warning These functions are experimental and subject to change in future versions.
|
||||
There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These functions are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3558.pdf [*N3558 - A Standardized Representation of Asynchronous Operations]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Notes:] [The three functions differ only by input parameters. The first only takes a callable object which accepts a
|
||||
@@ -717,7 +725,7 @@ launch::deferred
|
||||
|
||||
]]
|
||||
|
||||
[[Returns:] [An object of type future<decltype(func(*this))> that refers to the shared state created by the continuation.]]
|
||||
[[Returns:] [An object of type future<typename boost::result_of<F(__unique_future__&)> that refers to the shared state created by the continuation.]]
|
||||
|
||||
[[Postconditions:] [
|
||||
|
||||
@@ -1601,30 +1609,21 @@ __packaged_task__.]]
|
||||
|
||||
[section:async Non-member function `async()`]
|
||||
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(F&& f);
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F&& f);
|
||||
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(F&& f, Args&&... args);
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
|
||||
|
||||
The function template async provides a mechanism to launch a function potentially in a new thread and
|
||||
provides the result of the function in a future object with which it shares a shared state.
|
||||
|
||||
[warning `async(launch::deferred, F)` is NOT YET IMPLEMENTED!]
|
||||
|
||||
[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple>, and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.]
|
||||
|
||||
[heading Non-Variadic variant]
|
||||
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(F&& f);
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F&& f);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [
|
||||
@@ -1636,8 +1635,11 @@ decay_copy(boost::forward<F>(f))()
|
||||
shall be a valid expression.
|
||||
]]
|
||||
|
||||
[[Effects] [The first function behaves the same as a call to the second function with a policy argument of
|
||||
`launch::async | launch::deferred` and the same arguments for `F`. The second function creates a shared state that is associated with the returned future object.
|
||||
[[Effects] [
|
||||
The first function behaves the same as a call to the second function with a policy argument of
|
||||
`launch::async | launch::deferred` and the same arguments for `F`.
|
||||
|
||||
The second function creates a shared state that is associated with the returned future object.
|
||||
|
||||
The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
|
||||
|
||||
@@ -1645,6 +1647,8 @@ The further behavior of the second function depends on the policy argument as fo
|
||||
|
||||
- if `policy & launch::deferred` is non-zero - Stores `decay_copy(boost::forward<F>(f))` in the shared state. This copy of `f` constitute a deferred function. Invocation of the deferred function evaluates `boost::move(g)()` where `g` is the stored value of `decay_copy(boost::forward<F>(f))`. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of `boost::move(g)()` begins, the function is no longer considered deferred. (Note: If this policy is specified together with other policies, such as when using a policy value of `launch::async | launch::deferred`, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.)
|
||||
|
||||
- if no valid launch policy is provided the behaviour is undefined.
|
||||
|
||||
]]
|
||||
|
||||
[[Returns:] [An object of type `__unique_future__<typename result_of<typename decay<F>::type()>::type>` that refers to the shared state created by this call to `async`.]]
|
||||
@@ -1657,7 +1661,7 @@ The further behavior of the second function depends on the policy argument as fo
|
||||
|
||||
If the implementation chooses the `launch::async` policy,
|
||||
|
||||
- a call to a non-timed waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined;
|
||||
- a call to a non-timed waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined, or else time out;
|
||||
|
||||
- the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first.
|
||||
]]
|
||||
@@ -1678,6 +1682,15 @@ If the implementation chooses the `launch::async` policy,
|
||||
|
||||
[heading Variadic variant]
|
||||
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(F&& f, Args&&... args);
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
|
||||
[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple> (waiting for a boost::tuple that is move aware), and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [
|
||||
@@ -1710,6 +1723,8 @@ the implementation may choose any of the corresponding policies):
|
||||
an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function.
|
||||
Once evaluation of `invoke(move(g), move(xyz))` begins, the function is no longer considered deferred.
|
||||
|
||||
- if no valid launch policy is provided the behaviour is undefined.
|
||||
|
||||
]]
|
||||
|
||||
[[Note:] [If this policy is specified together with other policies, such as when using a policy value of `launch::async | launch::deferred`,
|
||||
@@ -1723,10 +1738,11 @@ that refers to the shared state created by this call to `async`.]]
|
||||
- the invocation of async synchronizes with the invocation of `f`. (Note: This statement applies even when the corresponding future object is moved to another thread.); and
|
||||
|
||||
- the completion of the function `f` is sequenced before the shared state is made ready. (Note: f might not be called at all, so its completion might never happen.)
|
||||
|
||||
If the implementation chooses the `launch::async` policy,
|
||||
|
||||
- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call
|
||||
shall block until the associated thread has completed, as if joined;
|
||||
shall block until the associated thread has completed, as if joined, or else time out;
|
||||
|
||||
- the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or
|
||||
with the return from the last function that releases the shared state, whichever happens first.
|
||||
|
||||
@@ -55,6 +55,9 @@ The following example includes a bank account of a person (Joe) and two componen
|
||||
|
||||
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.
|
||||
|
||||
[endsect]
|
||||
[section Internal locking]
|
||||
|
||||
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 {
|
||||
@@ -75,7 +78,7 @@ The above example works well as long as the bankAgent and Joe doesn't access Joe
|
||||
mtx_.lock();
|
||||
int b = balance_;
|
||||
mtx_.unlock();
|
||||
return balance_;
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,6 +108,9 @@ With the RAII idiom we can simplify a lot this using the scoped locks. In the co
|
||||
|
||||
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."
|
||||
@@ -203,6 +209,24 @@ As `boost::mutex` is not recursive, we need to use its recursive version `boost:
|
||||
// ...
|
||||
};
|
||||
|
||||
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]
|
||||
|
||||
@@ -440,11 +464,6 @@ Monitors and conditions are useful for describing simple cases of shared objects
|
||||
[endsect] [/Monitors]
|
||||
]
|
||||
|
||||
[section Synchronized variables]
|
||||
[/include synchronized_value.qbk]
|
||||
[endsect] [/Synchronized variables]
|
||||
|
||||
|
||||
[endsect] [/Internal Locking]
|
||||
|
||||
|
||||
|
||||
396
doc/latch.qbk
Normal file
396
doc/latch.qbk
Normal file
@@ -0,0 +1,396 @@
|
||||
[/
|
||||
(C) Copyright 2013 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:latches Latches -- EXPERIMENTAL]
|
||||
|
||||
[section Introdcution]
|
||||
|
||||
Latches are a thread co-ordination mechanism that allow one or more threads to block until one or more threads have reached a point. An individual latch is a reusable object; once the operation has been completed, the threads can re-use the same barrier. It is thus useful for managing repeated tasks handled by multiple threads.
|
||||
|
||||
A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
|
||||
|
||||
[endsect]
|
||||
[section Examples]
|
||||
|
||||
Sample use cases for the latch include:
|
||||
|
||||
* Setting multiple threads to perform a task, and then waiting until all threads have reached a common point.
|
||||
* Creating multiple threads, which wait for a signal before advancing beyond a common point.
|
||||
|
||||
An example of the first use case would be as follows:
|
||||
|
||||
void DoWork(thread_pool* pool) {
|
||||
latch completion_latch(NTASKS);
|
||||
for (int i = 0; i < NTASKS; ++i) {
|
||||
pool->submit([&] {
|
||||
// perform work
|
||||
...
|
||||
completion_latch.count_down();
|
||||
}));
|
||||
}
|
||||
// Block until work is done
|
||||
completion_latch.wait();
|
||||
}
|
||||
|
||||
An example of the second use case is shown below. We need to load data and then process it using a number of threads. Loading the data is I/O bound, whereas starting threads and creating data structures is CPU bound. By running these in parallel, throughput can be increased.
|
||||
|
||||
|
||||
void DoWork() {
|
||||
latch start_latch(1);
|
||||
vector<thread*> workers;
|
||||
for (int i = 0; i < NTHREADS; ++i) {
|
||||
workers.push_back(new thread([&] {
|
||||
// Initialize data structures. This is CPU bound.
|
||||
...
|
||||
start_latch.wait();
|
||||
// perform work
|
||||
...
|
||||
}));
|
||||
}
|
||||
// Load input data. This is I/O bound.
|
||||
...
|
||||
// Threads can now start processing
|
||||
start_latch.count_down();
|
||||
}
|
||||
|
||||
The completion latches can be used to co-ordinate also a set of threads carrying out a repeated task. The number of threads can be adjusted dynamically to respond to changing requirements.
|
||||
|
||||
In the example below, a number of threads are performing a multi-stage task. Some tasks may require fewer steps than others, meaning that some threads may finish before others. We reduce the number of threads waiting on the latch when this happens.
|
||||
|
||||
void DoWork() {
|
||||
Tasks& tasks;
|
||||
size_t initial_threads;
|
||||
atomic<size_t> current_threads(initial_threads)
|
||||
vector<thread*> workers;
|
||||
|
||||
// Create a barrier, and set a lambda that will be invoked every time the
|
||||
// barrier counts down. If one or more active threads have completed,
|
||||
// reduce the number of threads.
|
||||
completion_latch task_barrier(n_threads);
|
||||
task_barrier.then([&] {
|
||||
task_barrier.reset(current_threads);
|
||||
});
|
||||
|
||||
for (int i = 0; i < n_threads; ++i) {
|
||||
workers.push_back(new thread([&] {
|
||||
bool active = true;
|
||||
while(active) {
|
||||
Task task = tasks.get();
|
||||
// perform task
|
||||
...
|
||||
if (finished(task)) {
|
||||
current_threads--;
|
||||
active = false;
|
||||
}
|
||||
task_barrier.count_down_and_wait();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Read each stage of the task until all stages are complete.
|
||||
while (!finished()) {
|
||||
GetNextStage(tasks);
|
||||
}
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[section:latch Class `latch`]
|
||||
|
||||
#include <boost/thread/latch.hpp>
|
||||
|
||||
class latch
|
||||
{
|
||||
public:
|
||||
latch(latch const&) = delete;
|
||||
latch& operator=(latch const&) = delete;
|
||||
|
||||
latch(std::size_t count);
|
||||
~latch();
|
||||
|
||||
void wait();
|
||||
bool try_wait();
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void count_down();
|
||||
void count_down_and_wait();
|
||||
void reset(std::size_t count);
|
||||
|
||||
};
|
||||
|
||||
|
||||
A latch maintains an internal counter that is initialized when the latch is created. One or more threads may block waiting until the counter is decremented to 0.
|
||||
|
||||
Instances of __latch__ are not copyable or movable.
|
||||
|
||||
[section Constructor]
|
||||
|
||||
latch(std::size_t count);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a latch with is initial value for the internal counter.]]
|
||||
|
||||
[[Note:] [The counter could be zero and reset later.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section Destructor]
|
||||
|
||||
~latch();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [No threads are waiting or invoking count_down on `*this`.]]
|
||||
|
||||
[[Effects:] [Destroys `*this` latch.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:wait Member function `wait()`]
|
||||
|
||||
void wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Block the calling thread until the internal count reaches the value zero. Then all waiting threads
|
||||
are unblocked. ]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
|
||||
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
|
||||
]]
|
||||
|
||||
[[Notes:] [`wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_wait Member function `try_wait()`]
|
||||
|
||||
bool try_wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [Returns true if the internal count is 0, and false otherwise. Does not block the calling thread. ]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for Member function `wait_for() `]
|
||||
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Block the calling thread until the internal count reaches the value zero or the duration has been elapsed. If no timeout, all waiting threads are unblocked. ]]
|
||||
[[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if duration has been elapsed. ]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
|
||||
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
|
||||
]]
|
||||
|
||||
[[Notes:] [`wait_for()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:wait_until Member function `wait_until()`]
|
||||
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Block the calling thread until the internal count reaches the value zero or the time_point has been reached. If no timeout, all waiting threads are unblocked. ]]
|
||||
[[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if time_point has been reached.]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
|
||||
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
|
||||
]]
|
||||
|
||||
[[Notes:] [`wait_until()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:count_down Member function `count_down()`]
|
||||
|
||||
void count_down();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The internal counter is non zero.]]
|
||||
[[Effects:] [Decrements the internal count by 1, and returns. If the count reaches 0, any threads blocked in wait() will be released. ]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
|
||||
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
|
||||
]]
|
||||
[[Notes:] [`count_down()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:count_down_and_wait Member function `count_down_and_wait()`]
|
||||
|
||||
void count_down_and_wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The internal counter is non zero.]]
|
||||
[[Effects:] [Decrements the internal count by 1. If the resulting count is not 0, blocks the calling thread until the internal count is decremented to 0 by one or more other threads calling count_down() or count_down_and_wait(). ]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
|
||||
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
|
||||
]]
|
||||
[[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:reset Member function `reset()`]
|
||||
|
||||
reset( size_t );
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions.]]
|
||||
|
||||
[[Returns:] [Resets the latch with a new value for the initial thread count. ]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect] [/ latch]
|
||||
|
||||
[section:completion_latch Class `completion_latch `]
|
||||
|
||||
#include <boost/thread/completion_latch.hpp>
|
||||
|
||||
class completion_latch
|
||||
{
|
||||
public:
|
||||
typedef 'implementation defined' completion_function;
|
||||
|
||||
completion_latch(completion_latch const&) = delete;
|
||||
completion_latch& operator=(completion_latch const&) = delete;
|
||||
|
||||
completion_latch(std::size_t count);
|
||||
template <typename F>
|
||||
completion_latch(std::size_t count, F&& funct);
|
||||
~completion_latch();
|
||||
|
||||
void wait();
|
||||
bool try_wait();
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void count_down();
|
||||
void count_down_and_wait();
|
||||
void reset(std::size_t count);
|
||||
template <typename F>
|
||||
completion_function then(F&& funct);
|
||||
};
|
||||
|
||||
|
||||
A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
|
||||
|
||||
Instances of completion_latch are not copyable or movable.
|
||||
|
||||
Only the additional functions are documented.
|
||||
|
||||
[section:c Constructor]
|
||||
|
||||
completion_latch(std::size_t count);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a completion_latch with is initial value for the internal counter and a noop completion function.]]
|
||||
|
||||
[[Note:] [The counter could be zero and rest later.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:cf Constructor with completion function]
|
||||
|
||||
template <typename F>
|
||||
completion_latch(std::size_t count, F&& funct);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a completion_latch with is initial value for the internal counter and the completion function `funct`.]]
|
||||
|
||||
[[Note:] [The counter could be zero and reset later.]]
|
||||
|
||||
[[Throws:] [
|
||||
|
||||
- Any exception thrown by the copy/move construction of funct.
|
||||
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:then Member function `then`]
|
||||
|
||||
template <typename F>
|
||||
completion_function then(F&& funct);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions. It may also be invoked from within the registered completion function. ]]
|
||||
|
||||
[[Effects:] [Associates the parameter `funct` as completion function of the latch. The next time the internal count reaches 0, this function will be invoked.]]
|
||||
[[Returns:] [The old completion function.]]
|
||||
|
||||
[[Throws:] [
|
||||
- __thread_resource_error__ if an error occurs.
|
||||
|
||||
- Any exception thrown by the copy/move construction of completion functions.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect] [/ completion_latch]
|
||||
|
||||
|
||||
[endsect] [/ Latches]
|
||||
117
doc/lockable_adapter.qbk
Normal file
117
doc/lockable_adapter.qbk
Normal file
@@ -0,0 +1,117 @@
|
||||
[/
|
||||
(C) Copyright 2008-2013 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:lockable_adapter_hpp Header `<boost/thread/lockable_adapter.hpp>`]
|
||||
[/==========================================================================================]
|
||||
|
||||
namespace boost {
|
||||
template <typename Lockable> class basic_lockable_adapter;
|
||||
template <typename Lockable> class lockable_adapter;
|
||||
template <typename TimedLock> class timed_lockable_adapter;
|
||||
template <typename SharableLock> class shared_lockable_adapter;
|
||||
template <typename UpgradableLock> class upgrade_lockable_adapter;
|
||||
}
|
||||
|
||||
[section Template Class `basic_lockable_adapter<>`]
|
||||
|
||||
template <typename Lockable>
|
||||
class basic_lockable_adapter {
|
||||
public:
|
||||
basic_lockable_adapter(basic_lockable_adapter const&) = delete
|
||||
basic_lockable_adapter& opearator=(basic_lockable_adapter const&) = delete
|
||||
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
basic_lockable_adapter() {}
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
};
|
||||
|
||||
[endsect]
|
||||
[section Template Class `lockable_adapter<>`]
|
||||
|
||||
template <typename Lockable>
|
||||
class lockable_adapter : : public basic_lockable_adapter<Lockable> {
|
||||
public:
|
||||
lockable_adapter() {}
|
||||
|
||||
bool try_lock();
|
||||
};
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Template Class `timed_lockable_adapter<>`]
|
||||
|
||||
template <typename TimedLock>
|
||||
class timed_lockable_adapter : public lockable_adapter<TimedLock> {
|
||||
public:
|
||||
timed_lockable_adapter() {}
|
||||
|
||||
bool try_lock_until(system_time const & abs_time);
|
||||
template<typename TimeDuration>
|
||||
bool try_lock_for(TimeDuration const & relative_time);
|
||||
|
||||
void lock_until(system_time const & abs_time);
|
||||
template<typename TimeDuration>
|
||||
void lock_for(TimeDuration const & relative_time);
|
||||
};
|
||||
|
||||
[endsect]
|
||||
[section Template Class `shared_lockable_adapter<>`]
|
||||
|
||||
template <typename SharableLock>
|
||||
class shared_lockable_adapter : public timed_lockable_adapter<SharableLock> {
|
||||
public:
|
||||
shared_lockable_adapter() {}
|
||||
void lock_shared();
|
||||
bool try_lock_shared();
|
||||
void unlock_shared();
|
||||
|
||||
bool try_lock_shared_until(system_time const& t);
|
||||
template<typename TimeDuration>
|
||||
bool try_lock_shared_for(TimeDuration const& t);
|
||||
|
||||
template<typename TimeDuration>
|
||||
void lock_shared_for(TimeDuration const& t);
|
||||
void lock_shared_until(system_time const& t);
|
||||
};
|
||||
|
||||
|
||||
[endsect]
|
||||
[section Template Class `upgrade_lockable_adapter<>`]
|
||||
|
||||
template <typename UpgradableLock>
|
||||
class upgrade_lockable_adapter : public shared_lockable_adapter<UpgradableLock>{
|
||||
public:
|
||||
upgrade_lockable_adapter();
|
||||
|
||||
void lock_upgrade();
|
||||
bool try_lock_upgrade();
|
||||
void unlock_upgrade();
|
||||
|
||||
void unlock_upgrade_and_lock();
|
||||
void unlock_and_lock_upgrade();
|
||||
void unlock_and_lock_shared();
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
|
||||
bool try_lock_upgrade_until(system_time const&t);
|
||||
template<typename TimeDuration>
|
||||
bool try_lock_upgrade_for(TimeDuration const&t);
|
||||
void lock_upgrade_until(system_time const&t);
|
||||
template<typename TimeDuration>
|
||||
void lock_upgrade_for(TimeDuration const&t);
|
||||
};
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ Lock ownership acquired through a call to __lock_ref__ must be released through
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The calling thread doesn't owns the mutex if the mutex is not recursive.]]
|
||||
|
||||
[[Effects:] [The current thread blocks until ownership can be obtained for the current thread.]]
|
||||
|
||||
[[Synchronization:] [Prior `unlock()` operations on the same object synchronizes with this operation. ]]
|
||||
@@ -97,7 +99,12 @@ Lock ownership acquired through a call to __lock_ref__ must be released through
|
||||
}
|
||||
}
|
||||
|
||||
Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of BasicLockable you could build.
|
||||
|
||||
Some of the algorithms on mutexes use this trait via SFINAE.
|
||||
|
||||
This trait is true_type if the parameter L meets the __Lockable requirements.
|
||||
|
||||
[warning If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of BasicLockable you could build.]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
@@ -121,6 +128,9 @@ Lock ownership acquired through a call to __try_lock_ref__ must be released thro
|
||||
|
||||
[variablelist
|
||||
|
||||
|
||||
[[Requires:] [The calling thread doesn't owns the mutex if the mutex is not recursive.]]
|
||||
|
||||
[[Effects:] [Attempt to obtain ownership for the current thread without blocking.]]
|
||||
|
||||
[[Synchronization:] [If `try_lock()` returns true, prior `unlock()` operations on the same object synchronize with this operation.]]
|
||||
@@ -152,7 +162,11 @@ failure, even in the absence of spurious failures.]]
|
||||
}
|
||||
}
|
||||
|
||||
Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of Lockable you could build.
|
||||
Some of the algorithms on mutexes use this trait via SFINAE.
|
||||
|
||||
This trait is true_type if the parameter L meets the __Lockable requirements.
|
||||
|
||||
[warning If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of Lockable you could build.]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
@@ -185,6 +199,37 @@ It should be specialized by the user providing other model of recursive lockable
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:is_recursive_basic_lockable `is_recursive_basic_lockable` trait -- EXTENSION]
|
||||
|
||||
// #include <boost/thread/lockable_traits.hpp>
|
||||
namespace boost
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
template<typename L>
|
||||
class is_recursive_basic_lockable;// EXTENSION
|
||||
}
|
||||
}
|
||||
|
||||
This traits is true_type if is_basic_lockable and is_recursive_mutex_sur_parolle.
|
||||
|
||||
[endsect]
|
||||
[section:is_recursive_lockable `is_recursive_lockable` trait -- EXTENSION]
|
||||
|
||||
// #include <boost/thread/lockable_traits.hpp>
|
||||
namespace boost
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
template<typename L>
|
||||
class is_recursive_lockable;// EXTENSION
|
||||
}
|
||||
}
|
||||
|
||||
This traits is true_type if is_lockable and is_recursive_mutex_sur_parolle.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -220,6 +265,8 @@ Lock ownership acquired through a call to __try_lock_for or __try_lock_until mus
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The calling thread doesn't owns the mutex if the mutex is not recursive.]]
|
||||
|
||||
[[Effects:] [Attempt to obtain ownership for the current thread. Blocks until ownership can be obtained, or the specified time is
|
||||
reached. If the specified time has already passed, behaves as __try_lock_ref__.]]
|
||||
|
||||
@@ -239,6 +286,8 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The calling thread doesn't owns the mutex if the mutex is not recursive.]]
|
||||
|
||||
[[Effects:] [As-if `__try_lock_until(chrono::steady_clock::now() + rel_time)`.]]
|
||||
|
||||
[[Synchronization:] [If `try_lock_for()` returns true, prior `unlock()` operations on the same object synchronize with this operation.]]
|
||||
@@ -1134,7 +1183,7 @@ As the semantic "ensures that the associated mutex is locked during the lifetime
|
||||
The following classes are models of `StrictLock`:
|
||||
|
||||
* strict_lock: ensured by construction,
|
||||
* nested_strict_lock: ensured by construction,
|
||||
* nested_strict_lock: "sur parolle" as the user could use adopt_lock_t on unique_lock constructor overload without having locked the mutex,
|
||||
* __lock_guard__: "sur parolle" as the user could use adopt_lock_t constructor overload without having locked the mutex.
|
||||
|
||||
[endsect] [/ Models]
|
||||
@@ -2002,6 +2051,8 @@ __reverse_mutex reverse the operations of a __BasicLockable, that unlocks the lo
|
||||
{
|
||||
public:
|
||||
typedef BasicLockable mutex_type;
|
||||
strict_lock(strict_lock const& m_) = delete;
|
||||
strict_lock& operator=(strict_lock const& m_) = delete;
|
||||
explicit strict_lock(mutex_type& m_);
|
||||
~strict_lock();
|
||||
|
||||
@@ -2052,6 +2103,8 @@ object passed to the constructor.]]
|
||||
{
|
||||
public:
|
||||
typedef BasicLockable mutex_type;
|
||||
nested_strict_lock(nested_strict_lock const& m_) = delete;
|
||||
nested_strict_lock& operator=(nested_strict_lock const& m_) = delete;
|
||||
explicit nested_strict_lock(Lock& lk),
|
||||
~nested_strict_lock() noexcept;
|
||||
|
||||
@@ -2154,15 +2207,247 @@ If the lock doesn't owns the mutex lock it.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lock_ptrs Locking pointers]
|
||||
|
||||
// #include <boost/thread/synchroniezd_value.hpp>
|
||||
// #include <boost/thread/strict_lock_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<typename T, typename Lockable = mutex>
|
||||
class strict_lock_ptr;
|
||||
template<typename T, typename Lockable = mutex>
|
||||
class const_strict_lock_ptr;
|
||||
}
|
||||
|
||||
|
||||
[/
|
||||
template<typename T, typename Lockable = mutex>
|
||||
class unique_lock_ptr;
|
||||
template<typename T, typename Lockable = mutex>
|
||||
class const_unique_lock_ptr;
|
||||
|
||||
]
|
||||
|
||||
[section:const_strict_lock_ptr Class template `const_strict_lock_ptr `]
|
||||
|
||||
// #include <boost/thread/synchroniezd_value.hpp>
|
||||
// #include <boost/thread/strict_lock_ptr.hpp>
|
||||
|
||||
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class const_strict_lock_ptr
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
const_strict_lock_ptr(const_strict_lock_ptr const& m_) = delete;
|
||||
const_strict_lock_ptr& operator=(const_strict_lock_ptr const& m_) = delete;
|
||||
|
||||
const_strict_lock_ptr(T const& val, Lockable & mtx);
|
||||
const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag);
|
||||
|
||||
~const_strict_lock_ptr();
|
||||
|
||||
const T* operator->() const;
|
||||
const T& operator*() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
[section:constructor `const_strict_lock_ptr(T const&,Lockable&)`]
|
||||
|
||||
|
||||
const_strict_lock_ptr(T const& val, Lockable & m);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Invokes [lock_ref_link `m.lock()`], stores a reference to it and to the value type `val`.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:constructor_adopt `const_strict_lock_ptr(T const&,Lockable&,adopt_lock_t)`]
|
||||
|
||||
const_strict_lock_ptr(T const& val, Lockable & m, adopt_lock_t tag);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Stores a reference to it and to the value type `val`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:destructor `~const_strict_lock_ptr()`]
|
||||
|
||||
~const_strict_lock_ptr();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__
|
||||
object passed to the constructor.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:indir `operator->() const`]
|
||||
|
||||
const T* operator->() const;
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [return a constant pointer to the protected value.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:deref `operator*() const`]
|
||||
|
||||
const T& operator*() const;
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [return a constant reference to the protected value.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect] [/ const_strict_lock_ptr ]
|
||||
|
||||
[section:strict_lock_ptr Class template `strict_lock_ptr`]
|
||||
|
||||
// #include <boost/thread/synchroniezd_value.hpp>
|
||||
// #include <boost/thread/strict_lock_ptr.hpp>
|
||||
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable>
|
||||
{
|
||||
public:
|
||||
strict_lock_ptr(strict_lock_ptr const& m_) = delete;
|
||||
strict_lock_ptr& operator=(strict_lock_ptr const& m_) = delete;
|
||||
|
||||
strict_lock_ptr(T & val, Lockable & mtx);
|
||||
strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag);
|
||||
~strict_lock_ptr();
|
||||
|
||||
T* operator->();
|
||||
T& operator*();
|
||||
|
||||
};
|
||||
|
||||
|
||||
[section:constructor `strict_lock_ptr(T const&,Lockable&)`]
|
||||
|
||||
|
||||
strict_lock_ptr(T const& val, Lockable & m);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Invokes [lock_ref_link `m.lock()`], stores a reference to it and to the value type `val`.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:constructor_adopt `strict_lock_ptr(T const&,Lockable&,adopt_lock_t)`]
|
||||
|
||||
strict_lock_ptr(T const& val, Lockable & m, adopt_lock_t tag);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Stores a reference to it and to the value type `val`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:destructor `~strict_lock_ptr()`]
|
||||
|
||||
~ strict_lock_ptr();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__
|
||||
object passed to the constructor.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:indir `operator->()`]
|
||||
|
||||
T* operator->();
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [return a pointer to the protected value.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:deref `operator*()`]
|
||||
|
||||
T& operator*();
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [return a reference to the protected value.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect] [/ strict_lock_ptr ]
|
||||
|
||||
[endsect] [/ lock_ptrs ]
|
||||
|
||||
|
||||
[section Externally Locked]
|
||||
|
||||
// #include <boost/thread/externally_locked.hpp>
|
||||
template <class T, typename MutexType = boost::mutex>
|
||||
class externally_locked;
|
||||
template <class T, typename MutexType>
|
||||
class externally_locked<T&, MutexType>;
|
||||
|
||||
template <typename T, typename MutexType>
|
||||
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs);
|
||||
|
||||
[section Template Class `externally_locked`]
|
||||
[section:externally_locked Template Class `externally_locked`]
|
||||
|
||||
// #include <boost/thread/externally_locked.hpp>
|
||||
|
||||
@@ -2178,8 +2463,11 @@ If the lock doesn't owns the mutex lock it.
|
||||
externally_locked(mutex_type& mtx, const T& obj);
|
||||
externally_locked(mutex_type& mtx,T&& obj);
|
||||
explicit externally_locked(mutex_type& mtx);
|
||||
externally_locked(externally_locked const& rhs);
|
||||
externally_locked(externally_locked&& rhs);
|
||||
|
||||
externally_locked& operator=(externally_locked const& rhs);
|
||||
externally_locked& operator=(externally_locked&& rhs);
|
||||
|
||||
// observers
|
||||
T& get(strict_lock<mutex_type>& lk);
|
||||
const T& get(strict_lock<mutex_type>& lk) const;
|
||||
@@ -2194,7 +2482,7 @@ If the lock doesn't owns the mutex lock it.
|
||||
template <class Lock>
|
||||
T const& get(Lock& lk) const;
|
||||
|
||||
mutex_type* mutex();
|
||||
mutex_type* mutex() const noexcept;
|
||||
|
||||
// modifiers
|
||||
void lock();
|
||||
@@ -2258,7 +2546,7 @@ Only the specificities respect to __Lockable are described here.
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:constructor4 `externally_locked(externally_locked&)`]
|
||||
[section:constructor4 `externally_locked(externally_locked&&)`]
|
||||
|
||||
externally_locked(externally_locked&& rhs);
|
||||
|
||||
@@ -2266,13 +2554,62 @@ Only the specificities respect to __Lockable are described here.
|
||||
|
||||
[[Requires:] [T is a model of Movable.]]
|
||||
|
||||
[[Effects:] [Moves an externally locked object by moving the the cloaked type and copying the mutex reference ]]
|
||||
[[Effects:] [Move constructs an externally locked object by moving the cloaked type and copying the mutex reference ]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to `T(T&&)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:constructor5 `externally_locked(externally_locked&)`]
|
||||
|
||||
externally_locked(externally_locked& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [T is a model of Copyable.]]
|
||||
|
||||
[[Effects:] [Copy constructs an externally locked object by copying the cloaked type and copying the mutex reference ]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to `T(T&)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:assign4 `externally_locked(externally_locked&&)`]
|
||||
|
||||
externally_locked& operator=(externally_locked&& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [T is a model of Movable.]]
|
||||
|
||||
[[Effects:] [Move assigns an externally locked object by moving the cloaked type and copying the mutex reference ]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to `T::operator=(T&&)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:assign5 `externally_locked(externally_locked&)`]
|
||||
|
||||
externally_locked& operator=(externally_locked const& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [T is a model of Copyable.]]
|
||||
|
||||
[[Effects:] [Copy assigns an externally locked object by copying the cloaked type and copying the mutex reference ]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to `T::operator=(T&)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:get1 `get(strict_lock<mutex_type>&)`]
|
||||
|
||||
@@ -2331,8 +2668,172 @@ Only the specificities respect to __Lockable are described here.
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[section:externally_locked_ref Template Class `externally_locked<T&>`]
|
||||
|
||||
// #include <boost/thread/externally_locked.hpp>
|
||||
|
||||
template <class T, typename MutexType>
|
||||
class externally_locked<T&, MutexType>
|
||||
{
|
||||
//BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));
|
||||
|
||||
public:
|
||||
typedef MutexType mutex_type;
|
||||
|
||||
externally_locked(mutex_type& mtx, T& obj);
|
||||
explicit externally_locked(mutex_type& mtx);
|
||||
externally_locked(externally_locked const& rhs) noexcept;
|
||||
externally_locked(externally_locked&& rhs) noexcept;
|
||||
externally_locked& operator=(externally_locked const& rhs) noexcept;
|
||||
externally_locked& operator=(externally_locked&& rhs) noexcept;
|
||||
|
||||
// observers
|
||||
T& get(strict_lock<mutex_type>& lk);
|
||||
const T& get(strict_lock<mutex_type>& lk) const;
|
||||
|
||||
template <class Lock>
|
||||
T& get(nested_strict_lock<Lock>& lk);
|
||||
template <class Lock>
|
||||
const T& get(nested_strict_lock<Lock>& lk) const;
|
||||
|
||||
template <class Lock>
|
||||
T& get(Lock& lk);
|
||||
template <class Lock>
|
||||
T const& get(Lock& lk) const;
|
||||
|
||||
mutex_type* mutex() const noexcept;
|
||||
|
||||
// modifiers
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
void swap(externally_locked&) noexcept;
|
||||
};
|
||||
|
||||
`externally_locked` is a model of __Lockable, it 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.
|
||||
|
||||
Only the specificities respect to __Lockable are described here.
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:swap `swap(externally_locked, externally_locked&)`]
|
||||
[section:constructor1 `externally_locked<T&>(mutex_type&, T&)`]
|
||||
|
||||
externally_locked<T&>(mutex_type& mtx, T& obj) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
|
||||
[[Effects:] [Constructs an externally locked object copying the cloaked reference.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:constructor4 `externally_locked<T&>(externally_locked&&)`]
|
||||
|
||||
externally_locked(externally_locked&& rhs) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Moves an externally locked object by moving the cloaked type and copying the mutex reference ]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:assign4 `externally_locked(externally_locked&&)`]
|
||||
|
||||
externally_locked& operator=(externally_locked&& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Move assigns an externally locked object by copying the cloaked reference and copying the mutex reference ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:assign5 `externally_locked(externally_locked&)`]
|
||||
|
||||
externally_locked& operator=(externally_locked const& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [T is a model of Copyable.]]
|
||||
|
||||
[[Effects:] [Copy assigns an externally locked object by copying the cloaked reference and copying the mutex reference ]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to `T::operator=(T&)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:get1 `get(strict_lock<mutex_type>&)`]
|
||||
|
||||
T& get(strict_lock<mutex_type>& lk);
|
||||
const T& get(strict_lock<mutex_type>& lk) const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The `lk` parameter must be locking the associated mutex.]]
|
||||
|
||||
[[Returns:] [A reference to the cloaked object ]]
|
||||
|
||||
[[Throws:] [__lock_error__ if `BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED` is defined and the run-time preconditions are not satisfied .]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:get2 `get(strict_lock<nested_strict_lock<Lock>>&)`]
|
||||
|
||||
template <class Lock>
|
||||
T& get(nested_strict_lock<Lock>& lk);
|
||||
template <class Lock>
|
||||
const T& get(nested_strict_lock<Lock>& lk) const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`is_same<mutex_type, typename Lock::mutex_type>` and the `lk` parameter must be locking the associated mutex.]]
|
||||
|
||||
[[Returns:] [A reference to the cloaked object ]]
|
||||
|
||||
[[Throws:] [__lock_error__ if `BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED` is defined and the run-time preconditions are not satisfied .]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:get3 `get(strict_lock<nested_strict_lock<Lock>>&)`]
|
||||
|
||||
template <class Lock>
|
||||
T& get(Lock& lk);
|
||||
template <class Lock>
|
||||
T const& get(Lock& lk) const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Lock` is a model of __StrictLock, `is_same<mutex_type, typename Lock::mutex_type>` and the `lk` parameter must be locking the associated mutex.]]
|
||||
|
||||
[[Returns:] [A reference to the cloaked object ]]
|
||||
|
||||
[[Throws:] [__lock_error__ if `BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED` is defined and the run-time preconditions are not satisfied .]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:swap `swap(externally_locked&, externally_locked&)`]
|
||||
|
||||
template <typename T, typename MutexType>
|
||||
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs)
|
||||
|
||||
@@ -239,3 +239,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
[include shared_mutex_ref.qbk]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
28
doc/once.qbk
28
doc/once.qbk
@@ -12,8 +12,8 @@
|
||||
namespace boost
|
||||
{
|
||||
struct once_flag;
|
||||
template<typename Callable>
|
||||
void call_once(once_flag& flag,Callable func);
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, Function&& f, ArgTypes&&... args);
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
void call_once(void (*func)(),once_flag& flag);
|
||||
@@ -21,6 +21,11 @@
|
||||
|
||||
}
|
||||
|
||||
[warning the variadic prototype is provided only on C++11 compilers supporting variadic templates, otherwise the interface is limited up to 3 parameters.]
|
||||
|
||||
[warning the move semantics is ensured only on C++11 compilers supporting SFINAE expression, decltype N3276 and auto. Waiting for a boost::bind that is move aware.]
|
||||
|
||||
|
||||
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
|
||||
|
||||
[section:once_flag Typedef `once_flag`]
|
||||
@@ -45,24 +50,22 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT` i
|
||||
|
||||
[section:call_once Non-member function `call_once`]
|
||||
|
||||
template<typename Callable>
|
||||
void call_once(once_flag& flag,Callable func);
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, Function&& f, ArgTypes&&... args);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall
|
||||
be equivalent to calling the original. ]]
|
||||
[[Requires:] [`Function` and each or the `ArgTypes` are `MoveConstructible` and `invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...)` shall be well formed. ]]
|
||||
|
||||
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
|
||||
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
|
||||
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
|
||||
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
|
||||
the same `once_flag` object, the argument `func` is called as-if by invoking `invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...)`, and the invocation of
|
||||
`call_once` is effective if and only if `invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...)` returns without exception. If an exception is thrown, the exception is propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
|
||||
without invoking `func`. ]]
|
||||
|
||||
[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with
|
||||
all subsequent `call_once` invocations on the same `once_flag` object. ]]
|
||||
|
||||
[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]]
|
||||
[[Throws:] [`thread_resource_error` when the effects cannot be achieved or any exception propagated from `func`.]]
|
||||
|
||||
[[Note:] [The function passed to `call_once` must not also call
|
||||
`call_once` passing the same `once_flag` object. This may cause
|
||||
@@ -73,11 +76,14 @@ proceed even though the call to `call_once` didn't actually call the
|
||||
function, in which case it could also avoid calling `call_once`
|
||||
recursively.]]
|
||||
|
||||
|
||||
[[Note:] [On some compilers this function has some restrictions, e.g. if variadic templates are not supported the number of arguments is limited to 3; .]]
|
||||
|
||||
]
|
||||
|
||||
void call_once(void (*func)(),once_flag& flag);
|
||||
|
||||
This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of
|
||||
This second overload is provided for backwards compatibility and is deprecated. The effects of `call_once(func,flag)` shall be the same as those of
|
||||
`call_once(flag,func)`.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -105,6 +105,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
strict_scoped_thread& operator=(strict_scoped_thread const&) = delete;
|
||||
|
||||
explicit strict_scoped_thread(thread&& t) noexcept;
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
|
||||
~strict_scoped_thread();
|
||||
|
||||
@@ -125,7 +127,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
boost::strict_scoped_thread<> t((boost::thread(F)));
|
||||
|
||||
[section:default_constructor Default Constructor]
|
||||
[section:default_constructor Constructor from a __thread]
|
||||
|
||||
explicit strict_scoped_thread(thread&& t) noexcept;
|
||||
|
||||
@@ -139,6 +141,24 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:call_constructor Move Constructor from a Callable]
|
||||
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a internal thread in place.]]
|
||||
|
||||
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
|
||||
|
||||
[[Throws:] [Any exception the thread construction can throw.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
~strict_scoped_thread();
|
||||
@@ -149,7 +169,6 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
[[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]
|
||||
@@ -160,6 +179,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
template <class CallableThread>
|
||||
class scoped_thread
|
||||
{
|
||||
thread t_; // for exposition purposes only
|
||||
@@ -169,6 +189,8 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
scoped_thread& operator=(const scoped_thread&) = delete;
|
||||
|
||||
explicit scoped_thread(thread&& th) noexcept;
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
|
||||
~scoped_thread();
|
||||
|
||||
@@ -298,6 +320,23 @@ any) to `*this`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:call_constructor Move Constructor from a Callable]
|
||||
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a internal thread in place.]]
|
||||
|
||||
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
|
||||
|
||||
[[Throws:] [Any exception the thread construction can throw.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:destructor Destructor]
|
||||
|
||||
|
||||
547
doc/sync_queues_ref.qbk
Normal file
547
doc/sync_queues_ref.qbk
Normal file
@@ -0,0 +1,547 @@
|
||||
[section:synchronized_queues Synchronized Queues -- EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3533.html [*N3533 - C++ Concurrent Queues]] C++1y proposal from Lawrence Crowl and Chris Mysen and [@http://www.manning.com/williams/ [*C++ Concurrency in Action]] from Anthony Williams.]
|
||||
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Concurrent queues are a well know mechanism for communicating data between different threads.
|
||||
|
||||
Concurrent queues have inherently copy/move semantics for the data handling operation. Reference-returning interfaces are forbidden as multiple access to these references can not be thread-safe.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:ref Reference]
|
||||
|
||||
[section:sync_queue_req Synchronized Queue Model]
|
||||
|
||||
[section:bounded_unbounded Bounded-Unbounded Queues]
|
||||
|
||||
One of the major features of a concurrent queue is whether it has a bounded-unbounded capacity.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:locking Locking/Lock-free Queues]
|
||||
|
||||
Locking queues can by nature block waiting for the queue to be non-empty or non-full.
|
||||
|
||||
Lock-free queues will have some trouble waiting for the queue to be non-empty or non-full queues. These queues can not define operations such as push (and pull for bounded queues). That is, it could have blocking operations (presumably emulated with busy wait) but not waiting operations.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:closed Closed Queue]
|
||||
|
||||
Threads using a queue for communication need some mechanism to signal when the queue is no longer needed. The usual approach is add an additional out-of-band signal. However, this approach suffers from the flaw that threads waiting on either full or empty queues need to be woken up when the queue is no longer needed. Rather than require an out-of-band signal, we chose to directly support such a signal in the queue itself, which considerably simplifies coding.
|
||||
|
||||
To achieve this signal, a thread may close a queue. Once closed, no new elements may be pushed onto the queue. Push operations on a closed queue will either return queue_op_status::closed (when they have a queue_op_status return type), set the closed parameter if it has one or throw sync_queue::closed (when they do not). Elements already on the queue may be pulled off. When a queue is empty and closed, pull operations will either return queue_op_status::closed (when they have a status return), set the closed parameter if it has one or throw sync_queue::closed (when they do not).
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:exception Concurrent Queues Throw specification]
|
||||
[section:locking Locking]
|
||||
|
||||
All the functions are defined as if we had in addition to its specific Throw specification the following:
|
||||
|
||||
[variablelist
|
||||
[[Throws:] [Any exception thrown by the internal locking.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:bad_alloc Allocation]
|
||||
|
||||
All the functions that allocate a resource are defined as if we had in addition to its specific Throw specification the following:
|
||||
|
||||
[variablelist
|
||||
[[Throws:] [Any exception due to allocation errors.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[section:BasicConcurrentQueue Basic Concurrent Queue Operations]
|
||||
|
||||
The essential solution to the problem of concurrent queuing is to shift to value-based operations, rather than reference-based operations.
|
||||
|
||||
The BasicConcurrentQueue concept models the basic operations of a concurrent queue.
|
||||
|
||||
A type `Q` meets the BasicConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* Q::value_type
|
||||
* Q::size_type
|
||||
* `q.push(e);`
|
||||
* `q.push(rve);`
|
||||
* `q.pull(lre);`
|
||||
* `lre = q.pull();`
|
||||
* `spe = q.ptr_pull();`
|
||||
* `b = q.empty();`
|
||||
* `u = q.size();`
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
|
||||
|
||||
[section:push `q.push(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.empty()`.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [If the queue was closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:push_m `q.push(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.empty()`.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:pull_lv `q.pull(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pull `e = q.pull()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety.]]
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`Q::value_type`.]]
|
||||
|
||||
[[Return:] [The pulled element.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:ptr_pull `spe = q.ptr_pull()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[/[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety. ]]
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element into a shared_ptr.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`Q::value_type`.]]
|
||||
|
||||
[[Return:] [A shared_ptr containing the pulled element.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`. Any exception throw when allocation resources are missing. ]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:non_waaiting Non-waiting Concurrent Queue Operations]
|
||||
|
||||
The ConcurrentQueue concept models a queue with .
|
||||
|
||||
|
||||
A type `Q` meets the ConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `b = q.try_push(e);`
|
||||
* `b = q.try_push(rve);`
|
||||
* `b = q.try_pull(lre);`
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
|
||||
|
||||
[section:try_push `q.try_push(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full, push the `e` to the queue copying it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation when the operation succeeds. ]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
|
||||
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:try_push_m `q.try_push(rve());`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full, push the `e` onto the queue moving it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
|
||||
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:pull_lv `b = q.try_pull(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[section:non_blocking Non-blocking Concurrent Queue Operations]
|
||||
|
||||
For cases when blocking for mutual exclusion is undesirable, we have non-blocking operations. The interface is the same as the try operations but is allowed to also return queue_op_status::busy in case the operation is unable to complete without blocking.
|
||||
|
||||
Non-blocking operations are provided only for BlockingQueues
|
||||
|
||||
* `b = q.try_push(nb, e);`
|
||||
* `b = q.try_push(nb, rve);`
|
||||
* `b = q.try_pull(nb, lre);`
|
||||
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:bounded Bounded Concurrent Queue Operations]
|
||||
|
||||
Bounded queues add the following valid expressions
|
||||
|
||||
* `Q q(u);`
|
||||
* `b = q.full();`
|
||||
* `u = q.capacity();`
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:closed_op Closed Concurrent Queue Operations]
|
||||
|
||||
|
||||
* `q.close();`
|
||||
* `b = q.closed();`
|
||||
|
||||
Basic expressions
|
||||
|
||||
* `q.push(e,c);`
|
||||
* `q.push(rve,c);`
|
||||
* `q.pull(lre,c);`
|
||||
* `spe = q.ptr_pull(c);`
|
||||
|
||||
Non-waiting operations
|
||||
|
||||
* `b = q.try_push(e, c);`
|
||||
* `b = q.try_push(rve, c);`
|
||||
* `b = q.try_pull(lre, c);`
|
||||
|
||||
Non-blocking operations are provided by BlockingQueues
|
||||
|
||||
* `b = q.try_push(nb, e, c);`
|
||||
* `b = q.try_push(nb, rve, c);`
|
||||
* `b = q.try_pull(nb, lre, c);`
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:sync_bounded_queue_ref Synchronized Bounded Queue]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct sync_queue_is_closed : std::exception {};
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue;
|
||||
|
||||
// Stream-like operators
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType&& elem);
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem);
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[section:sync_queue_is_closed Class `sync_queue_is_closed`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct sync_queue_is_closed : std::exception {};
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:sync_bounded_queue Class template `sync_bounded_queue<>`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
sync_bounded_queue(sync_bounded_queue const&) = delete;
|
||||
sync_bounded_queue& operator=(sync_bounded_queue const&) = delete;
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type capacity() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(value_type&& x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, value_type&& x);
|
||||
|
||||
void pull(value_type&);
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stream_out_operators Non-Member Function `operator<<()`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType&& elem);
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem);
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[section:stream_in_operators Non-Member Function `operator>>()`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[section:sync_queue_ref Synchronized Unbounded Queue]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_queue;
|
||||
|
||||
// Stream-like operators
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType&& elem);
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem);
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[section:sync_queue Class template `sync_queue<>`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
sync_queue(sync_queue const&) = delete;
|
||||
sync_queue& operator=(sync_queue const&) = delete;
|
||||
sync_queue();
|
||||
explicit template <typename Range>
|
||||
sync_queue(Range range);
|
||||
~sync_queue();
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(value_type&&) x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, value_type&& x);
|
||||
|
||||
void pull(value_type&);
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stream_out_operators Non-Member Function `operator<<()`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType&& elem);
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem);
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[section:stream_in_operators Non-Member Function `operator>>()`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
190
doc/sync_streams.qbk
Normal file
190
doc/sync_streams.qbk
Normal file
@@ -0,0 +1,190 @@
|
||||
[/
|
||||
/ Copyright (c) 2013 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:ext_locked_streams Externally Locked Streams - EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3535.html [*N3535 - C++ Streams Mutex]] C++1y proposal, even if the library proposes al alternative interface.]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
[endsect] [/tutorial]
|
||||
|
||||
[section:ref Reference]
|
||||
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename Stream, typename RecursiveMutex=recursive_mutex>
|
||||
class externally_locked_stream;
|
||||
template <class Stream, typename RecursiveMutex=recursive_mutex>
|
||||
class stream_guard;
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
struct is_strict_lock_sur_parolle<stream_guard<Stream, RecursiveMutex> > : true_type {};
|
||||
|
||||
// Stream-like operators
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, T arg);
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
const stream_guard<Stream, RecursiveMutex>&
|
||||
operator<<(const stream_guard<Stream, RecursiveMutex>& lck, Stream& (*arg)(Stream&));
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
const stream_guard<Stream, RecursiveMutex>&
|
||||
operator>>(const stream_guard<Stream, RecursiveMutex>& lck, T& arg);
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
stream_guard<Stream, RecursiveMutex>
|
||||
operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, T arg);
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
stream_guard<Stream, RecursiveMutex>
|
||||
operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, Stream& (*arg)(Stream&));
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
stream_guard<Stream, RecursiveMutex>
|
||||
operator>>(externally_locked_stream<Stream, RecursiveMutex>& mtx, T& arg);
|
||||
}
|
||||
|
||||
|
||||
[section:stream_guard Class `stream_guard`]
|
||||
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <class Stream, typename RecursiveMutex=recursive_mutex>
|
||||
class stream_guard
|
||||
{
|
||||
public:
|
||||
typedef typename externally_locked_stream<Stream, RecursiveMutex>::mutex_type mutex_type;
|
||||
|
||||
// Constructors, Assignment and Destructors
|
||||
stream_guard(stream_guard const&) = delete;
|
||||
stream_guard& operator=(stream_guard const&) = delete;
|
||||
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx);
|
||||
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx, adopt_lock_t);
|
||||
stream_guard(stream_guard&& rhs);
|
||||
~stream_guard();
|
||||
|
||||
// Observers
|
||||
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT;
|
||||
Stream& get() const;
|
||||
Stream& bypass() const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
`stream_guard` is a model of __StrictLock.
|
||||
|
||||
[section:constructor `stream_guard(mutex_type & m)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:constructor_adopt `stream_guard(mutex_type & m,boost::adopt_lock_t)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [The current thread owns a lock on `m` equivalent to one
|
||||
obtained by a call to [lock_ref_link `m.lock()`].]]
|
||||
|
||||
[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of
|
||||
`m`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:move_constructor `stream_guard(stream_guard && m)`]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:destructor `~stream_guard()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__
|
||||
object passed to the constructor.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
[section:externally_locked_stream Class `externally_locked_stream `]
|
||||
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
namespace boost
|
||||
{
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
class externally_locked_stream: public externally_locked<Stream&, RecursiveMutex>
|
||||
{
|
||||
public:
|
||||
// Constructors, Assignment and Destructors
|
||||
externally_locked_stream(externally_locked_stream const&) = delete;
|
||||
externally_locked_stream& operator=(externally_locked_stream const&) = delete;
|
||||
externally_locked_stream(Stream& stream, RecursiveMutex& mtx);
|
||||
|
||||
// Modifiers
|
||||
stream_guard<Stream, RecursiveMutex> hold();
|
||||
Stream& bypass() const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
`externally_locked_stream` cloaks a reference to an stream of type `Stream`, and actually
|
||||
provides full access to that object through the `get` member functions, provided you
|
||||
pass a reference to a strict lock object.
|
||||
|
||||
|
||||
[section:constructor `externally_locked_stream(Stream&, RecursiveMutex&)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an externally locked object storing the cloaked reference object and its locking mutex.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:hold `hold()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [A stream_guard which will hold the mutex during it lifetime .]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect] [/ref]
|
||||
|
||||
[endsect] [/Externally Locked Streams]
|
||||
147
doc/synchronized_value.qbk
Normal file
147
doc/synchronized_value.qbk
Normal file
@@ -0,0 +1,147 @@
|
||||
[/
|
||||
/ Copyright (c) 2013 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:synchronized_valuesxxx Synchronized values - EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
|
||||
[note This tutorial is an adaptation of the paper of Anthony Williams "Enforcing Correct Mutex Usage with Synchronized Values" to the Boost library.]
|
||||
|
||||
[section The Problem with Mutexes]
|
||||
|
||||
The key problem with protecting shared data with a mutex is that there is no easy way to associate the mutex with the data. It is thus relatively easy to accidentally write code that fails to lock the right mutex - or even locks the wrong mutex - and the compiler will not help you.
|
||||
|
||||
|
||||
std::mutex m1;
|
||||
int value1;
|
||||
std::mutex m2;
|
||||
int value2;
|
||||
|
||||
int readValue1()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lk(m1);
|
||||
return value1;
|
||||
}
|
||||
int readValue2()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lk(m1); // oops: wrong mutex
|
||||
return value2;
|
||||
}
|
||||
|
||||
Moreover, managing the mutex lock also clutters the source code, making it harder to see what is really going on.
|
||||
|
||||
The use of synchronized_value solves both these problems - the mutex is intimately tied to the value, so you cannot access it without a lock, and yet access semantics are still straightforward. For simple accesses, synchronized_value behaves like a pointer-to-T; for example:
|
||||
|
||||
|
||||
boost::synchronized_value<std::string> value3;
|
||||
std::string readValue3()
|
||||
{
|
||||
return *value3;
|
||||
}
|
||||
void setValue3(std::string const& newVal)
|
||||
{
|
||||
*value3=newVal;
|
||||
}
|
||||
void appendToValue3(std::string const& extra)
|
||||
{
|
||||
value3->append(extra);
|
||||
}
|
||||
|
||||
Both forms of pointer dereference return a proxy object rather than a real reference, to ensure that the lock on the mutex is held across the assignment or method call, but this is transparent to the user.
|
||||
|
||||
[endsect] [/The Problem with Mutexes]
|
||||
|
||||
[section Beyond Simple Accesses]
|
||||
|
||||
The pointer-like semantics work very well for simple accesses such as assignment and calls to member functions. However, sometimes you need to perform an operation that requires multiple accesses under protection of the same lock, and that's what the synchronize() method provides.
|
||||
|
||||
By calling synchronize() you obtain an strict_lock_ptr object that holds a lock on the mutex protecting the data, and which can be used to access the protected data. The lock is held until the strict_lock_ptr object is destroyed, so you can safely perform multi-part operations. The strict_lock_ptr object also acts as a pointer-to-T, just like synchronized_value does, but this time the lock is already held. For example, the following function adds a trailing slash to a path held in a synchronized_value. The use of the strict_lock_ptr object ensures that the string hasn't changed in between the query and the update.
|
||||
|
||||
void addTrailingSlashIfMissing(boost::synchronized_value<std::string> & path)
|
||||
{
|
||||
boost::strict_lock_ptr<std::string> u=path.synchronize();
|
||||
|
||||
if(u->empty() || (*u->rbegin()!='/'))
|
||||
{
|
||||
*u+='/';
|
||||
}
|
||||
}
|
||||
|
||||
[endsect] [/Beyond Simple Accesses]
|
||||
|
||||
[section Operations Across Multiple Objects]
|
||||
|
||||
Though synchronized_value works very well for protecting a single object of type T, nothing that we've seen so far solves the problem of operations that require atomic access to multiple objects unless those objects can be combined within a single structure protected by a single mutex.
|
||||
|
||||
One way to protect access to two synchronized_value objects is to construct a strict_lock_ptr for each object and use those to access the respective protected values; for instance:
|
||||
|
||||
synchronized_value<std::queue<MessageType> > q1,q2;
|
||||
void transferMessage()
|
||||
{
|
||||
strict_lock_ptr<std::queue<MessageType> > u1 = q1.synchronize();
|
||||
strict_lock_ptr<std::queue<MessageType> > u2 = q2.synchronize();
|
||||
|
||||
if(!u1->empty())
|
||||
{
|
||||
u2->push_back(u1->front());
|
||||
u1->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
This works well in some scenarios, but not all -- if the same two objects are updated together in different sections of code then you need to take care to ensure that the strict_lock_ptr objects are constructed in the same sequence in all cases, otherwise you have the potential for deadlock. This is just the same as when acquiring any two mutexes.
|
||||
|
||||
In order to be able to use the dead-lock free lock algorithms we need to use instead unique_lock_ptr, which is Lockable.
|
||||
|
||||
synchronized_value<std::queue<MessageType> > q1,q2;
|
||||
void transferMessage()
|
||||
{
|
||||
unique_lock_ptr<std::queue<MessageType> > u1 = q1.unique_synchronize(boost::defer_lock);
|
||||
unique_lock_ptr<std::queue<MessageType> > u2 = q2.unique_synchronize(boost::defer_lock);
|
||||
boost::lock(u1,u2); // dead-lock free algorithm
|
||||
|
||||
if(!u1->empty())
|
||||
{
|
||||
u2->push_back(u1->front());
|
||||
u1->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
While the preceding takes care of dead-lock, the access to the synchronized_value via unique_lock_ptr requires a lock that is not forced by the interface.
|
||||
An alternative on compilers providing a standard library that supports movable std::tuple is to use the free synchronize function, which will lock all the mutexes associated to the synchronized values and return a tuple os strict_lock_ptr.
|
||||
|
||||
synchronized_value<std::queue<MessageType> > q1,q2;
|
||||
void transferMessage()
|
||||
{
|
||||
auto lks = synchronize(u1,u2); // dead-lock free algorithm
|
||||
|
||||
if(!std::get<1>(lks)->empty())
|
||||
{
|
||||
std::get<2>(lks)->push_back(u1->front());
|
||||
std::get<1>(lks)->pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[endsect] [/Operations Across Multiple Objects]
|
||||
|
||||
[section Value semantics]
|
||||
|
||||
synchronized_value has value semantics even if the syntax lets is close to a pointer (this is just because we are unable to define smart references).
|
||||
|
||||
[endsect] [/Value semantics]
|
||||
|
||||
|
||||
[endsect] [/tutorial]
|
||||
|
||||
[include synchronized_value_ref.qbk]
|
||||
|
||||
[endsect] [/Synchronized values]
|
||||
|
||||
408
doc/synchronized_value_ref.qbk
Normal file
408
doc/synchronized_value_ref.qbk
Normal file
@@ -0,0 +1,408 @@
|
||||
[section:synchronized_value_ref Reference ]
|
||||
|
||||
|
||||
#include <boost/thread/synchronized_value.hpp>
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<typename T, typename Lockable = mutex>
|
||||
class synchronized_value;
|
||||
|
||||
// Specialized swap algorithm
|
||||
template <typename T, typename L>
|
||||
void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs);
|
||||
template <typename T, typename L>
|
||||
void swap(synchronized_value<T,L> & lhs, T & rhs);
|
||||
template <typename T, typename L>
|
||||
void swap(T & lhs, synchronized_value<T,L> & rhs);
|
||||
|
||||
// Hash support
|
||||
template<typename T, typename L>
|
||||
struct hash<synchronized_value<T,L> >;
|
||||
|
||||
// Comparison
|
||||
template <typename T, typename L>
|
||||
bool operator==(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
template <typename T, typename L>
|
||||
bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
template <typename T, typename L>
|
||||
bool operator<(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
template <typename T, typename L>
|
||||
bool operator<=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
template <typename T, typename L>
|
||||
bool operator>(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
template <typename T, typename L>
|
||||
bool operator>=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
|
||||
// Comparison with T
|
||||
template <typename T, typename L>
|
||||
bool operator==(T const& lhs, synchronized_value<T,L> const&rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator<(T const& lhs, synchronized_value<T,L> const&rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator>(T const& lhs, synchronized_value<T,L> const&rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs);
|
||||
|
||||
template <typename T, typename L>
|
||||
bool operator==(synchronized_value<T,L> const& lhs, T const& rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator!=(synchronized_value<T,L> const& lhs, T const& rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator<(synchronized_value<T,L> const& lhs, T const& rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator<=(synchronized_value<T,L> const& lhs, T const& rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator>(synchronized_value<T,L> const& lhs, T const& rhs);
|
||||
template <typename T, typename L>
|
||||
bool operator>=(synchronized_value<T,L> const& lhs, T const& rhs);
|
||||
|
||||
#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
|
||||
template <typename ...SV>
|
||||
std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
|
||||
#endif
|
||||
}
|
||||
|
||||
[section:synchronized_value Class `synchronized_value`]
|
||||
|
||||
#include <boost/thread/synchronized_value.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<typename T, typename Lockable = mutex>
|
||||
class synchronized_value
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
synchronized_value() noexept(is_nothrow_default_constructible<T>::value);
|
||||
synchronized_value(T const& other) noexept(is_nothrow_copy_constructible<T>::value);
|
||||
synchronized_value(T&& other) noexept(is_nothrow_move_constructible<T>::value);
|
||||
synchronized_value(synchronized_value const& rhs);
|
||||
synchronized_value(synchronized_value&& other);
|
||||
|
||||
// mutation
|
||||
synchronized_value& operator=(synchronized_value const& rhs);
|
||||
synchronized_value& operator=(value_type const& val);
|
||||
void swap(synchronized_value & rhs);
|
||||
void swap(value_type & rhs);
|
||||
|
||||
//observers
|
||||
T get() const;
|
||||
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
explicit operator T() const;
|
||||
#endif
|
||||
|
||||
strict_lock_ptr<T,Lockable> operator->();
|
||||
const_strict_lock_ptr<T,Lockable> operator->() const;
|
||||
strict_lock_ptr<T,Lockable> synchronize();
|
||||
const_strict_lock_ptr<T,Lockable> synchronize() const;
|
||||
|
||||
deref_value operator*();;
|
||||
const_deref_value operator*() const;
|
||||
|
||||
private:
|
||||
T value_; // for exposition only
|
||||
mutable mutex_type mtx_; // for exposition only
|
||||
};
|
||||
}
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Lockable` is `Lockable`.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[section:constructor `synchronized_value()`]
|
||||
|
||||
synchronized_value() noexept(is_nothrow_default_constructible<T>::value);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `DefaultConstructible`.]]
|
||||
[[Effects:] [Default constructs the cloaked value_type]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:constructor_vt `synchronized_value(T const&)`]
|
||||
|
||||
synchronized_value(T const& other) noexept(is_nothrow_copy_constructible<T>::value);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyConstructible`.]]
|
||||
[[Effects:] [Copy constructs the cloaked value_type using the parameter `other`]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(other)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:copy_cons `synchronized_value(synchronized_value const&)`]
|
||||
|
||||
synchronized_value(synchronized_value const& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[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.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type()` or `value_type& operator=(value_type&)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move_vt `synchronized_value(T&&)`]
|
||||
|
||||
synchronized_value(T&& other) noexept(is_nothrow_move_constructible<T>::value);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyMovable `.]]
|
||||
[[Effects:] [Move constructs the cloaked value_type]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(value_type&&)`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move `synchronized_value(synchronized_value&&)`]
|
||||
|
||||
synchronized_value(synchronized_value&& other);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyMovable `.]]
|
||||
[[Effects:] [Move constructs the cloaked value_type]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:assign `operator=(synchronized_value const&)`]
|
||||
|
||||
synchronized_value& operator=(synchronized_value const& rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Assignale`.]]
|
||||
[[Effects:] [Copies the underlying value on a scope protected by the two mutexes. The mutex is not copied. The locks are acquired avoiding deadlock. For example, there is no problem if one thread assigns `a = b` and the other assigns `b = a`.]]
|
||||
[[Return:] [`*this`]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:assign_vt `operator=(T const&)`]
|
||||
|
||||
synchronized_value& operator=(value_type const& val);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Assignale`.]]
|
||||
[[Effects:] [Copies the value on a scope protected by the mutex.]]
|
||||
[[Return:] [`*this`]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get `get() const`]
|
||||
|
||||
T get() const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyConstructible`.]]
|
||||
[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:T `operator T() const`]
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
explicit operator T() const;
|
||||
#endif
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyConstructible`.]]
|
||||
[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:swap `swap(synchronized_value&)`]
|
||||
|
||||
void swap(synchronized_value & rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Assignale`.]]
|
||||
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:swap_vt `swap(synchronized_value&)`]
|
||||
|
||||
void swap(value_type & rhs);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Swapable`.]]
|
||||
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `swap(value_, rhs)` or `mtx_.lock()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:indir `operator->()`]
|
||||
|
||||
strict_lock_ptr<T,Lockable> operator->();
|
||||
|
||||
|
||||
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.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [`A strict_lock_ptr<>.`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:indir_const `operator->() const`]
|
||||
|
||||
const_strict_lock_ptr<T,Lockable> operator->() const;
|
||||
|
||||
|
||||
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.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [`A const_strict_lock_ptr <>.`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:synchronize `synchronize()`]
|
||||
|
||||
strict_lock_ptr<T,Lockable> synchronize();
|
||||
|
||||
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 vec2=vec.synchronize();
|
||||
vec2.push_back(42);
|
||||
assert(vec2.back() == 42);
|
||||
}
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [`A strict_lock_ptr <>.`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:synchronize_const `synchronize() const`]
|
||||
|
||||
const_strict_lock_ptr<T,Lockable> synchronize() const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [`A const_strict_lock_ptr <>.`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:deref `operator*()`]
|
||||
|
||||
deref_value operator*();;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a reference to the protected value.`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:deref_const `operator*() const`]
|
||||
|
||||
const_deref_value operator*() const;
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a constant reference to the protected value.`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
[section:synchronize Non-Member Function `synchronize`]
|
||||
|
||||
#include <boost/thread/synchronized_value.hpp>
|
||||
namespace boost
|
||||
{
|
||||
#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
|
||||
template <typename ...SV>
|
||||
std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
|
||||
#endif
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 4.0.0]
|
||||
[version 4.1.0]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-12 Vicente J. Botet Escriba]
|
||||
[copyright 2011-13 Vicente J. Botet Escriba]
|
||||
[purpose C++ Library for launching threads and synchronizing data between them]
|
||||
[category text]
|
||||
[license
|
||||
@@ -203,6 +203,7 @@
|
||||
[def __thread_resource_error__ `boost::thread_resource_error`]
|
||||
[def __thread_interrupted__ `boost::thread_interrupted`]
|
||||
[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]]
|
||||
[def __latch__ [link thread.synchronization.latches.latch `latch`]]
|
||||
|
||||
[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]]
|
||||
[def __cond_wait__ [cond_wait_link `wait()`]]
|
||||
@@ -238,11 +239,20 @@
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[/include latch.qbk]
|
||||
[include futures.qbk]
|
||||
[/include async_executors.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
[include tss.qbk]
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
[include synchronized_value.qbk]
|
||||
[/include sync_queues_ref.qbk]
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
[include time.qbk]
|
||||
|
||||
[include emulations.qbk]
|
||||
|
||||
@@ -201,7 +201,7 @@ __thread_interrupted__, `std::terminate()` is called.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:detac Detaching thread]
|
||||
[section:detach 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__.
|
||||
@@ -1708,7 +1708,6 @@ registered with `at_thread_exit()`]]
|
||||
[section:threadgroup Class `thread_group` EXTENSION]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_group.hpp>
|
||||
|
||||
class thread_group
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <vector>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include "../test/remove_error_code_unused_warning.hpp"
|
||||
|
||||
class bounded_buffer : private boost::noncopyable
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
// Copyright (C) 2012-2013 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_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>
|
||||
@@ -45,11 +44,9 @@ 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> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << f2.get() << BOOST_THREAD_END_LOG;
|
||||
(void)f2.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
|
||||
60
example/lambda_future.cpp
Normal file
60
example/lambda_future.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2013 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 <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
|
||||
int result = f1.get();
|
||||
BOOST_THREAD_LOG << "f1 " << result << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
|
||||
boost::future<int> f2 = f1.then([](boost::future<int>& f) {return 2*f.get(); });
|
||||
int result = f2.get();
|
||||
BOOST_THREAD_LOG << "f2 " << result << 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
|
||||
@@ -10,6 +10,15 @@
|
||||
|
||||
int p1() { return 5; }
|
||||
|
||||
void p() { }
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
boost::future<void> void_compute()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF(boost::make_future());
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::future<int> compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_future(0);
|
||||
@@ -30,10 +39,20 @@ boost::shared_future<int> shared_compute(int x)
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
{
|
||||
boost::future<void> f = void_compute();
|
||||
f.get();
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::future<int> f = compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
boost::future<int> f = compute(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
boost::shared_future<int> f = shared_compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
|
||||
namespace {
|
||||
const int ITERS = 100;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
void use_cerr(boost::externally_locked_stream<std::ostream> &mcerr)
|
||||
{
|
||||
using namespace boost;
|
||||
auto tf = chrono::steady_clock::now() + chrono::seconds(10);
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(10);
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
mcerr << "logging data to cerr\n";
|
||||
@@ -26,7 +26,7 @@ void use_cerr(boost::externally_locked_stream<std::ostream> &mcerr)
|
||||
void use_cout(boost::externally_locked_stream<std::ostream> &mcout)
|
||||
{
|
||||
using namespace boost;
|
||||
auto tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
mcout << "logging data to cout\n";
|
||||
@@ -50,14 +50,14 @@ int main()
|
||||
std::string nm;
|
||||
{
|
||||
strict_lock<recursive_mutex> lk(terminal_mutex);
|
||||
auto& gcout = mcout.hold(lk);
|
||||
auto& gcin = mcin.hold(lk);
|
||||
std::ostream & gcout = mcout.get(lk);
|
||||
//std::istream & gcin = mcin.get(lk);
|
||||
gcout << "Enter name: ";
|
||||
//gcin >> nm;
|
||||
}
|
||||
t1.join();
|
||||
t2.join();
|
||||
mcout << nm << '\n';
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
|
||||
int value=0;
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
boost::once_flag once;
|
||||
static boost::once_flag once;
|
||||
//static boost::once_flag once2 = BOOST_ONCE_INIT;
|
||||
#else
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
boost::once_flag once2 = once;
|
||||
static boost::once_flag once = BOOST_ONCE_INIT;
|
||||
//static boost::once_flag once2 = once;
|
||||
#endif
|
||||
|
||||
void init()
|
||||
|
||||
72
example/perf_shared_mutex.cpp
Normal file
72
example/perf_shared_mutex.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// (C) Copyright 2013 Andrey
|
||||
// (C) Copyright 2013 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_USES_CHRONO
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
shared_mutex mtx;
|
||||
const int cycles = 10000;
|
||||
|
||||
void shared()
|
||||
{
|
||||
int cycle(0);
|
||||
while (++cycle < cycles)
|
||||
{
|
||||
shared_lock<shared_mutex> lock(mtx);
|
||||
}
|
||||
}
|
||||
|
||||
void unique()
|
||||
{
|
||||
int cycle(0);
|
||||
while (++cycle < cycles)
|
||||
{
|
||||
unique_lock<shared_mutex> lock(mtx);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::chrono::high_resolution_clock::duration best_time(std::numeric_limits<boost::chrono::high_resolution_clock::duration::rep>::max());
|
||||
for (int i =100; i>0; --i) {
|
||||
boost::chrono::high_resolution_clock clock;
|
||||
boost::chrono::high_resolution_clock::time_point s1 = clock.now();
|
||||
thread t0(shared);
|
||||
thread t1(shared);
|
||||
thread t2(unique);
|
||||
//thread t11(shared);
|
||||
//thread t12(shared);
|
||||
//thread t13(shared);
|
||||
|
||||
t0.join();
|
||||
t1.join();
|
||||
t2.join();
|
||||
//t11.join();
|
||||
// t12.join();
|
||||
// t13.join();
|
||||
boost::chrono::high_resolution_clock::time_point f1 = clock.now();
|
||||
//std::cout << " Time spent:" << (f1 - s1) << std::endl;
|
||||
best_time = std::min(best_time, f1 - s1);
|
||||
|
||||
}
|
||||
std::cout << "Best Time spent:" << best_time << std::endl;
|
||||
std::cout << "Time spent/cycle:" << best_time/cycles/3 << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
127
example/producer_consumer.cpp
Normal file
127
example/producer_consumer.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// (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>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
|
||||
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
//sbq.push(i);
|
||||
sbq << i;
|
||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
//sbq.pull(r);
|
||||
sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
bool closed=false;
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r, closed);
|
||||
if (closed) break;
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
// try {
|
||||
// for(int i=0; ;++i)
|
||||
// {
|
||||
// int r;
|
||||
// queue_op_status res = sbq.wait_and_pull(r);
|
||||
// if (res==queue_op_status::closed) break;
|
||||
// mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// this_thread::sleep_for(chrono::milliseconds(250));
|
||||
// }
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// mos << "exception !!!\n";
|
||||
// }
|
||||
//}
|
||||
|
||||
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);
|
||||
|
||||
sync_queue<int> sbq;
|
||||
|
||||
{
|
||||
mcout << "begin of main" << std::endl;
|
||||
scoped_thread<> t11(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
mcout << "closed()" << std::endl;
|
||||
sbq.close();
|
||||
mcout << "closed()" << std::endl;
|
||||
|
||||
} // all threads joined here.
|
||||
mcout << "end of main" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
126
example/producer_consumer_bounded.cpp
Normal file
126
example/producer_consumer_bounded.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// (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>
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
|
||||
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
//sbq.push(i);
|
||||
sbq << i;
|
||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
//sbq.pull(r);
|
||||
sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
bool closed=false;
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r, closed);
|
||||
if (closed) break;
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
// try {
|
||||
// for(int i=0; ;++i)
|
||||
// {
|
||||
// int r;
|
||||
// queue_op_status res = sbq.wait_and_pull(r);
|
||||
// if (res==queue_op_status::closed) break;
|
||||
// mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// this_thread::sleep_for(chrono::milliseconds(250));
|
||||
// }
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// mos << "exception !!!\n";
|
||||
// }
|
||||
//}
|
||||
|
||||
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);
|
||||
|
||||
sync_bounded_queue<int> sbq(10);
|
||||
|
||||
{
|
||||
mcout << "begin of main" << std::endl;
|
||||
scoped_thread<> t11(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
sbq.close();
|
||||
mcout << "closed()" << std::endl;
|
||||
|
||||
} // all threads joined here.
|
||||
mcout << "end of main" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,24 @@ int main()
|
||||
// do_something_in_current_thread();
|
||||
// do_something_with_current_thread(boost::thread(g));
|
||||
// }
|
||||
{
|
||||
int some_local_state;
|
||||
boost::scoped_thread<> t( (boost::thread(func(some_local_state))));
|
||||
|
||||
if (t.joinable())
|
||||
t.join();
|
||||
else
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state;
|
||||
boost::thread t(( func(some_local_state) ));
|
||||
boost::scoped_thread<> g( (boost::move(t)) );
|
||||
t.detach();
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#if defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/lock_algorithms.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <vector>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
@@ -255,5 +255,28 @@ int main()
|
||||
lk2->SetName("Javier");
|
||||
lk3->SetName("Matias");
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS \
|
||||
&& ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
|
||||
{
|
||||
Person3_ts p1(1);
|
||||
Person3_ts p2(2);
|
||||
Person3_ts p3(3);
|
||||
|
||||
auto t = boost::synchronize(p1,p2,p3);
|
||||
std::get<0>(t)->SetName("Carmen");
|
||||
std::get<1>(t)->SetName("Javier");
|
||||
std::get<2>(t)->SetName("Matias");
|
||||
}
|
||||
{
|
||||
const Person3_ts p1(1);
|
||||
Person3_ts p2(2);
|
||||
const Person3_ts p3(3);
|
||||
|
||||
auto t = boost::synchronize(p1,p2,p3);
|
||||
//std::get<0>(t)->SetName("Carmen");
|
||||
std::get<1>(t)->SetName("Javier");
|
||||
//std::get<2>(t)->SetName("Matias");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
#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()!='/'))
|
||||
void addTrailingSlashIfMissing(boost::synchronized_value<std::string> & path)
|
||||
{
|
||||
*u+='/';
|
||||
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;
|
||||
@@ -80,6 +80,68 @@ int main()
|
||||
addTrailingSlashIfMissing(s);
|
||||
std::cout<<"s="<<std::string(*s)<<std::endl;
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<std::string> s;
|
||||
s = std::string("foo/");
|
||||
std::cout<<"ss="<< s << std::endl;
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<std::string> s;
|
||||
s = "foo/";
|
||||
std::cout<<"ss="<< s << std::endl;
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<std::string> s1("a");
|
||||
boost::synchronized_value<std::string> s2;
|
||||
s2=s1;
|
||||
std::cout<<"s1="<< s1 << std::endl;
|
||||
std::cout<<"s2="<< s2 << std::endl;
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<std::string> s1("a");
|
||||
boost::synchronized_value<std::string> s2("b");
|
||||
std::cout<<"s1="<< s1 << std::endl;
|
||||
std::cout<<"s2="<< s2 << std::endl;
|
||||
swap(s1,s2);
|
||||
std::cout<<"s1="<< s1 << std::endl;
|
||||
std::cout<<"s2="<< s2 << std::endl;
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
{
|
||||
boost::synchronized_value<std::string> sts("a");
|
||||
std::string s(sts);
|
||||
std::cout<<"ssts="<< s << std::endl;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::synchronized_value<int> s1(1);
|
||||
boost::synchronized_value<int> s2(1);
|
||||
BOOST_ASSERT(s1==s2);
|
||||
BOOST_ASSERT(s1<=s2);
|
||||
BOOST_ASSERT(s1>=s2);
|
||||
BOOST_ASSERT(s1==1);
|
||||
BOOST_ASSERT(s1<=1);
|
||||
BOOST_ASSERT(s1>=1);
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<int> s1(1);
|
||||
boost::synchronized_value<int> s2(2);
|
||||
BOOST_ASSERT(s1!=s2);
|
||||
BOOST_ASSERT(s1!=2);
|
||||
BOOST_ASSERT(2!=s1);
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<int> s1(1);
|
||||
boost::synchronized_value<int> s2(2);
|
||||
BOOST_ASSERT(s1<s2);
|
||||
BOOST_ASSERT(s1<=s2);
|
||||
BOOST_ASSERT(s2>s1);
|
||||
BOOST_ASSERT(s2>=s1);
|
||||
BOOST_ASSERT(s1<2);
|
||||
BOOST_ASSERT(s1<=2);
|
||||
BOOST_ASSERT(s2>1);
|
||||
BOOST_ASSERT(s2>=1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -29,7 +29,7 @@ int state;
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
|
||||
char* player_name(int state)
|
||||
const char* player_name(int state)
|
||||
{
|
||||
if (state == PLAYER_A)
|
||||
return "PLAYER-A";
|
||||
@@ -39,11 +39,10 @@ char* player_name(int state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void player(void* param)
|
||||
void player(int active)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
|
||||
int active = (int)param;
|
||||
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
|
||||
|
||||
while (state < GAME_OVER)
|
||||
@@ -96,12 +95,12 @@ private:
|
||||
void* _param;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
int main()
|
||||
{
|
||||
state = START;
|
||||
|
||||
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
|
||||
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
|
||||
boost::thread thrda(&player, PLAYER_A);
|
||||
boost::thread thrdb(&player, PLAYER_B);
|
||||
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
@@ -112,7 +111,7 @@ int main(int argc, char* argv[])
|
||||
std::cout << "---Noise ON..." << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000000000; ++i)
|
||||
for (int i = 0; i < 10; ++i)
|
||||
cond.notify_all();
|
||||
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define BOOST_THREAD_VERSION 2
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/thread_guard.hpp>
|
||||
|
||||
void do_something(int& i)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define BOOST_THREAD_VERSION 2
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
int main()
|
||||
|
||||
19
include/boost/detail/atomic_redef_macros.hpp
Normal file
19
include/boost/detail/atomic_redef_macros.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
|
||||
#if defined(BOOST_INTEL)
|
||||
|
||||
#pragma pop_macro("atomic_compare_exchange")
|
||||
#pragma pop_macro("atomic_compare_exchange_explicit")
|
||||
#pragma pop_macro("atomic_exchange")
|
||||
#pragma pop_macro("atomic_exchange_explicit")
|
||||
#pragma pop_macro("atomic_is_lock_free")
|
||||
#pragma pop_macro("atomic_load")
|
||||
#pragma pop_macro("atomic_load_explicit")
|
||||
#pragma pop_macro("atomic_store")
|
||||
#pragma pop_macro("atomic_store_explicit")
|
||||
|
||||
#endif // #if defined(BOOST_INTEL)
|
||||
39
include/boost/detail/atomic_undef_macros.hpp
Normal file
39
include/boost/detail/atomic_undef_macros.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
|
||||
#if defined(BOOST_INTEL)
|
||||
|
||||
#pragma push_macro("atomic_compare_exchange")
|
||||
#undef atomic_compare_exchange
|
||||
|
||||
#pragma push_macro("atomic_compare_exchange_explicit")
|
||||
#undef atomic_compare_exchange_explicit
|
||||
|
||||
#pragma push_macro("atomic_exchange")
|
||||
#undef atomic_exchange
|
||||
|
||||
#pragma push_macro("atomic_exchange_explicit")
|
||||
#undef atomic_exchange_explicit
|
||||
|
||||
#pragma push_macro("atomic_is_lock_free")
|
||||
#undef atomic_is_lock_free
|
||||
|
||||
#pragma push_macro("atomic_load")
|
||||
#undef atomic_load
|
||||
|
||||
#pragma push_macro("atomic_load_explicit")
|
||||
#undef atomic_load_explicit
|
||||
|
||||
#pragma push_macro("atomic_store")
|
||||
#undef atomic_store
|
||||
|
||||
#pragma push_macro("atomic_store_explicit")
|
||||
#undef atomic_store_explicit
|
||||
|
||||
|
||||
#endif // #if defined(BOOST_INTEL)
|
||||
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
#define BOOST_BARRIER_JDM030602_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
@@ -25,6 +26,8 @@ namespace boost
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( barrier )
|
||||
|
||||
barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
|
||||
233
include/boost/thread/completion_latch.hpp
Normal file
233
include/boost/thread/completion_latch.hpp
Normal file
@@ -0,0 +1,233 @@
|
||||
// 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 2013 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_COMPLETION_LATCH_HPP
|
||||
#define BOOST_THREAD_COMPLETION_LATCH_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/counter.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <boost/function.hpp>
|
||||
#else
|
||||
#include <functional>
|
||||
#endif
|
||||
//#include <boost/thread/latch.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
void noop()
|
||||
{
|
||||
}
|
||||
}
|
||||
class completion_latch
|
||||
{
|
||||
public:
|
||||
/// the implementation defined completion function type
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef function<void()> completion_function;
|
||||
#else
|
||||
typedef std::function<void()> completion_function;
|
||||
#endif
|
||||
/// noop completion function factory
|
||||
static completion_function noop()
|
||||
{
|
||||
return completion_function(&thread_detail::noop);
|
||||
}
|
||||
|
||||
private:
|
||||
struct around_wait;
|
||||
friend struct around_wait;
|
||||
struct around_wait
|
||||
{
|
||||
completion_latch &that_;
|
||||
boost::unique_lock<boost::mutex> &lk_;
|
||||
around_wait(completion_latch &that, boost::unique_lock<boost::mutex> &lk)
|
||||
: that_(that), lk_(lk)
|
||||
{
|
||||
that_.leavers_.cond_.wait(lk, detail::counter_is_zero(that_.leavers_));
|
||||
that_.waiters_.inc_and_notify_all();
|
||||
that_.leavers_.cond_.wait(lk, detail::counter_is_not_zero(that_.leavers_));
|
||||
}
|
||||
~around_wait()
|
||||
{
|
||||
that_.waiters_.dec_and_notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
bool count_down(unique_lock<mutex> &lk)
|
||||
{
|
||||
BOOST_ASSERT(count_ > 0);
|
||||
if (--count_ == 0)
|
||||
{
|
||||
waiters_.cond_.wait(lk, detail::counter_is_not_zero(waiters_));
|
||||
leavers_.assign_and_notify_all(waiters_);
|
||||
count_.cond_.notify_all();
|
||||
waiters_.cond_.wait(lk, detail::counter_is_zero(waiters_));
|
||||
leavers_.assign_and_notify_all(0);
|
||||
lk.unlock();
|
||||
funct_();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( completion_latch )
|
||||
|
||||
/// Constructs a latch with a given count.
|
||||
completion_latch(std::size_t count) :
|
||||
count_(count), funct_(noop()), waiters_(0), leavers_(0)
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructs a latch with a given count and a completion function.
|
||||
template <typename F>
|
||||
completion_latch(std::size_t count, BOOST_THREAD_RV_REF(F) funct) :
|
||||
count_(count),
|
||||
funct_(boost::move(funct)),
|
||||
waiters_(0),
|
||||
leavers_(0)
|
||||
{
|
||||
}
|
||||
template <typename F>
|
||||
completion_latch(std::size_t count, void(*funct)()) :
|
||||
count_(count), funct_(funct), waiters_(0), leavers_(0)
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
~completion_latch()
|
||||
{
|
||||
}
|
||||
|
||||
/// Blocks until the latch has counted down to zero.
|
||||
void wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
around_wait aw(*this, lk);
|
||||
count_.cond_.wait(lk, detail::counter_is_zero(count_));
|
||||
}
|
||||
|
||||
/// @return true if the internal counter is already 0, false otherwise
|
||||
bool try_wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
around_wait aw(*this, lk);
|
||||
return (count_ == 0);
|
||||
}
|
||||
|
||||
/// try to wait for a specified amount of time
|
||||
/// @return whether there is a timeout or not.
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
around_wait aw(*this, lk);
|
||||
return count_.cond_.wait_for(lk, rel_time, detail::counter_is_zero(count_))
|
||||
? cv_status::no_timeout
|
||||
: cv_status::timeout;
|
||||
}
|
||||
|
||||
/// try to wait until the specified time_point is reached
|
||||
/// @return whether there is a timeout or not.
|
||||
template <class Clock, class Duration>
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
around_wait aw(*this, lk);
|
||||
return count_.cond_.wait_until(lk, abs_time, detail::counter_is_zero(count_))
|
||||
? cv_status::no_timeout
|
||||
: cv_status::timeout;
|
||||
}
|
||||
|
||||
/// Decrement the count and notify anyone waiting if we reach zero.
|
||||
/// @Requires count must be greater than 0
|
||||
void count_down()
|
||||
{
|
||||
unique_lock<mutex> lk(mutex_);
|
||||
count_down(lk);
|
||||
}
|
||||
void signal()
|
||||
{
|
||||
count_down();
|
||||
}
|
||||
|
||||
/// Decrement the count and notify anyone waiting if we reach zero.
|
||||
/// Blocks until the latch has counted down to zero.
|
||||
/// @Requires count must be greater than 0
|
||||
void count_down_and_wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
if (count_down(lk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
around_wait aw(*this, lk);
|
||||
count_.cond_.wait(lk, detail::counter_is_zero(count_));
|
||||
}
|
||||
void sync()
|
||||
{
|
||||
count_down_and_wait();
|
||||
}
|
||||
|
||||
/// Reset the counter
|
||||
/// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
|
||||
void reset(std::size_t count)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lk(mutex_);
|
||||
//BOOST_ASSERT(count_ == 0);
|
||||
count_ = count;
|
||||
}
|
||||
|
||||
/// Resets the latch with the new completion function.
|
||||
/// The next time the internal count reaches 0, this function will be invoked.
|
||||
/// This completion function may only be invoked when there are no other threads
|
||||
/// currently inside the count_down and wait related functions.
|
||||
/// It may also be invoked from within the registered completion function.
|
||||
/// @Returns the old completion function if any or noop if
|
||||
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
template <typename F>
|
||||
completion_function then(BOOST_THREAD_RV_REF(F) funct)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lk(mutex_);
|
||||
completion_function tmp(funct_);
|
||||
funct_ = boost::move(funct);
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
completion_function then(void(*funct)())
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lk(mutex_);
|
||||
completion_function tmp(funct_);
|
||||
funct_ = completion_function(funct);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex mutex_;
|
||||
detail::counter count_;
|
||||
completion_function funct_;
|
||||
detail::counter waiters_;
|
||||
detail::counter leavers_;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,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)
|
||||
|
||||
// 2013/04 Vicente J. Botet Escriba
|
||||
// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined.
|
||||
// Make use of Boost.Move
|
||||
// Make use of Boost.Tuple (movable)
|
||||
// 2012/11 Vicente J. Botet Escriba
|
||||
// Adapt to boost libc++ implementation
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
@@ -23,8 +30,11 @@
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#include <tuple>
|
||||
#else
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
@@ -33,68 +43,528 @@ namespace boost
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
template <class Fp, class... Args>
|
||||
template <class Fp, class ... Args>
|
||||
class async_func
|
||||
{
|
||||
std::tuple<Fp, Args...> f_;
|
||||
std::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
|
||||
typedef typename result_of<Fp(Args...)>::type result_type;
|
||||
BOOST_THREAD_MOVABLE_ONLY( async_func)
|
||||
//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
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args)... args)
|
||||
: f_(boost::move(f), boost::move(args)...)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(async_func&& f) : f_(boost::move(f.f_)) {}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(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());
|
||||
}
|
||||
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_))...);
|
||||
}
|
||||
template <size_t ...Indices>
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke(boost::move(std::get<0>(f_)), boost::move(std::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) async_func<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
#else
|
||||
template <class Fp>
|
||||
class async_func
|
||||
template <class Fp,
|
||||
class T0 = tuples::null_type, class T1 = tuples::null_type, class T2 = tuples::null_type,
|
||||
class T3 = tuples::null_type, class T4 = tuples::null_type, class T5 = tuples::null_type,
|
||||
class T6 = tuples::null_type, class T7 = tuples::null_type, class T8 = tuples::null_type
|
||||
, class T9 = tuples::null_type
|
||||
>
|
||||
class async_func;
|
||||
|
||||
template <class Fp,
|
||||
class T0 , class T1 , class T2 ,
|
||||
class T3 , class T4 , class T5 ,
|
||||
class T6 , class T7 , class T8 >
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
{
|
||||
Fp f_;
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
T8 v8_;
|
||||
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type;
|
||||
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
, BOOST_THREAD_RV_REF(T7) a7
|
||||
, BOOST_THREAD_RV_REF(T8) a8
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
, v7_(boost::move(a7))
|
||||
, v8_(boost::move(a8))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
: f_(boost::move(f)) {}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
, v7_(boost::move(f.a7))
|
||||
, v8_(boost::move(f.a8))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_FWD_REF(async_func) f) : f_(boost::move(f.f_)) {}
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
, boost::move(v7_)
|
||||
, boost::move(v8_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type;
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return execute();
|
||||
}
|
||||
private:
|
||||
result_type
|
||||
execute()
|
||||
{
|
||||
return f_();
|
||||
}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
, BOOST_THREAD_RV_REF(T7) a7
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
, v7_(boost::move(a7))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
, v7_(boost::move(f.a7))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
, boost::move(v7_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3>
|
||||
class async_func<Fp, T0, T1, T2, T3>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2>
|
||||
class async_func<Fp, T0, T1, T2>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1>
|
||||
class async_func<Fp, T0, T1>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0>
|
||||
class async_func<Fp, T0>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp>
|
||||
class async_func<Fp>
|
||||
{
|
||||
Fp fp_;
|
||||
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)
|
||||
: fp_(boost::move(f))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_FWD_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp_))
|
||||
{}
|
||||
result_type operator()()
|
||||
{
|
||||
return fp_();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2011-2012 Vicente J. Botet Escriba
|
||||
// Copyright (C) 2011-2013 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)
|
||||
@@ -8,23 +8,26 @@
|
||||
#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()
|
||||
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
// ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 302 \
|
||||
&& !defined(__INTEL_COMPILER)
|
||||
|
||||
// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with
|
||||
// regard to violation of the strict aliasing rules.
|
||||
|
||||
#define BOOST_THREAD_DETAIL_USE_ATTRIBUTE_MAY_ALIAS
|
||||
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS __attribute__((__may_alias__))
|
||||
#else
|
||||
# define BOOST_THREAD_NOEXCEPT_OR_THROW noexcept
|
||||
#endif
|
||||
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
|
||||
#endif
|
||||
|
||||
|
||||
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \
|
||||
if (EXPR) {} else boost::throw_exception(EX)
|
||||
@@ -44,8 +47,8 @@
|
||||
#if defined __IBMCPP__ && (__IBMCPP__ < 1100) \
|
||||
&& ! defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#define BOOST_THREAD_DONT_USE_CHRONO
|
||||
#if ! defined BOOST_THREAD_USE_DATE
|
||||
#define BOOST_THREAD_USE_DATE
|
||||
#if ! defined BOOST_THREAD_USES_DATETIME
|
||||
#define BOOST_THREAD_USES_DATETIME
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -76,22 +79,23 @@
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS
|
||||
#define BOOST_THREAD_NO_SYNCHRONIZE
|
||||
#elif defined _MSC_VER && _MSC_VER <= 1600
|
||||
// C++ features supported by VC++ 10 (aka 2010)
|
||||
#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS
|
||||
#define BOOST_THREAD_NO_SYNCHRONIZE
|
||||
#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
|
||||
#define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#endif
|
||||
|
||||
/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
|
||||
//#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
|
||||
#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
// Default version
|
||||
#if !defined BOOST_THREAD_VERSION
|
||||
@@ -109,6 +113,20 @@
|
||||
#define BOOST_THREAD_USES_CHRONO
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_DONT_USE_ATOMIC \
|
||||
&& ! defined BOOST_THREAD_USES_ATOMIC
|
||||
#define BOOST_THREAD_USES_ATOMIC
|
||||
//#define BOOST_THREAD_DONT_USE_ATOMIC
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_ATOMIC
|
||||
// Andrey Semashev
|
||||
#define BOOST_THREAD_ONCE_ATOMIC
|
||||
#else
|
||||
//#elif ! defined BOOST_NO_CXX11_THREAD_LOCAL && ! defined BOOST_NO_THREAD_LOCAL && ! defined BOOST_THREAD_NO_UINT32_PSEUDO_ATOMIC
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html#Appendix
|
||||
#define BOOST_THREAD_ONCE_FAST_EPOCH
|
||||
#endif
|
||||
#if BOOST_THREAD_VERSION==2
|
||||
|
||||
// PROVIDE_PROMISE_LAZY
|
||||
@@ -230,6 +248,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// MAKE_READY_AT_THREAD_EXIT
|
||||
#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_MAKE_READY_AT_THREAD_EXIT
|
||||
|
||||
//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#define BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
// FUTURE_CONTINUATION
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION
|
||||
@@ -277,7 +305,20 @@
|
||||
#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
|
||||
// For C++11 call_once interface the compiler MUST support constexpr.
|
||||
// Otherwise once_flag would be initialized during dynamic initialization stage, which is not thread-safe.
|
||||
#if defined(BOOST_THREAD_PROVIDES_ONCE_CXX11)
|
||||
#if defined(BOOST_NO_CXX11_CONSTEXPR)
|
||||
#undef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_DATETIME
|
||||
#undef BOOST_THREAD_DONT_USE_DATETIME
|
||||
#define BOOST_THREAD_USES_DATETIME
|
||||
#endif
|
||||
|
||||
// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
|
||||
// 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
|
||||
|
||||
@@ -321,8 +362,9 @@
|
||||
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
#else //Use default
|
||||
# if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
|
||||
//For compilers supporting auto-tss cleanup
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) \
|
||||
|| defined(__MINGW32__) || defined(MINGW32) || defined(BOOST_MINGW32)
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# else
|
||||
|
||||
93
include/boost/thread/detail/counter.hpp
Normal file
93
include/boost/thread/detail/counter.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// 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 2013 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_COUNTER_HPP
|
||||
#define BOOST_THREAD_COUNTER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
//#include <boost/thread/mutex.hpp>
|
||||
//#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail {
|
||||
struct counter
|
||||
{
|
||||
condition_variable cond_;
|
||||
std::size_t value_;
|
||||
|
||||
counter(std::size_t value)
|
||||
: value_(value)
|
||||
{
|
||||
|
||||
}
|
||||
counter& operator=(counter const& rhs)
|
||||
{
|
||||
value_ = rhs.value_;
|
||||
return *this;
|
||||
}
|
||||
counter& operator=(std::size_t value)
|
||||
{
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator std::size_t() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
operator std::size_t&()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
void inc_and_notify_all()
|
||||
{
|
||||
++value_;
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
||||
void dec_and_notify_all()
|
||||
{
|
||||
--value_;
|
||||
cond_.notify_all();
|
||||
}
|
||||
void assign_and_notify_all(counter const& rhs)
|
||||
{
|
||||
value_ = rhs.value_;
|
||||
cond_.notify_all();
|
||||
}
|
||||
void assign_and_notify_all(std::size_t value)
|
||||
{
|
||||
value_ = value;
|
||||
cond_.notify_all();
|
||||
}
|
||||
};
|
||||
struct counter_is_not_zero
|
||||
{
|
||||
counter_is_not_zero(const counter& count) : count_(count) {}
|
||||
bool operator()() const { return count_ != 0; }
|
||||
const counter& count_;
|
||||
};
|
||||
struct counter_is_zero
|
||||
{
|
||||
counter_is_zero(const counter& count) : count_(count) {}
|
||||
bool operator()() const { return count_ == 0; }
|
||||
const counter& count_;
|
||||
};
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,13 @@
|
||||
// Copyright (C) 2012 Vicente J. Botet Escriba
|
||||
// Copyright (C) 2012-2013 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)
|
||||
|
||||
// 2013/04 Vicente J. Botet Escriba
|
||||
// Provide implementation up to 10 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined.
|
||||
// 2012/11 Vicente J. Botet Escriba
|
||||
// Adapt to boost libc++ implementation
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
@@ -10,7 +15,7 @@
|
||||
// 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.
|
||||
// The make_tuple_indices C++11 code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP
|
||||
@@ -24,9 +29,7 @@ namespace boost
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
// make_tuple_indices
|
||||
|
||||
template <std::size_t...> struct tuple_indices
|
||||
@@ -53,6 +56,167 @@ namespace boost
|
||||
BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error");
|
||||
typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
|
||||
};
|
||||
#else
|
||||
|
||||
// - tuple forward declaration -----------------------------------------------
|
||||
template <
|
||||
std::size_t T0 = 0, std::size_t T1 = 0, std::size_t T2 = 0,
|
||||
std::size_t T3 = 0, std::size_t T4 = 0, std::size_t T5 = 0,
|
||||
std::size_t T6 = 0, std::size_t T7 = 0, std::size_t T8 = 0,
|
||||
std::size_t T9 = 0>
|
||||
class 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 Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
, std::size_t I7
|
||||
, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, Sp>, Ep>::type type;
|
||||
};
|
||||
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
, std::size_t I7
|
||||
, std::size_t I8
|
||||
, std::size_t Ep>
|
||||
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7, I8>, Ep>
|
||||
{
|
||||
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, Sp>, Ep>::type type;
|
||||
};
|
||||
// template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
// , std::size_t I6
|
||||
// , std::size_t I7
|
||||
// , std::size_t I8
|
||||
// , std::size_t I9
|
||||
// , std::size_t Ep>
|
||||
// struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7, I8, I9>, Ep>
|
||||
// {
|
||||
// typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, Sp>, Ep>::type type;
|
||||
// };
|
||||
|
||||
template <std::size_t Ep>
|
||||
struct make_indices_imp<Ep, tuple_indices<>, Ep>
|
||||
{
|
||||
typedef tuple_indices<> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3, I4> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3, I4, I5> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
, std::size_t I7
|
||||
>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7> type;
|
||||
};
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
, std::size_t I7
|
||||
, std::size_t I8
|
||||
>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8> type;
|
||||
};
|
||||
|
||||
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
|
||||
, std::size_t I6
|
||||
, std::size_t I7
|
||||
, std::size_t I8
|
||||
, std::size_t I9
|
||||
>
|
||||
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9>, Ep>
|
||||
{
|
||||
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9> 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/move/utility.hpp>
|
||||
#include <boost/move/traits.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
|
||||
@@ -476,8 +476,13 @@ namespace boost
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_join_until(s_now + ceil<nanoseconds>(t - c_now));
|
||||
bool joined= false;
|
||||
do {
|
||||
typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
|
||||
if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
|
||||
joined = try_join_until(s_now + d);
|
||||
} while (! joined);
|
||||
return true;
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace boost
|
||||
|
||||
//[externally_locked
|
||||
template <typename T, typename MutexType = boost::mutex>
|
||||
class externally_locked;
|
||||
template <typename T, typename MutexType>
|
||||
class externally_locked
|
||||
{
|
||||
//BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
|
||||
@@ -46,7 +48,7 @@ namespace boost
|
||||
* 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) :
|
||||
externally_locked(mutex_type& mtx, const T& obj) :
|
||||
obj_(obj), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
@@ -55,7 +57,7 @@ namespace boost
|
||||
* 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) :
|
||||
externally_locked(mutex_type& mtx, BOOST_THREAD_RV_REF(T) obj) :
|
||||
obj_(move(obj)), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
@@ -64,18 +66,46 @@ namespace boost
|
||||
* 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)
|
||||
externally_locked(mutex_type& mtx) // BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T()))
|
||||
: obj_(), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*/
|
||||
externally_locked(externally_locked const& rhs) //BOOST_NOEXCEPT
|
||||
: obj_(rhs.obj_), mtx_(rhs.mtx_)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Move constructor
|
||||
*/
|
||||
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) :
|
||||
obj_(move(rhs.obj_)), mtx_(rhs.mtx_)
|
||||
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) //BOOST_NOEXCEPT
|
||||
: obj_(move(rhs.obj_)), mtx_(rhs.mtx_)
|
||||
{
|
||||
rhs.mtx_=0;
|
||||
}
|
||||
|
||||
/// assignment
|
||||
externally_locked& operator=(externally_locked const& rhs) //BOOST_NOEXCEPT
|
||||
{
|
||||
obj_=rhs.obj_;
|
||||
mtx_=rhs.mtx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// move assignment
|
||||
externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) // BOOST_NOEXCEPT
|
||||
{
|
||||
obj_=move(rhs.obj_);
|
||||
mtx_=rhs.mtx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(externally_locked& rhs) //BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR)
|
||||
{
|
||||
swap(obj_, rhs.obj_);
|
||||
swap(mtx_, rhs.mtx_);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,13 +156,12 @@ namespace boost
|
||||
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()
|
||||
mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return mtx_;
|
||||
}
|
||||
@@ -175,25 +204,45 @@ namespace boost
|
||||
public:
|
||||
typedef MutexType mutex_type;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY( externally_locked )
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked )
|
||||
|
||||
/**
|
||||
* Effects: Constructs an externally locked object storing the cloaked reference object.
|
||||
*/
|
||||
externally_locked(T& obj, mutex_type& mtx) :
|
||||
externally_locked(T& obj, mutex_type& mtx) BOOST_NOEXCEPT :
|
||||
obj_(&obj), mtx_(&mtx)
|
||||
{
|
||||
}
|
||||
|
||||
/// move constructor
|
||||
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) :
|
||||
/// copy constructor
|
||||
externally_locked(externally_locked const& rhs) BOOST_NOEXCEPT :
|
||||
obj_(rhs.obj_), mtx_(rhs.mtx_)
|
||||
{
|
||||
rhs.obj_=0;
|
||||
rhs.mtx_=0;
|
||||
}
|
||||
|
||||
void swap(externally_locked& rhs)
|
||||
/// move constructor
|
||||
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT :
|
||||
obj_(rhs.obj_), mtx_(rhs.mtx_)
|
||||
{
|
||||
}
|
||||
|
||||
/// assignment
|
||||
externally_locked& operator=(externally_locked const& rhs) BOOST_NOEXCEPT
|
||||
{
|
||||
obj_=rhs.obj_;
|
||||
mtx_=rhs.mtx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// move assignment
|
||||
externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT
|
||||
{
|
||||
obj_=rhs.obj_;
|
||||
mtx_=rhs.mtx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(externally_locked& rhs) BOOST_NOEXCEPT
|
||||
{
|
||||
swap(obj_, rhs.obj_);
|
||||
swap(mtx_, rhs.mtx_);
|
||||
@@ -245,7 +294,6 @@ namespace boost
|
||||
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_;
|
||||
}
|
||||
@@ -262,11 +310,10 @@ namespace boost
|
||||
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()
|
||||
mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return mtx_;
|
||||
}
|
||||
@@ -292,7 +339,7 @@ namespace boost
|
||||
//]
|
||||
|
||||
template <typename T, typename MutexType>
|
||||
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs)
|
||||
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs) // BOOST_NOEXCEPT
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
@@ -21,12 +21,6 @@
|
||||
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;
|
||||
|
||||
@@ -51,7 +45,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
stream_guard(BOOST_THREAD_RV_REF(stream_guard) rhs)
|
||||
stream_guard(BOOST_THREAD_RV_REF(stream_guard) rhs) BOOST_NOEXCEPT
|
||||
: mtx_(rhs.mtx_)
|
||||
{
|
||||
rhs.mtx_= 0;
|
||||
@@ -62,15 +56,24 @@ namespace boost
|
||||
if (mtx_ != 0) mtx_->unlock();
|
||||
}
|
||||
|
||||
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT
|
||||
bool owns_lock(const mutex_type * l) const BOOST_NOEXCEPT
|
||||
{
|
||||
return l == mtx_->mutex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Requires mtx_
|
||||
*/
|
||||
Stream& get() const
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( mtx_, lock_error() );
|
||||
return mtx_->get(*this);
|
||||
}
|
||||
Stream& bypass() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
externally_locked_stream<Stream, RecursiveMutex>* mtx_;
|
||||
@@ -98,22 +101,20 @@ namespace boost
|
||||
/**
|
||||
* Effects: Constructs an externally locked object storing the cloaked reference object.
|
||||
*/
|
||||
externally_locked_stream(Stream& stream, RecursiveMutex& mtx) :
|
||||
externally_locked_stream(Stream& stream, RecursiveMutex& mtx) BOOST_NOEXCEPT :
|
||||
base_type(stream, mtx)
|
||||
{
|
||||
}
|
||||
|
||||
stream_guard<Stream, RecursiveMutex> hold()
|
||||
stream_guard<Stream, RecursiveMutex> hold() BOOST_NOEXCEPT
|
||||
{
|
||||
return stream_guard<Stream, RecursiveMutex> (*this);
|
||||
}
|
||||
|
||||
Stream& hold(strict_lock<RecursiveMutex>& lk)
|
||||
Stream& bypass() const
|
||||
{
|
||||
return this->get(lk);
|
||||
stream_guard<Stream, RecursiveMutex> lk(*this);
|
||||
return get(lk);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
//]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ namespace boost
|
||||
template <typename Lockable>
|
||||
bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
|
||||
{
|
||||
return mtx.is_locked();
|
||||
return mtx.is_locked_by_this_thread();
|
||||
}
|
||||
template <typename Lockable>
|
||||
bool is_locked_by_this_thread(Lockable const&)
|
||||
|
||||
142
include/boost/thread/latch.hpp
Normal file
142
include/boost/thread/latch.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// 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 2013 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_LATCH_HPP
|
||||
#define BOOST_THREAD_LATCH_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/counter.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class latch
|
||||
{
|
||||
/// @Requires: count_.value_ must be greater than 0
|
||||
/// Effect: Decrement the count. Unlocks the lock notify anyone waiting if we reached zero.
|
||||
/// Returns: true if count_.value_ reached the value 0.
|
||||
/// @ThreadSafe ensured by the @c lk parameter
|
||||
bool count_down(unique_lock<mutex> &lk)
|
||||
/// pre_condition (count_.value_ > 0)
|
||||
{
|
||||
BOOST_ASSERT(count_.value_ > 0);
|
||||
if (--count_.value_ == 0)
|
||||
{
|
||||
count_.cond_.notify_all();
|
||||
lk.unlock();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( latch)
|
||||
|
||||
/// Constructs a latch with a given count.
|
||||
latch(std::size_t count) :
|
||||
count_(count)
|
||||
{
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
/// Precondition: No threads are waiting or invoking count_down on @c *this.
|
||||
|
||||
~latch()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// Blocks until the latch has counted down to zero.
|
||||
void wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
count_.cond_.wait(lk, detail::counter_is_zero(count_));
|
||||
}
|
||||
|
||||
/// @return true if the internal counter is already 0, false otherwise
|
||||
bool try_wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
return (count_ == 0);
|
||||
}
|
||||
|
||||
/// try to wait for a specified amount of time is elapsed.
|
||||
/// @return whether there is a timeout or not.
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
return count_.cond_.wait_for(lk, rel_time, detail::counter_is_zero(count_))
|
||||
? cv_status::no_timeout
|
||||
: cv_status::timeout;
|
||||
}
|
||||
|
||||
/// try to wait until the specified time_point is reached
|
||||
/// @return whether there were a timeout or not.
|
||||
template <class Clock, class Duration>
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
return count_.cond_.wait_until(lk, abs_time, detail::counter_is_zero(count_))
|
||||
? cv_status::no_timeout
|
||||
: cv_status::timeout;
|
||||
}
|
||||
|
||||
/// Decrement the count and notify anyone waiting if we reach zero.
|
||||
/// @Requires count must be greater than 0
|
||||
void count_down()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
count_down(lk);
|
||||
}
|
||||
void signal()
|
||||
{
|
||||
count_down();
|
||||
}
|
||||
|
||||
/// Decrement the count and notify anyone waiting if we reach zero.
|
||||
/// Blocks until the latch has counted down to zero.
|
||||
/// @Requires count must be greater than 0
|
||||
void count_down_and_wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
if (count_down(lk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
count_.cond_.wait(lk, detail::counter_is_zero(count_));
|
||||
}
|
||||
void sync()
|
||||
{
|
||||
count_down_and_wait();
|
||||
}
|
||||
|
||||
/// Reset the counter
|
||||
/// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
|
||||
void reset(std::size_t count)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lk(mutex_);
|
||||
//BOOST_ASSERT(count_ == 0);
|
||||
count_ = count;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex mutex_;
|
||||
detail::counter count_;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -30,7 +30,7 @@ namespace boost
|
||||
struct BasicLock
|
||||
{
|
||||
typedef typename Lk::mutex_type mutex_type;
|
||||
void cvt_mutex_ptr(mutex_type*);
|
||||
void cvt_mutex_ptr(mutex_type*) {}
|
||||
BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> ));
|
||||
|
||||
BOOST_CONCEPT_USAGE(BasicLock)
|
||||
|
||||
@@ -174,7 +174,8 @@ namespace boost
|
||||
BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other);
|
||||
|
||||
#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT
|
||||
//std-2104 unique_lock move-assignment should not be noexcept
|
||||
unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
|
||||
{
|
||||
unique_lock temp(::boost::move(other));
|
||||
swap(temp);
|
||||
@@ -182,7 +183,8 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT
|
||||
//std-2104 unique_lock move-assignment should not be noexcept
|
||||
unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) //BOOST_NOEXCEPT
|
||||
{
|
||||
unique_lock temp(::boost::move(other));
|
||||
swap(temp);
|
||||
@@ -581,7 +583,8 @@ namespace boost
|
||||
BOOST_THREAD_RV(other).m=0;
|
||||
}
|
||||
|
||||
shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT
|
||||
//std-2104 unique_lock move-assignment should not be noexcept
|
||||
shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
|
||||
{
|
||||
shared_lock temp(::boost::move(other));
|
||||
swap(temp);
|
||||
@@ -826,7 +829,8 @@ namespace boost
|
||||
BOOST_THREAD_RV(other).m=0;
|
||||
}
|
||||
|
||||
upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT
|
||||
//std-2104 unique_lock move-assignment should not be noexcept
|
||||
upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
|
||||
{
|
||||
upgrade_lock temp(::boost::move(other));
|
||||
swap(temp);
|
||||
@@ -1073,7 +1077,8 @@ namespace boost
|
||||
BOOST_THREAD_RV(other).source=0;
|
||||
}
|
||||
|
||||
upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT
|
||||
//std-2104 unique_lock move-assignment should not be noexcept
|
||||
upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT
|
||||
{
|
||||
upgrade_to_unique_lock temp(other);
|
||||
swap(temp);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#ifndef BOOST_THREAD_NULL_MUTEX_HPP
|
||||
#define BOOST_THREAD_NULL_MUTEX_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/chrono/chrono.hpp>
|
||||
|
||||
@@ -28,6 +29,8 @@ namespace boost
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( null_mutex) /*< no copyable >*/
|
||||
|
||||
null_mutex() {}
|
||||
|
||||
/// Simulates a mutex lock() operation. Empty function.
|
||||
void lock()
|
||||
{
|
||||
|
||||
@@ -9,11 +9,18 @@
|
||||
// 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/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/once.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#if defined BOOST_THREAD_ONCE_FAST_EPOCH
|
||||
#include <boost/thread/pthread/once.hpp>
|
||||
#elif defined BOOST_THREAD_ONCE_ATOMIC
|
||||
#include <boost/thread/pthread/once_atomic.hpp>
|
||||
#else
|
||||
#error "Once Not Implemented"
|
||||
#endif
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
@@ -24,7 +31,9 @@ namespace boost
|
||||
{
|
||||
// template<class Callable, class ...Args> void
|
||||
// call_once(once_flag& flag, Callable&& func, Args&&... args);
|
||||
inline void call_once(void (*func)(),once_flag& flag)
|
||||
template<typename Function>
|
||||
inline void call_once(Function func,once_flag& flag)
|
||||
//inline void call_once(void (*func)(),once_flag& flag)
|
||||
{
|
||||
call_once(flag,func);
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L
|
||||
#if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
|
||||
@@ -11,11 +11,14 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.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/bind.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -26,21 +29,32 @@
|
||||
namespace boost
|
||||
{
|
||||
|
||||
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
|
||||
struct once_flag;
|
||||
|
||||
#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
|
||||
typedef boost::uint32_t uintmax_atomic_t;
|
||||
#define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##u
|
||||
#define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0)
|
||||
//#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
|
||||
#else
|
||||
template<typename Function>
|
||||
inline void call_once(once_flag& flag, Function f);
|
||||
template<typename Function, typename T1>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1);
|
||||
template<typename Function, typename T1, typename T2>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
|
||||
#endif
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
@@ -50,11 +64,26 @@ namespace boost
|
||||
{}
|
||||
private:
|
||||
volatile thread_detail::uintmax_atomic_t epoch;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template<typename Function, class ...ArgTypes>
|
||||
friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
|
||||
#else
|
||||
template<typename Function>
|
||||
friend
|
||||
void call_once(once_flag& flag,Function f);
|
||||
friend void call_once(once_flag& flag, Function f);
|
||||
template<typename Function, typename T1>
|
||||
friend void call_once(once_flag& flag, Function f, T1 p1);
|
||||
template<typename Function, typename T1, typename T2>
|
||||
friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT once_flag()
|
||||
|
||||
#else // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
@@ -65,59 +94,445 @@ namespace boost
|
||||
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
|
||||
#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
namespace detail
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INVOKE
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID_CALL
|
||||
#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID_CALL
|
||||
#else
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID boost::bind
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
|
||||
#endif
|
||||
|
||||
namespace thread_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 uintmax_atomic_t& get_once_per_thread_epoch();
|
||||
BOOST_THREAD_DECL extern uintmax_atomic_t once_global_epoch;
|
||||
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
|
||||
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
|
||||
}
|
||||
|
||||
// Based on Mike Burrows fast_pthread_once algorithm as described in
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
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();
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
|
||||
f();
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
else
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
|
||||
}
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
this_thread_epoch=detail::once_global_epoch;
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename Function>
|
||||
inline 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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
f();
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
f();
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p1))
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p1)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p2))
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
|
||||
{
|
||||
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=thread_detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
BOOST_TRY
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex);
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p1)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p2)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p3))
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
flag.epoch=--thread_detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=thread_detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
313
include/boost/thread/pthread/once_atomic.hpp
Normal file
313
include/boost/thread/pthread/once_atomic.hpp
Normal file
@@ -0,0 +1,313 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
|
||||
#define BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2013 Andrey Semashev
|
||||
// (C) Copyright 2013 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)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
struct once_flag;
|
||||
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
#if BOOST_ATOMIC_INT_LOCK_FREE == 2
|
||||
typedef unsigned int atomic_int_type;
|
||||
#elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2
|
||||
typedef unsigned short atomic_int_type;
|
||||
#elif BOOST_ATOMIC_CHAR_LOCK_FREE == 2
|
||||
typedef unsigned char atomic_int_type;
|
||||
#elif BOOST_ATOMIC_LONG_LOCK_FREE == 2
|
||||
typedef unsigned long atomic_int_type;
|
||||
#elif defined(BOOST_HAS_LONG_LONG) && BOOST_ATOMIC_LLONG_LOCK_FREE == 2
|
||||
typedef ulong_long_type atomic_int_type;
|
||||
#else
|
||||
// All tested integer types are not atomic, the spinlock pool will be used
|
||||
typedef unsigned int atomic_int_type;
|
||||
#endif
|
||||
|
||||
typedef boost::atomic<atomic_int_type> atomic_type;
|
||||
|
||||
BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
|
||||
BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
|
||||
BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
|
||||
inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT;
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
BOOST_THREAD_NO_COPYABLE(once_flag)
|
||||
BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : storage(0)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
thread_detail::atomic_type storage;
|
||||
|
||||
friend BOOST_THREAD_DECL bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
|
||||
friend BOOST_THREAD_DECL void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
|
||||
friend BOOST_THREAD_DECL void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
|
||||
friend thread_detail::atomic_type& thread_detail::get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT;
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT boost::once_flag()
|
||||
|
||||
namespace thread_detail
|
||||
{
|
||||
inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
//return reinterpret_cast< atomic_type& >(flag.storage);
|
||||
return flag.storage;
|
||||
}
|
||||
}
|
||||
|
||||
#else // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
struct once_flag
|
||||
{
|
||||
// The thread_detail::atomic_int_type storage is marked
|
||||
// with this attribute in order to let the compiler know that it will alias this member
|
||||
// and silence compilation warnings.
|
||||
BOOST_THREAD_ATTRIBUTE_MAY_ALIAS thread_detail::atomic_int_type storage;
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT {0}
|
||||
|
||||
namespace thread_detail
|
||||
{
|
||||
inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
return reinterpret_cast< atomic_type& >(flag.storage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INVOKE
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID_CALL
|
||||
#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID_CALL
|
||||
#else
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID boost::bind
|
||||
#define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename Function>
|
||||
inline void call_once(once_flag& flag, Function f)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
f();
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(f, p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1, typename T2>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
f();
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function, typename T1>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p1))
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p1)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p2))
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
|
||||
{
|
||||
if (thread_detail::enter_once_region(flag))
|
||||
{
|
||||
BOOST_TRY
|
||||
{
|
||||
BOOST_THREAD_INVOKE_RET_VOID(
|
||||
thread_detail::decay_copy(boost::forward<Function>(f)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p1)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p2)),
|
||||
thread_detail::decay_copy(boost::forward<T1>(p3))
|
||||
) BOOST_THREAD_INVOKE_RET_VOID_CALL;
|
||||
|
||||
}
|
||||
BOOST_CATCH (...)
|
||||
{
|
||||
thread_detail::rollback_once_region(flag);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
thread_detail::commit_once_region(flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,10 +28,13 @@
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK)
|
||||
#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -28,8 +29,125 @@ namespace boost
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
class state_data
|
||||
{
|
||||
public:
|
||||
state_data () :
|
||||
shared_count(0),
|
||||
exclusive(false),
|
||||
upgrade(false),
|
||||
exclusive_waiting_blocked(false)
|
||||
{}
|
||||
|
||||
void assert_free() const
|
||||
{
|
||||
BOOST_ASSERT( ! exclusive );
|
||||
BOOST_ASSERT( ! upgrade );
|
||||
BOOST_ASSERT( shared_count==0 );
|
||||
}
|
||||
|
||||
void assert_locked() const
|
||||
{
|
||||
BOOST_ASSERT( exclusive );
|
||||
BOOST_ASSERT( shared_count==0 );
|
||||
BOOST_ASSERT( ! upgrade );
|
||||
}
|
||||
|
||||
void assert_lock_shared () const
|
||||
{
|
||||
BOOST_ASSERT( ! exclusive );
|
||||
BOOST_ASSERT( shared_count>0 );
|
||||
//BOOST_ASSERT( (! upgrade) || (shared_count>1));
|
||||
// if upgraded there are at least 2 threads sharing the mutex,
|
||||
// except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
|
||||
}
|
||||
|
||||
void assert_lock_upgraded () const
|
||||
{
|
||||
BOOST_ASSERT( ! exclusive );
|
||||
BOOST_ASSERT( upgrade );
|
||||
BOOST_ASSERT( shared_count>0 );
|
||||
}
|
||||
|
||||
void assert_lock_not_upgraded () const
|
||||
{
|
||||
BOOST_ASSERT( ! upgrade );
|
||||
}
|
||||
|
||||
bool can_lock () const
|
||||
{
|
||||
return ! (shared_count || exclusive);
|
||||
}
|
||||
|
||||
void exclusive_blocked (bool blocked)
|
||||
{
|
||||
exclusive_waiting_blocked = blocked;
|
||||
}
|
||||
|
||||
void lock ()
|
||||
{
|
||||
exclusive = true;
|
||||
}
|
||||
|
||||
void unlock ()
|
||||
{
|
||||
exclusive = false;
|
||||
exclusive_waiting_blocked = false;
|
||||
}
|
||||
|
||||
bool can_lock_shared () const
|
||||
{
|
||||
return ! (exclusive || exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
bool more_shared () const
|
||||
{
|
||||
return shared_count > 0 ;
|
||||
}
|
||||
unsigned get_shared_count () const
|
||||
{
|
||||
return shared_count ;
|
||||
}
|
||||
unsigned lock_shared ()
|
||||
{
|
||||
return ++shared_count;
|
||||
}
|
||||
|
||||
|
||||
void unlock_shared ()
|
||||
{
|
||||
--shared_count;
|
||||
}
|
||||
|
||||
bool unlock_shared_downgrades()
|
||||
{
|
||||
if (upgrade) {
|
||||
upgrade=false;
|
||||
exclusive=true;
|
||||
return true;
|
||||
} else {
|
||||
exclusive_waiting_blocked=false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void lock_upgrade ()
|
||||
{
|
||||
++shared_count;
|
||||
upgrade=true;
|
||||
}
|
||||
bool can_lock_upgrade () const
|
||||
{
|
||||
return ! (exclusive || exclusive_waiting_blocked || upgrade);
|
||||
}
|
||||
|
||||
void unlock_upgrade ()
|
||||
{
|
||||
upgrade=false;
|
||||
--shared_count;
|
||||
}
|
||||
|
||||
//private:
|
||||
unsigned shared_count;
|
||||
bool exclusive;
|
||||
bool upgrade;
|
||||
@@ -51,12 +169,11 @@ namespace boost
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE(shared_mutex)
|
||||
|
||||
shared_mutex()
|
||||
{
|
||||
state_data state_={0,0,0,0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
@@ -69,27 +186,23 @@ namespace boost
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
while(!state.can_lock_shared())
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
if(!state.can_lock_shared())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
state.lock_shared();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
@@ -100,14 +213,14 @@ namespace boost
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
while(!state.can_lock_shared())
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -131,33 +244,38 @@ namespace boost
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
while(!state.can_lock_shared())
|
||||
//while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
state.assert_lock_shared();
|
||||
state.unlock_shared();
|
||||
if (! state.more_shared())
|
||||
{
|
||||
if(state.upgrade)
|
||||
if (state.upgrade)
|
||||
{
|
||||
// As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared()
|
||||
// avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
lk.unlock();
|
||||
upgrade_cond.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
lk.unlock();
|
||||
}
|
||||
release_waiters();
|
||||
}
|
||||
@@ -170,7 +288,7 @@ namespace boost
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
while (state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
exclusive_cond.wait(lk);
|
||||
@@ -262,8 +380,10 @@ namespace boost
|
||||
void unlock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_locked();
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
state.assert_free();
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
@@ -277,7 +397,7 @@ namespace boost
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
state.upgrade=true;
|
||||
}
|
||||
|
||||
@@ -299,7 +419,7 @@ namespace boost
|
||||
break;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
@@ -334,7 +454,7 @@ namespace boost
|
||||
break;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
@@ -348,8 +468,9 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
state.upgrade=true;
|
||||
state.assert_lock_upgraded();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -357,15 +478,14 @@ namespace boost
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
//state.upgrade=false;
|
||||
state.unlock_upgrade();
|
||||
if(! state.more_shared() )
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
} else {
|
||||
shared_cond.notify_all();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,28 +496,33 @@ namespace boost
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
--state.shared_count;
|
||||
while(state.shared_count)
|
||||
state.assert_lock_upgraded();
|
||||
state.unlock_shared();
|
||||
while (state.more_shared())
|
||||
{
|
||||
upgrade_cond.wait(lk);
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
state.assert_locked();
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_locked();
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
state.exclusive_waiting_blocked=false;
|
||||
state.assert_lock_upgraded();
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_upgraded();
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& state.upgrade
|
||||
@@ -406,6 +531,7 @@ namespace boost
|
||||
state.shared_count=0;
|
||||
state.exclusive=true;
|
||||
state.upgrade=false;
|
||||
state.assert_locked();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -428,6 +554,7 @@ namespace boost
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_upgraded();
|
||||
if (state.shared_count != 1)
|
||||
{
|
||||
for (;;)
|
||||
@@ -451,8 +578,9 @@ namespace boost
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_locked();
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.lock_shared();
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
@@ -461,6 +589,7 @@ namespace boost
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& !state.upgrade
|
||||
@@ -490,6 +619,7 @@ namespace boost
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
if (state.shared_count != 1)
|
||||
{
|
||||
for (;;)
|
||||
@@ -514,6 +644,7 @@ namespace boost
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_upgraded();
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
@@ -523,6 +654,7 @@ namespace boost
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& !state.upgrade
|
||||
@@ -551,6 +683,7 @@ namespace boost
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
#endif
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
if( state.exclusive
|
||||
|| state.exclusive_waiting_blocked
|
||||
|| state.upgrade
|
||||
|
||||
724
include/boost/thread/pthread/shared_mutex_assert.hpp
Normal file
724
include/boost/thread/pthread/shared_mutex_assert.hpp
Normal file
@@ -0,0 +1,724 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// (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)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#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>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
class state_data
|
||||
{
|
||||
public:
|
||||
state_data () :
|
||||
shared_count(0),
|
||||
exclusive(false),
|
||||
upgrade(false),
|
||||
exclusive_waiting_blocked(false)
|
||||
{}
|
||||
|
||||
void assert_free() const
|
||||
{
|
||||
BOOST_ASSERT( ! exclusive );
|
||||
BOOST_ASSERT( ! upgrade );
|
||||
BOOST_ASSERT( shared_count==0 );
|
||||
}
|
||||
|
||||
void assert_locked() const
|
||||
{
|
||||
BOOST_ASSERT( exclusive );
|
||||
BOOST_ASSERT( shared_count==0 );
|
||||
BOOST_ASSERT( ! upgrade );
|
||||
}
|
||||
|
||||
void assert_lock_shared () const
|
||||
{
|
||||
BOOST_ASSERT( ! exclusive );
|
||||
BOOST_ASSERT( shared_count>0 );
|
||||
//BOOST_ASSERT( (! upgrade) || (shared_count>1));
|
||||
// if upgraded there are at least 2 threads sharing the mutex,
|
||||
// except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
|
||||
}
|
||||
|
||||
void assert_lock_upgraded () const
|
||||
{
|
||||
BOOST_ASSERT( ! exclusive );
|
||||
BOOST_ASSERT( upgrade );
|
||||
BOOST_ASSERT( shared_count>0 );
|
||||
}
|
||||
|
||||
void assert_lock_not_upgraded () const
|
||||
{
|
||||
BOOST_ASSERT( ! upgrade );
|
||||
}
|
||||
|
||||
bool can_lock () const
|
||||
{
|
||||
return ! (shared_count || exclusive);
|
||||
}
|
||||
|
||||
void exclusive_blocked (bool blocked)
|
||||
{
|
||||
exclusive_waiting_blocked = blocked;
|
||||
}
|
||||
|
||||
void lock ()
|
||||
{
|
||||
exclusive = true;
|
||||
}
|
||||
|
||||
void unlock ()
|
||||
{
|
||||
exclusive = false;
|
||||
exclusive_waiting_blocked = false;
|
||||
}
|
||||
|
||||
bool can_lock_shared () const
|
||||
{
|
||||
return ! (exclusive || exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
bool is_last_shared () const
|
||||
{
|
||||
return !shared_count ;
|
||||
}
|
||||
unsigned get_shared_count () const
|
||||
{
|
||||
return shared_count ;
|
||||
}
|
||||
unsigned lock_shared ()
|
||||
{
|
||||
return ++shared_count;
|
||||
}
|
||||
|
||||
|
||||
void unlock_shared ()
|
||||
{
|
||||
--shared_count;
|
||||
}
|
||||
|
||||
bool unlock_shared_downgrades()
|
||||
{
|
||||
if (upgrade) {
|
||||
upgrade=false;
|
||||
exclusive=true;
|
||||
return true;
|
||||
} else {
|
||||
exclusive_waiting_blocked=false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void lock_upgrade ()
|
||||
{
|
||||
lock_shared ();
|
||||
upgrade=true;
|
||||
}
|
||||
bool can_lock_upgrade () const
|
||||
{
|
||||
return ! (exclusive || exclusive_waiting_blocked || upgrade);
|
||||
}
|
||||
|
||||
void unlock_upgrade ()
|
||||
{
|
||||
upgrade=false;
|
||||
unlock_shared();
|
||||
}
|
||||
|
||||
//private:
|
||||
unsigned shared_count;
|
||||
bool exclusive;
|
||||
bool upgrade;
|
||||
bool exclusive_waiting_blocked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
state_data state;
|
||||
boost::mutex state_change;
|
||||
boost::condition_variable shared_cond;
|
||||
boost::condition_variable exclusive_cond;
|
||||
boost::condition_variable upgrade_cond;
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
exclusive_cond.notify_one();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(shared_mutex)
|
||||
|
||||
shared_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
while(!state.can_lock_shared())
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
state.lock_shared();
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
if(!state.can_lock_shared())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.lock_shared();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
while(!state.can_lock_shared())
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.lock_shared();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
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);
|
||||
|
||||
while(!state.can_lock_shared())
|
||||
{
|
||||
if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.lock_shared();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
state.unlock_shared();
|
||||
if (state.get_shared_count () == 0)
|
||||
{
|
||||
if (state.unlock_shared_downgrades())
|
||||
{
|
||||
lk.unlock();
|
||||
upgrade_cond.notify_one();
|
||||
} else {
|
||||
lk.unlock();
|
||||
}
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
while(!state.can_lock())
|
||||
{
|
||||
state.exclusive_blocked(true);
|
||||
exclusive_cond.wait(lk);
|
||||
}
|
||||
state.lock();
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
while(!state.can_lock())
|
||||
{
|
||||
state.exclusive_blocked(true);
|
||||
if(!exclusive_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(!state.can_lock())
|
||||
{
|
||||
state.exclusive_blocked(false);
|
||||
release_waiters();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.exclusive=true;
|
||||
//state.lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return try_lock_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
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);
|
||||
|
||||
while(!state.can_lock())
|
||||
{
|
||||
state.exclusive_blocked(true);
|
||||
if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
if(!state.can_lock())
|
||||
{
|
||||
state.exclusive_blocked(false);
|
||||
release_waiters();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.exclusive=true;
|
||||
//state.lock();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
|
||||
if(!state.can_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_locked();
|
||||
state.unlock();
|
||||
state.assert_free();
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
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);
|
||||
while(!state.can_lock_upgrade())
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
state.lock_upgrade();
|
||||
}
|
||||
|
||||
#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);
|
||||
while(!state.can_lock_upgrade())
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(!state.can_lock_upgrade())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.lock_upgrade();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_upgrade(TimeDuration const & relative_time)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
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);
|
||||
while(!state.can_lock_upgrade())
|
||||
{
|
||||
if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
if(!state.can_lock_upgrade())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.lock_upgrade();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
if(!state.can_lock_upgrade())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.lock_upgrade();
|
||||
state.assert_lock_upgraded();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_upgraded();
|
||||
state.unlock_upgrade();
|
||||
state.assert_lock_not_upgraded ();
|
||||
if(state.get_shared_count () == 0)
|
||||
{
|
||||
state.exclusive_blocked(false);
|
||||
lk.unlock();
|
||||
release_waiters();
|
||||
} else {
|
||||
lk.unlock();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
state.assert_lock_upgraded();
|
||||
// assert state.get_shared_count() >=1
|
||||
while(
|
||||
//! state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
//&&
|
||||
state.get_shared_count()!=1)
|
||||
{
|
||||
upgrade_cond.wait(lk);
|
||||
}
|
||||
state.unlock_upgrade();
|
||||
state.lock();
|
||||
state.assert_locked();
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_locked();
|
||||
state.unlock();
|
||||
state.lock_upgrade();
|
||||
state.assert_lock_upgraded();
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_upgraded();
|
||||
if( //!state.exclusive // this should be removed once the assertion work
|
||||
! state.exclusive_waiting_blocked // Fixme: why this is needed?
|
||||
//&& state.upgrade // this should be removed once the assertion work
|
||||
&& state.get_shared_count()==1)
|
||||
{
|
||||
state.unlock_upgrade();
|
||||
state.lock();
|
||||
state.assert_locked();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
try_unlock_upgrade_and_lock_for(
|
||||
const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_unlock_upgrade_and_lock_until(
|
||||
chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
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);
|
||||
state.assert_lock_upgraded();
|
||||
if (//state.exclusive // this should be removed once the assertion work
|
||||
state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
//|| ! state.upgrade // this should be removed once the assertion work
|
||||
|| state.get_shared_count() != 1)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
//cv_status status = shared_cond.wait_until(lk,abs_time);
|
||||
cv_status status = upgrade_cond.wait_until(lk,abs_time);
|
||||
if (//!state.exclusive // this should be removed once the assertion work
|
||||
! state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
//&& ! state.upgrade // this should be removed once the assertion work
|
||||
&& state.get_shared_count() == 1)
|
||||
break;
|
||||
if(status == cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.unlock_upgrade();
|
||||
state.lock();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Shared <-> Exclusive
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_locked();
|
||||
state.unlock();
|
||||
state.lock_shared();
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
if( //!state.exclusive // this should be removed once the assertion work
|
||||
! state.exclusive_waiting_blocked // Fixme: why this is needed?
|
||||
//&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
|
||||
&& state.get_shared_count()==1)
|
||||
{
|
||||
state.unlock_shared();
|
||||
state.lock();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
try_unlock_shared_and_lock_for(
|
||||
const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_until(
|
||||
chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
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);
|
||||
state.assert_lock_shared();
|
||||
if ( // !state.exclusive // this should be removed once the assertion work
|
||||
state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
//|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
|
||||
|| state.get_shared_count() != 1)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cv_status status = shared_cond.wait_until(lk,abs_time);
|
||||
if ( //! state.exclusive // this should be removed once the assertion work
|
||||
! state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
//&& ! state.upgrade
|
||||
&& state.get_shared_count() == 1)
|
||||
break;
|
||||
if(status == cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.unlock_shared();
|
||||
state.lock();
|
||||
state.upgrade=false; // Is this absolutely needed?
|
||||
state.exclusive_waiting_blocked=false; // Is this absolutely needed?
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Shared <-> Upgrade
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_upgraded();
|
||||
//state.unlock_upgrade();
|
||||
//state.lock_shared(); // less efficient
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false; // Is this absolutely needed?
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(state_change);
|
||||
state.assert_lock_shared();
|
||||
if( //! state.exclusive // this should be removed once the assertion work
|
||||
! state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
&& ! state.upgrade
|
||||
)
|
||||
{
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
return try_unlock_shared_and_lock_upgrade_until(
|
||||
chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
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);
|
||||
state.assert_lock_shared();
|
||||
if( //state.exclusive // this should be removed once the assertion work
|
||||
state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
|| state.upgrade
|
||||
)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cv_status status = exclusive_cond.wait_until(lk,abs_time);
|
||||
if( //! state.exclusive // this should be removed once the assertion work
|
||||
! state.exclusive_waiting_blocked // Fixme: is this needed?
|
||||
&& ! state.upgrade
|
||||
)
|
||||
break;
|
||||
if(status == cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//state.unlock_shared();
|
||||
//state.lock_upgrade(); // less efficient
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef shared_mutex upgrade_mutex;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -132,8 +132,10 @@ namespace boost
|
||||
bool interrupt_requested;
|
||||
//#endif
|
||||
thread_data_base():
|
||||
thread_handle(0),
|
||||
done(false),join_started(false),joined(false),
|
||||
thread_exit_callbacks(0),
|
||||
cond_mutex(0),
|
||||
current_cond(0),
|
||||
notify(),
|
||||
async_states_()
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#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/thread/thread_only.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -38,10 +38,35 @@ namespace boost
|
||||
class strict_scoped_thread
|
||||
{
|
||||
thread t_;
|
||||
struct dummy;
|
||||
public:
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class F, class ...Args>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
t_(boost::forward<F>(f)) {}
|
||||
template <class F, class A1>
|
||||
strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
|
||||
t_(boost::forward<F>(f), boost::forward<A1>(a1)) {}
|
||||
template <class F, class A1, class A2>
|
||||
strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) :
|
||||
t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {}
|
||||
template <class F, class A1, class A2, class A3>
|
||||
strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) :
|
||||
t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructor from the thread to own.
|
||||
*
|
||||
@@ -91,6 +116,7 @@ namespace boost
|
||||
class scoped_thread
|
||||
{
|
||||
thread t_;
|
||||
struct dummy;
|
||||
public:
|
||||
|
||||
typedef thread::id id;
|
||||
@@ -107,6 +133,31 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class F, class ...Args>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
t_(boost::forward<F>(f)) {}
|
||||
template <class F, class A1>
|
||||
scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
|
||||
t_(boost::forward<F>(f), boost::forward<A1>(a1)) {}
|
||||
template <class F, class A1, class A2>
|
||||
scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) :
|
||||
t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {}
|
||||
template <class F, class A1, class A2, class A3>
|
||||
scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) :
|
||||
t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Constructor from the thread to own.
|
||||
*
|
||||
@@ -195,6 +246,11 @@ namespace boost
|
||||
return t_.native_handle();
|
||||
}
|
||||
|
||||
bool joinable() const BOOST_NOEXCEPT
|
||||
{
|
||||
return t_.joinable();
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void interrupt()
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <boost/thread/win32/shared_mutex.hpp>
|
||||
#endif
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
//#include <boost/thread/v2/shared_mutex.hpp>
|
||||
#include <boost/thread/pthread/shared_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
|
||||
@@ -73,7 +73,6 @@ namespace boost
|
||||
|
||||
|
||||
// observers
|
||||
private:
|
||||
|
||||
/**
|
||||
* @return the owned mutex.
|
||||
@@ -82,12 +81,19 @@ namespace boost
|
||||
{
|
||||
return &mtx_;
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* @return whether this lock is locking a mutex.
|
||||
*/
|
||||
bool owns_lock() const BOOST_NOEXCEPT
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this lock is locking that mutex.
|
||||
*/
|
||||
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT
|
||||
bool owns_lock(const mutex_type* l) const BOOST_NOEXCEPT
|
||||
{
|
||||
return l == mutex();
|
||||
} /*< strict locks specific function >*/
|
||||
@@ -173,7 +179,6 @@ namespace boost
|
||||
}
|
||||
|
||||
// observers
|
||||
private:
|
||||
/**
|
||||
* return @c the owned mutex.
|
||||
*/
|
||||
@@ -181,7 +186,15 @@ private:
|
||||
{
|
||||
return tmp_lk_.mutex();
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* @return whether this lock is locking a mutex.
|
||||
*/
|
||||
bool owns_lock() const BOOST_NOEXCEPT
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether if this lock is locking that mutex.
|
||||
*/
|
||||
|
||||
594
include/boost/thread/sync_bounded_queue.hpp
Normal file
594
include/boost/thread/sync_bounded_queue.hpp
Normal file
@@ -0,0 +1,594 @@
|
||||
#ifndef BOOST_THREAD_SYNC_BOUNDED_QUEUE_HPP
|
||||
#define BOOST_THREAD_SYNC_BOUNDED_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013. 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
|
||||
{ success = 0, empty, full, closed, busy }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
|
||||
struct sync_queue_is_closed : std::exception {};
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_bounded_queue)
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type capacity() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void close();
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
void pull(value_type&);
|
||||
void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
condition_variable not_full_;
|
||||
size_type waiting_full_;
|
||||
size_type waiting_empty_;
|
||||
value_type* data_;
|
||||
size_type in_;
|
||||
size_type out_;
|
||||
size_type capacity_;
|
||||
bool closed_;
|
||||
|
||||
size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (idx + 1) % capacity_;
|
||||
}
|
||||
|
||||
bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity;
|
||||
}
|
||||
size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return ((out_+capacity_-in_) % capacity_)-1;
|
||||
}
|
||||
|
||||
void throw_if_closed(unique_lock<mutex>&);
|
||||
|
||||
bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
|
||||
void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_full_ > 0)
|
||||
{
|
||||
--waiting_full_;
|
||||
lk.unlock();
|
||||
not_full_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
in_ = in;
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = elem;
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = boost::move(elem);
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) :
|
||||
waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
closed_(false)
|
||||
{
|
||||
BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) :
|
||||
// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
// closed_(false)
|
||||
// {
|
||||
// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size");
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// size_type in = 0;
|
||||
// for (iterator_t cur = first; cur != end; ++cur, ++in)
|
||||
// {
|
||||
// data_[in] = *cur;
|
||||
// }
|
||||
// set_in(in);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::~sync_bounded_queue()
|
||||
{
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
not_full_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::full() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return full(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return capacity(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk, closed);
|
||||
if (closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 != out_) // ! full()
|
||||
{
|
||||
return in_p_1;
|
||||
}
|
||||
++waiting_full_;
|
||||
not_full_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::forward<ValueType>(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
516
include/boost/thread/sync_queue.hpp
Normal file
516
include/boost/thread/sync_queue.hpp
Normal file
@@ -0,0 +1,516 @@
|
||||
#ifndef BOOST_THREAD_SYNC_QUEUE_HPP
|
||||
#define BOOST_THREAD_SYNC_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013. 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
#include <boost/container/deque.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue)
|
||||
sync_queue();
|
||||
template <typename Range>
|
||||
explicit sync_queue(Range range);
|
||||
~sync_queue();
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void close();
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
void pull(value_type&);
|
||||
void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
size_type waiting_empty_;
|
||||
boost::container::deque<ValueType> data_;
|
||||
bool closed_;
|
||||
|
||||
bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
void throw_if_closed(unique_lock<mutex>&);
|
||||
|
||||
bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
|
||||
void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void pull(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
}
|
||||
boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front()));
|
||||
data_.pop_front();
|
||||
return res;
|
||||
}
|
||||
|
||||
void push(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(elem);
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push(boost::move(elem));
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::sync_queue() :
|
||||
waiting_empty_(0), data_(), closed_(false)
|
||||
{
|
||||
BOOST_ASSERT(data_.empty());
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// explicit sync_queue<ValueType>::sync_queue(Range range) :
|
||||
// waiting_empty_(0), data_(), closed_(false)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// for (iterator_t cur = first; cur != end; ++cur)
|
||||
// {
|
||||
// data_.push(boost::move(*cur));;
|
||||
// }
|
||||
// notify_not_empty_if_needed(lk);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::~sync_queue()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::full() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_queue<ValueType>::size_type sync_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk, closed);
|
||||
if (closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
push(boost::forward<ValueType>(elem), lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::forward<ValueType>(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -18,6 +18,17 @@
|
||||
#include <boost/thread/lock_factories.hpp>
|
||||
#include <boost/thread/strict_lock.hpp>
|
||||
#include <boost/utility/swap.hpp>
|
||||
#include <boost/utility/declval.hpp>
|
||||
//#include <boost/type_traits.hpp>
|
||||
//#include <boost/thread/detail/is_nothrow_default_constructible.hpp>
|
||||
//#if ! defined BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
//#include <type_traits>
|
||||
//#endif
|
||||
|
||||
#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
|
||||
#include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics.
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -25,29 +36,44 @@ namespace boost
|
||||
{
|
||||
|
||||
/**
|
||||
* strict lock providing a const pointer access to the synchronized value type.
|
||||
*
|
||||
* @param T the value type.
|
||||
* @param Lockable the mutex type protecting the value type.
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class const_strict_lock_ptr
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
typedef Lockable mutex_type;
|
||||
protected:
|
||||
|
||||
// this should be a strict_lock, but we need to be able to return it.
|
||||
boost::unique_lock<lockable_type> lk_;
|
||||
// this should be a strict_lock, but unique_lock is needed to be able to return it.
|
||||
boost::unique_lock<mutex_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)
|
||||
/**
|
||||
* @param value constant reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
|
||||
*/
|
||||
const_strict_lock_ptr(T const& val, Lockable & mtx) :
|
||||
lk_(mtx), value_(val)
|
||||
{
|
||||
}
|
||||
|
||||
const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other)
|
||||
const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag) BOOST_NOEXCEPT :
|
||||
lk_(mtx, tag), value_(val)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Move constructor.
|
||||
* @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
|
||||
*/
|
||||
const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other) BOOST_NOEXCEPT
|
||||
: lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_)
|
||||
{
|
||||
}
|
||||
@@ -56,11 +82,17 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a constant pointer to the protected value
|
||||
*/
|
||||
const T* operator->() const
|
||||
{
|
||||
return &value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a constant reference to the protected value
|
||||
*/
|
||||
const T& operator*() const
|
||||
{
|
||||
return value_;
|
||||
@@ -69,7 +101,10 @@ namespace boost
|
||||
};
|
||||
|
||||
/**
|
||||
* strict lock providing a pointer access to the synchronized value type.
|
||||
*
|
||||
* @param T the value type.
|
||||
* @param Lockable the mutex type protecting the value type.
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable>
|
||||
@@ -78,11 +113,24 @@ namespace boost
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( strict_lock_ptr )
|
||||
|
||||
strict_lock_ptr(T & value, Lockable & mtx) :
|
||||
base_type(value, mtx)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
|
||||
*/
|
||||
strict_lock_ptr(T & val, Lockable & mtx) :
|
||||
base_type(val, mtx)
|
||||
{
|
||||
}
|
||||
strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag) :
|
||||
base_type(val, mtx, tag)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Move constructor.
|
||||
* @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
|
||||
*/
|
||||
strict_lock_ptr(BOOST_THREAD_RV_REF(strict_lock_ptr) other)
|
||||
: base_type(boost::move(static_cast<base_type&>(other)))
|
||||
{
|
||||
@@ -92,11 +140,17 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a pointer to the protected value
|
||||
*/
|
||||
T* operator->()
|
||||
{
|
||||
return const_cast<T*>(&this->value_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a reference to the protected value
|
||||
*/
|
||||
T& operator*()
|
||||
{
|
||||
return const_cast<T&>(this->value_);
|
||||
@@ -104,8 +158,35 @@ namespace boost
|
||||
|
||||
};
|
||||
|
||||
template <typename SV>
|
||||
struct synchronized_value_strict_lock_ptr
|
||||
{
|
||||
typedef strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
|
||||
};
|
||||
|
||||
template <typename SV>
|
||||
struct synchronized_value_strict_lock_ptr<const SV>
|
||||
{
|
||||
typedef const_strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
|
||||
};
|
||||
/**
|
||||
* unique_lock providing a const pointer access to the synchronized value type.
|
||||
*
|
||||
* An object of type const_unique_lock_ptr is a unique_lock that provides a const pointer access to the synchronized value type.
|
||||
* As unique_lock controls the ownership of a lockable object within a scope.
|
||||
* Ownership of the lockable object may be acquired at construction or after construction,
|
||||
* and may be transferred, after acquisition, to another const_unique_lock_ptr object.
|
||||
* Objects of type const_unique_lock_ptr are not copyable but are movable.
|
||||
* The behavior of a program is undefined if the mutex and the value type
|
||||
* pointed do not exist for the entire remaining lifetime of the const_unique_lock_ptr object.
|
||||
* The supplied Mutex type shall meet the BasicLockable requirements.
|
||||
*
|
||||
* @note const_unique_lock_ptr<T, Lockable> meets the Lockable requirements.
|
||||
* If Lockable meets the TimedLockable requirements, const_unique_lock_ptr<T,Lockable>
|
||||
* also meets the TimedLockable requirements.
|
||||
*
|
||||
* @param T the value type.
|
||||
* @param Lockable the mutex type protecting the value type.
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class const_unique_lock_ptr : public unique_lock<Lockable>
|
||||
@@ -113,44 +194,85 @@ namespace boost
|
||||
typedef unique_lock<Lockable> base_type;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
typedef Lockable mutex_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)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
*
|
||||
* @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex.
|
||||
*
|
||||
* @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
|
||||
*/
|
||||
const_unique_lock_ptr(T const& val, Lockable & mtx)
|
||||
: base_type(mtx), value_(val)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx, adopt_lock_t)
|
||||
: base_type(mtx, adopt_lock), value_(value)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @param tag of type adopt_lock_t used to differentiate the constructor.
|
||||
* @requires The calling thread own the mutex.
|
||||
* @effects stores a reference to it and to the value type @c value taking ownership.
|
||||
*/
|
||||
const_unique_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT
|
||||
: base_type(mtx, adopt_lock), value_(val)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx, defer_lock_t)
|
||||
: base_type(mtx, defer_lock), value_(value)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @param tag of type defer_lock_t used to differentiate the constructor.
|
||||
* @effects stores a reference to it and to the value type @c value c.
|
||||
*/
|
||||
const_unique_lock_ptr(T const& val, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT
|
||||
: base_type(mtx, defer_lock), value_(val)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(T const& value, Lockable & mtx, try_to_lock_t)
|
||||
: base_type(mtx, try_to_lock), value_(value)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @param tag of type try_to_lock_t used to differentiate the constructor.
|
||||
* @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex.
|
||||
* @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value.
|
||||
*/
|
||||
const_unique_lock_ptr(T const& val, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT
|
||||
: base_type(mtx, try_to_lock), value_(val)
|
||||
{
|
||||
}
|
||||
const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other)
|
||||
/**
|
||||
* Move constructor.
|
||||
* @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
|
||||
*/
|
||||
const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other) BOOST_NOEXCEPT
|
||||
: base_type(boost::move(static_cast<base_type&>(other))), value_(BOOST_THREAD_RV(other).value_)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @effects If owns calls unlock() on the owned mutex.
|
||||
*/
|
||||
~const_unique_lock_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a constant pointer to the protected value
|
||||
*/
|
||||
const T* operator->() const
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
return &value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a constant reference to the protected value
|
||||
*/
|
||||
const T& operator*() const
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
@@ -160,7 +282,10 @@ namespace boost
|
||||
};
|
||||
|
||||
/**
|
||||
* unique lock providing a pointer access to the synchronized value type.
|
||||
*
|
||||
* @param T the value type.
|
||||
* @param Lockable the mutex type protecting the value type.
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class unique_lock_ptr : public const_unique_lock_ptr<T, Lockable>
|
||||
@@ -168,27 +293,54 @@ namespace boost
|
||||
typedef const_unique_lock_ptr<T, Lockable> base_type;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(unique_lock_ptr)
|
||||
|
||||
unique_lock_ptr(T & value, Lockable & mtx)
|
||||
: base_type(value, mtx)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value.
|
||||
*/
|
||||
unique_lock_ptr(T & val, Lockable & mtx)
|
||||
: base_type(val, mtx)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @param tag of type adopt_lock_t used to differentiate the constructor.
|
||||
* @effects stores a reference to it and to the value type @c value taking ownership.
|
||||
*/
|
||||
unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT
|
||||
: base_type(value, mtx, adopt_lock)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @param tag of type defer_lock_t used to differentiate the constructor.
|
||||
* @effects stores a reference to it and to the value type @c value c.
|
||||
*/
|
||||
unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT
|
||||
: base_type(value, mtx, defer_lock)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t)
|
||||
/**
|
||||
* @param value reference of the value to protect.
|
||||
* @param mtx reference to the mutex used to protect the value.
|
||||
* @param tag of type try_to_lock_t used to differentiate the constructor.
|
||||
* @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value.
|
||||
*/
|
||||
unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT
|
||||
: base_type(value, mtx, try_to_lock)
|
||||
{
|
||||
}
|
||||
unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other)
|
||||
/**
|
||||
* Move constructor.
|
||||
* @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other.
|
||||
*/
|
||||
unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other) BOOST_NOEXCEPT
|
||||
: base_type(boost::move(static_cast<base_type&>(other)))
|
||||
{
|
||||
}
|
||||
@@ -197,12 +349,18 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a pointer to the protected value
|
||||
*/
|
||||
T* operator->()
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
return const_cast<T*>(&this->value_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a reference to the protected value
|
||||
*/
|
||||
T& operator*()
|
||||
{
|
||||
BOOST_ASSERT (this->owns_lock());
|
||||
@@ -212,25 +370,62 @@ namespace boost
|
||||
|
||||
};
|
||||
|
||||
template <typename SV>
|
||||
struct synchronized_value_unique_lock_ptr
|
||||
{
|
||||
typedef unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
|
||||
};
|
||||
|
||||
template <typename SV>
|
||||
struct synchronized_value_unique_lock_ptr<const SV>
|
||||
{
|
||||
typedef const_unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type;
|
||||
};
|
||||
/**
|
||||
*
|
||||
* cloaks a value type and the mutex used to protect it together.
|
||||
* @param T the value type.
|
||||
* @param Lockable the mutex type protecting the value type.
|
||||
*/
|
||||
template <typename T, typename Lockable = mutex>
|
||||
class synchronized_value
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
|
||||
#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template <typename ...SV>
|
||||
friend std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
|
||||
#else
|
||||
template <typename SV1, typename SV2>
|
||||
friend std::tuple<
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type
|
||||
>
|
||||
synchronize(SV1& sv1, SV2& sv2);
|
||||
template <typename SV1, typename SV2, typename SV3>
|
||||
friend std::tuple<
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV3>::type
|
||||
>
|
||||
synchronize(SV1& sv1, SV2& sv2, SV3& sv3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Lockable lockable_type;
|
||||
typedef Lockable mutex_type;
|
||||
private:
|
||||
T value_;
|
||||
mutable lockable_type mtx_;
|
||||
mutable mutex_type mtx_;
|
||||
public:
|
||||
// construction/destruction
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* Requires: T is DefaultConstructible
|
||||
* @Requires: T is DefaultConstructible
|
||||
*/
|
||||
synchronized_value()
|
||||
//BOOST_NOEXCEPT_IF(is_nothrow_default_constructible<T>::value)
|
||||
: value_()
|
||||
{
|
||||
}
|
||||
@@ -241,47 +436,50 @@ namespace boost
|
||||
* Requires: T is CopyConstructible
|
||||
*/
|
||||
synchronized_value(T const& other)
|
||||
//BOOST_NOEXCEPT_IF(is_nothrow_copy_constructible<T>::value)
|
||||
: value_(other)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Move Constructor from movable value.
|
||||
* Move Constructor.
|
||||
*
|
||||
* Requires: T is Movable
|
||||
* Requires: T is CopyMovable
|
||||
*/
|
||||
synchronized_value(BOOST_THREAD_RV_REF(T) other)
|
||||
//BOOST_NOEXCEPT_IF(is_nothrow_move_constructible<T>::value)
|
||||
: value_(boost::move(other))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
* Constructor from value type.
|
||||
*
|
||||
* 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_);
|
||||
strict_lock<mutex_type> lk(rhs.mtx_);
|
||||
value_ = rhs.value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move Constructor.
|
||||
* Move Constructor from movable value type
|
||||
*
|
||||
*/
|
||||
synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other)
|
||||
{
|
||||
strict_lock<lockable_type> lk(other.mtx_);
|
||||
value_= boost::move(other);
|
||||
strict_lock<mutex_type> lk(other.mtx_);
|
||||
value_= boost::move(other.value_);
|
||||
}
|
||||
|
||||
// mutation
|
||||
/**
|
||||
* 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.
|
||||
* The mutex is 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
|
||||
@@ -292,8 +490,8 @@ namespace boost
|
||||
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);
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
value_ = rhs.value_;
|
||||
@@ -305,15 +503,16 @@ namespace boost
|
||||
* Effects: The operator copies the value on a scope protected by the mutex.
|
||||
* Return: *this
|
||||
*/
|
||||
synchronized_value& operator=(value_type const& value)
|
||||
synchronized_value& operator=(value_type const& val)
|
||||
{
|
||||
{
|
||||
strict_lock<lockable_type> lk(mtx_);
|
||||
value_ = value;
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
value_ = val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//observers
|
||||
/**
|
||||
* Explicit conversion to value type.
|
||||
*
|
||||
@@ -323,7 +522,7 @@ namespace boost
|
||||
*/
|
||||
T get() const
|
||||
{
|
||||
strict_lock<lockable_type> lk(mtx_);
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return value_;
|
||||
}
|
||||
/**
|
||||
@@ -340,6 +539,30 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* value type getter.
|
||||
*
|
||||
* Return: A constant reference to the protected value.
|
||||
*
|
||||
* Note: Not thread safe
|
||||
*
|
||||
*/
|
||||
T const& value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
/**
|
||||
* mutex getter.
|
||||
*
|
||||
* Return: A constant reference to the protecting mutex.
|
||||
*
|
||||
* Note: Not thread safe
|
||||
*
|
||||
*/
|
||||
mutex_type const& mutex() const
|
||||
{
|
||||
return mtx_;
|
||||
}
|
||||
/**
|
||||
* Swap
|
||||
*
|
||||
@@ -354,20 +577,20 @@ namespace boost
|
||||
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);
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
boost::swap(value_, rhs.value_);
|
||||
}
|
||||
/**
|
||||
* Swap with the underlying type
|
||||
* Swap with the underlying value 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_);
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
boost::swap(value_, rhs);
|
||||
}
|
||||
|
||||
|
||||
@@ -415,27 +638,53 @@ namespace boost
|
||||
{
|
||||
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_)));
|
||||
}
|
||||
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(defer_lock_t tag) const
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, tag)));
|
||||
}
|
||||
unique_lock_ptr<T,Lockable> defer_synchronize() BOOST_NOEXCEPT
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock)));
|
||||
}
|
||||
const_unique_lock_ptr<T,Lockable> defer_synchronize() const BOOST_NOEXCEPT
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock)));
|
||||
}
|
||||
unique_lock_ptr<T,Lockable> try_to_synchronize() BOOST_NOEXCEPT
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock)));
|
||||
}
|
||||
const_unique_lock_ptr<T,Lockable> try_to_synchronize() const BOOST_NOEXCEPT
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock)));
|
||||
}
|
||||
unique_lock_ptr<T,Lockable> adopt_synchronize() BOOST_NOEXCEPT
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock)));
|
||||
}
|
||||
const_unique_lock_ptr<T,Lockable> adopt_synchronize() const BOOST_NOEXCEPT
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock)));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
#if ! defined __IBMCPP__
|
||||
private:
|
||||
#endif
|
||||
class deref_value
|
||||
{
|
||||
private:
|
||||
friend class synchronized_value;
|
||||
|
||||
boost::unique_lock<lockable_type> lk_;
|
||||
boost::unique_lock<mutex_type> lk_;
|
||||
T& value_;
|
||||
|
||||
explicit deref_value(synchronized_value& outer):
|
||||
@@ -448,7 +697,7 @@ namespace boost
|
||||
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()
|
||||
operator T&()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
@@ -464,7 +713,7 @@ namespace boost
|
||||
private:
|
||||
friend class synchronized_value;
|
||||
|
||||
boost::unique_lock<lockable_type> lk_;
|
||||
boost::unique_lock<mutex_type> lk_;
|
||||
const T& value_;
|
||||
|
||||
explicit const_deref_value(synchronized_value const& outer):
|
||||
@@ -478,7 +727,7 @@ namespace boost
|
||||
lk_(boost::move(BOOST_THREAD_RV(other).lk_)), value_(BOOST_THREAD_RV(other).value_)
|
||||
{}
|
||||
|
||||
operator T()
|
||||
operator const T&()
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
@@ -495,8 +744,121 @@ namespace boost
|
||||
return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this));
|
||||
}
|
||||
|
||||
// io functions
|
||||
/**
|
||||
* @requires T is OutputStreamable
|
||||
* @effects saves the value type on the output stream @c os.
|
||||
*/
|
||||
template <typename OStream>
|
||||
void save(OStream& os) const
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
os << value_;
|
||||
}
|
||||
/**
|
||||
* @requires T is InputStreamable
|
||||
* @effects loads the value type from the input stream @c is.
|
||||
*/
|
||||
template <typename IStream>
|
||||
void load(IStream& is) const
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
is >> value_;
|
||||
}
|
||||
|
||||
// relational operators
|
||||
/**
|
||||
* @requires T is EqualityComparable
|
||||
*
|
||||
*/
|
||||
bool operator==(synchronized_value const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
return value_ == rhs.value_;
|
||||
}
|
||||
/**
|
||||
* @requires T is LessThanComparable
|
||||
*
|
||||
*/
|
||||
bool operator<(synchronized_value const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
return value_ < rhs.value_;
|
||||
}
|
||||
/**
|
||||
* @requires T is GreaterThanComparable
|
||||
*
|
||||
*/
|
||||
bool operator>(synchronized_value const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
return value_ > rhs.value_;
|
||||
}
|
||||
bool operator<=(synchronized_value const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
return value_ <= rhs.value_;
|
||||
}
|
||||
bool operator>=(synchronized_value const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_, defer_lock);
|
||||
unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock);
|
||||
lock(lk1,lk2);
|
||||
|
||||
return value_ >= rhs.value_;
|
||||
}
|
||||
bool operator==(value_type const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_);
|
||||
|
||||
return value_ == rhs;
|
||||
}
|
||||
bool operator!=(value_type const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_);
|
||||
|
||||
return value_ != rhs;
|
||||
}
|
||||
bool operator<(value_type const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_);
|
||||
|
||||
return value_ < rhs;
|
||||
}
|
||||
bool operator<=(value_type const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_);
|
||||
|
||||
return value_ <= rhs;
|
||||
}
|
||||
bool operator>(value_type const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_);
|
||||
|
||||
return value_ > rhs;
|
||||
}
|
||||
bool operator>=(value_type const& rhs) const
|
||||
{
|
||||
unique_lock<mutex_type> lk1(mtx_);
|
||||
|
||||
return value_ >= rhs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Specialized algorithms
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -505,7 +867,133 @@ namespace boost
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
template <typename T, typename L>
|
||||
inline void swap(synchronized_value<T,L> & lhs, T & rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
template <typename T, typename L>
|
||||
inline void swap(T & lhs, synchronized_value<T,L> & rhs)
|
||||
{
|
||||
rhs.swap(lhs);
|
||||
}
|
||||
|
||||
//Hash support
|
||||
|
||||
template <class T> struct hash;
|
||||
template <typename T, typename L>
|
||||
struct hash<synchronized_value<T,L> >;
|
||||
|
||||
// Comparison with T
|
||||
template <typename T, typename L>
|
||||
bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
|
||||
{
|
||||
return ! (lhs==rhs);
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
bool operator==(T const& lhs, synchronized_value<T,L> const&rhs)
|
||||
{
|
||||
return rhs==lhs;
|
||||
}
|
||||
template <typename T, typename L>
|
||||
bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs)
|
||||
{
|
||||
return rhs!=lhs;
|
||||
}
|
||||
template <typename T, typename L>
|
||||
bool operator<(T const& lhs, synchronized_value<T,L> const&rhs)
|
||||
{
|
||||
return rhs>=lhs;
|
||||
}
|
||||
template <typename T, typename L>
|
||||
bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs)
|
||||
{
|
||||
return rhs>lhs;
|
||||
}
|
||||
template <typename T, typename L>
|
||||
bool operator>(T const& lhs, synchronized_value<T,L> const&rhs)
|
||||
{
|
||||
return rhs<=lhs;
|
||||
}
|
||||
template <typename T, typename L>
|
||||
bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs)
|
||||
{
|
||||
return rhs<lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename OStream, typename T, typename L>
|
||||
inline OStream& operator<<(OStream& os, synchronized_value<T,L> const& rhs)
|
||||
{
|
||||
rhs.save(os);
|
||||
return os;
|
||||
}
|
||||
template <typename IStream, typename T, typename L>
|
||||
inline IStream& operator>>(IStream& is, synchronized_value<T,L> const& rhs)
|
||||
{
|
||||
rhs.load(is);
|
||||
return is;
|
||||
}
|
||||
|
||||
#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
|
||||
#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
template <typename ...SV>
|
||||
std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv)
|
||||
{
|
||||
boost::lock(sv.mtx_ ...);
|
||||
typedef std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> t_type;
|
||||
|
||||
return t_type(typename synchronized_value_strict_lock_ptr<SV>::type(sv.value_, sv.mtx_, adopt_lock) ...);
|
||||
}
|
||||
#else
|
||||
|
||||
template <typename SV1, typename SV2>
|
||||
std::tuple<
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type
|
||||
>
|
||||
synchronize(SV1& sv1, SV2& sv2)
|
||||
{
|
||||
boost::lock(sv1.mtx_, sv2.mtx_);
|
||||
typedef std::tuple<
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type
|
||||
> t_type;
|
||||
|
||||
return t_type(
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type(sv1.value_, sv1.mtx_, adopt_lock),
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type(sv2.value_, sv2.mtx_, adopt_lock)
|
||||
);
|
||||
|
||||
}
|
||||
template <typename SV1, typename SV2, typename SV3>
|
||||
std::tuple<
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV3>::type
|
||||
>
|
||||
synchronize(SV1& sv1, SV2& sv2, SV3& sv3)
|
||||
{
|
||||
boost::lock(sv1.mtx_, sv2.mtx_);
|
||||
typedef std::tuple<
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type,
|
||||
typename synchronized_value_strict_lock_ptr<SV3>::type
|
||||
> t_type;
|
||||
|
||||
return t_type(
|
||||
typename synchronized_value_strict_lock_ptr<SV1>::type(sv1.value_, sv1.mtx_, adopt_lock),
|
||||
typename synchronized_value_strict_lock_ptr<SV2>::type(sv2.value_, sv2.mtx_, adopt_lock),
|
||||
typename synchronized_value_strict_lock_ptr<SV3>::type(sv3.value_, sv3.mtx_, adopt_lock)
|
||||
);
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
@@ -26,7 +26,7 @@ namespace boost
|
||||
*
|
||||
* 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.
|
||||
* Sometimes it is needed to know if a method like is_locked 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.
|
||||
@@ -44,6 +44,8 @@ namespace boost
|
||||
/// Non copyable
|
||||
BOOST_THREAD_NO_COPYABLE(testable_mutex)
|
||||
|
||||
testable_mutex() : id_(thread::id()) {}
|
||||
|
||||
void lock()
|
||||
{
|
||||
mtx_.lock();
|
||||
@@ -52,7 +54,7 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_ASSERT(is_locked(mtx_));
|
||||
BOOST_ASSERT(is_locked_by_this_thread());
|
||||
id_ = thread::id();
|
||||
mtx_.unlock();
|
||||
}
|
||||
@@ -70,40 +72,44 @@ namespace boost
|
||||
}
|
||||
}
|
||||
#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;
|
||||
}
|
||||
}
|
||||
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()
|
||||
bool is_locked_by_this_thread() const
|
||||
{
|
||||
return this_thread::get_id() == id_;
|
||||
}
|
||||
bool is_locked() const
|
||||
{
|
||||
return ! (thread::id() == id_);
|
||||
}
|
||||
|
||||
bool get_id()
|
||||
thread::id get_id() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
@@ -9,22 +9,8 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread_data.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#endif
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/detail/thread_group.hpp>
|
||||
#include <boost/thread/v2/thread.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#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/thread/thread_only.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
|
||||
29
include/boost/thread/thread_only.hpp
Normal file
29
include/boost/thread/thread_only.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef BOOST_THREAD_THREAD_ONLY_HPP
|
||||
#define BOOST_THREAD_THREAD_ONLY_HPP
|
||||
|
||||
// thread.hpp
|
||||
//
|
||||
// (C) Copyright 2013 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)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread_data.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#endif
|
||||
#include <boost/thread/v2/thread.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
1062
include/boost/thread/v2/shared_mutex.hpp
Executable file
1062
include/boost/thread/v2/shared_mutex.hpp
Executable file
File diff suppressed because it is too large
Load Diff
@@ -68,11 +68,8 @@ namespace boost
|
||||
using namespace chrono;
|
||||
if (d > duration<Rep, Period>::zero())
|
||||
{
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
do
|
||||
{
|
||||
sleep_until(system_clock::now() + ceil<nanoseconds>(d));
|
||||
} while (steady_clock::now() - c_now < d );
|
||||
steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d);
|
||||
sleep_until(c_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,10 +93,13 @@ namespace boost
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
|
||||
bool const was_locked=(old_count&lock_flag_value) ? true : false;
|
||||
long const new_count=was_locked?(old_count+1):(old_count|lock_flag_value);
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
|
||||
if(current==old_count)
|
||||
{
|
||||
if(was_locked)
|
||||
old_count=new_count;
|
||||
break;
|
||||
}
|
||||
old_count=current;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -95,7 +95,7 @@ namespace boost
|
||||
detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
state_data state_={0};
|
||||
state_data state_={0,0,0,0,0,0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,11 @@ namespace boost
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
|
||||
#else
|
||||
BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
@@ -379,14 +383,20 @@ namespace boost
|
||||
|
||||
void lock()
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
#else
|
||||
BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
|
||||
#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
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
@@ -414,6 +424,7 @@ namespace boost
|
||||
}
|
||||
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
@@ -460,6 +471,7 @@ namespace boost
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
bool must_notify = false;
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
@@ -468,6 +480,7 @@ namespace boost
|
||||
if(!--new_state.exclusive_waiting)
|
||||
{
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
must_notify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,6 +490,11 @@ namespace boost
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if (must_notify)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
|
||||
}
|
||||
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
@@ -492,7 +510,7 @@ namespace boost
|
||||
BOOST_ASSERT(wait_res<2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
@@ -569,6 +587,7 @@ namespace boost
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
bool must_notify = false;
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
@@ -577,6 +596,7 @@ namespace boost
|
||||
if(!--new_state.exclusive_waiting)
|
||||
{
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
must_notify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -586,6 +606,10 @@ namespace boost
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if (must_notify)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
|
||||
}
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
@@ -725,9 +749,11 @@ namespace boost
|
||||
if(last_reader)
|
||||
{
|
||||
release_waiters(old_state);
|
||||
} else {
|
||||
release_waiters(old_state);
|
||||
}
|
||||
// #7720
|
||||
//else {
|
||||
// release_waiters(old_state);
|
||||
//}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace boost
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE timeout
|
||||
{
|
||||
unsigned long start;
|
||||
win32::ticks_type start;
|
||||
uintmax_t milliseconds;
|
||||
bool relative;
|
||||
boost::system_time abs_time;
|
||||
@@ -173,14 +173,14 @@ namespace boost
|
||||
static unsigned long const max_non_infinite_wait=0xfffffffe;
|
||||
|
||||
timeout(uintmax_t milliseconds_):
|
||||
start(win32::GetTickCount()),
|
||||
start(win32::GetTickCount64()),
|
||||
milliseconds(milliseconds_),
|
||||
relative(true),
|
||||
abs_time(boost::get_system_time())
|
||||
{}
|
||||
|
||||
timeout(boost::system_time const& abs_time_):
|
||||
start(win32::GetTickCount()),
|
||||
start(win32::GetTickCount64()),
|
||||
milliseconds(0),
|
||||
relative(false),
|
||||
abs_time(abs_time_)
|
||||
@@ -205,8 +205,8 @@ namespace boost
|
||||
}
|
||||
else if(relative)
|
||||
{
|
||||
unsigned long const now=win32::GetTickCount();
|
||||
unsigned long const elapsed=now-start;
|
||||
win32::ticks_type const now=win32::GetTickCount64();
|
||||
win32::ticks_type const elapsed=now-start;
|
||||
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
#define BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
@@ -26,6 +32,11 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
#ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
typedef unsigned long long ticks_type;
|
||||
#else
|
||||
typedef unsigned long ticks_type;
|
||||
#endif
|
||||
typedef ULONG_PTR ulong_ptr;
|
||||
typedef HANDLE handle;
|
||||
unsigned const infinite=INFINITE;
|
||||
@@ -61,6 +72,11 @@ namespace boost
|
||||
using ::Sleep;
|
||||
using ::QueueUserAPC;
|
||||
using ::GetTickCount;
|
||||
#ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
using ::GetTickCount64;
|
||||
#else
|
||||
inline ticks_type GetTickCount64() { return GetTickCount(); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,13 +104,18 @@ typedef void* HANDLE;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
#ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
typedef unsigned long long ticks_type;
|
||||
#else
|
||||
typedef unsigned long ticks_type;
|
||||
#endif
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
@@ -133,7 +154,9 @@ namespace boost
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
|
||||
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||
|
||||
# ifdef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
__declspec(dllimport) ticks_type __stdcall GetTickCount64();
|
||||
# endif
|
||||
# ifndef UNDER_CE
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
|
||||
@@ -150,6 +173,9 @@ namespace boost
|
||||
using ::ResetEvent;
|
||||
# endif
|
||||
}
|
||||
# ifndef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
inline ticks_type GetTickCount64() { return GetTickCount(); }
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,14 +48,16 @@ namespace boost
|
||||
}
|
||||
return std::string("unspecified future_errc value\n");
|
||||
}
|
||||
future_error_category future_error_category_var;
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL
|
||||
const system::error_category&
|
||||
future_category() BOOST_NOEXCEPT
|
||||
{
|
||||
static thread_detail::future_error_category f;
|
||||
return f;
|
||||
return thread_detail::future_error_category_var;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifdef BOOST_THREAD_ONCE_ATOMIC
|
||||
#include "./once_atomic.cpp"
|
||||
#else
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
@@ -13,9 +17,9 @@
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
namespace thread_detail
|
||||
{
|
||||
BOOST_THREAD_DECL thread_detail::uintmax_atomic_t once_global_epoch=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
|
||||
BOOST_THREAD_DECL uintmax_atomic_t once_global_epoch=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
|
||||
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
@@ -56,7 +60,7 @@ namespace boost
|
||||
#endif
|
||||
}
|
||||
|
||||
thread_detail::uintmax_atomic_t& get_once_per_thread_epoch()
|
||||
uintmax_atomic_t& get_once_per_thread_epoch()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
|
||||
void* data=pthread_getspecific(epoch_tss_key);
|
||||
@@ -71,3 +75,4 @@ namespace boost
|
||||
}
|
||||
|
||||
}
|
||||
#endif //
|
||||
|
||||
90
src/pthread/once_atomic.cpp
Normal file
90
src/pthread/once_atomic.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// (C) Copyright 2013 Andrey Semashev
|
||||
// (C) Copyright 2013 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)
|
||||
|
||||
//#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
enum flag_states
|
||||
{
|
||||
uninitialized, in_progress, initialized
|
||||
};
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(atomic_int_type) == sizeof(atomic_type), "Boost.Thread: unsupported platform");
|
||||
#endif
|
||||
|
||||
static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
atomic_type& f = get_atomic_storage(flag);
|
||||
if (f.load(memory_order_acquire) != initialized)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
if (f.load(memory_order_acquire) != initialized)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
atomic_int_type expected = uninitialized;
|
||||
if (f.compare_exchange_strong(expected, in_progress, memory_order_acq_rel, memory_order_acquire))
|
||||
{
|
||||
// We have set the flag to in_progress
|
||||
return true;
|
||||
}
|
||||
else if (expected == initialized)
|
||||
{
|
||||
// Another thread managed to complete the initialization
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait until the initialization is complete
|
||||
//pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_wait(&once_cv, &once_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
atomic_type& f = get_atomic_storage(flag);
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
f.store(initialized, memory_order_release);
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
atomic_type& f = get_atomic_storage(flag);
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
f.store(uninitialized, memory_order_release);
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
|
||||
}
|
||||
|
||||
} // namespace thread_detail
|
||||
|
||||
} // namespace boost
|
||||
@@ -6,10 +6,9 @@
|
||||
// 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 <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#endif
|
||||
@@ -436,7 +435,11 @@ namespace boost
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
# if defined(__IBMCPP__)
|
||||
BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
|
||||
# else
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# endif
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#endif
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
@@ -402,7 +402,8 @@ namespace boost
|
||||
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
SYSTEM_INFO info={{0}};
|
||||
//SYSTEM_INFO info={{0}};
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
@@ -425,7 +426,7 @@ namespace boost
|
||||
{
|
||||
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
|
||||
{
|
||||
LARGE_INTEGER due_time={{0}};
|
||||
LARGE_INTEGER due_time={{0,0}};
|
||||
if(target_time.relative)
|
||||
{
|
||||
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
|
||||
@@ -439,7 +440,7 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
SYSTEMTIME target_system_time={0};
|
||||
SYSTEMTIME target_system_time={0,0,0,0,0,0,0,0};
|
||||
target_system_time.wYear=target_time.abs_time.date().year();
|
||||
target_system_time.wMonth=target_time.abs_time.date().month();
|
||||
target_system_time.wDay=target_time.abs_time.date().day();
|
||||
@@ -748,4 +749,3 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
110
test/Jamfile.v2
110
test/Jamfile.v2
@@ -31,12 +31,18 @@ project
|
||||
<toolset>gcc:<cxxflags>-Wno-long-long
|
||||
#<toolset>gcc:<cxxflags>-ansi
|
||||
#<toolset>gcc:<cxxflags>-fpermissive
|
||||
<toolset>gcc:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>gcc:<cxxflags>-Wunused-local-typedefs
|
||||
<toolset>gcc:<cxxflags>-Wunused-function
|
||||
|
||||
<toolset>darwin:<cxxflags>-Wextra
|
||||
<toolset>darwin:<cxxflags>-pedantic
|
||||
<toolset>darwin:<cxxflags>-Wno-long-long
|
||||
#<toolset>darwin:<cxxflags>-ansi # doesn't work for 4.1.2
|
||||
<toolset>darwin:<cxxflags>-fpermissive
|
||||
<toolset>darwin:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>darwin:<cxxflags>-Wunused-local-typedefs
|
||||
<toolset>darwin:<cxxflags>-Wunused-function
|
||||
|
||||
#<toolset>pathscale:<cxxflags>-Wextra
|
||||
<toolset>pathscale:<cxxflags>-Wno-long-long
|
||||
@@ -47,6 +53,7 @@ project
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive # doesn't work
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
|
||||
<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
@@ -127,7 +134,7 @@ rule thread-run2-noit ( sources : name )
|
||||
: : :
|
||||
: $(name)_lib ]
|
||||
#[ run $(sources) ../build//boost_thread : : :
|
||||
# <define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
# <define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
# : $(name)_noit ]
|
||||
;
|
||||
}
|
||||
@@ -141,7 +148,7 @@ rule thread-run2-noit-pthread ( sources : name )
|
||||
: : : <threadapi>win32:<build>no
|
||||
: $(name)_lib ]
|
||||
#[ run $(sources) ../build//boost_thread : : :
|
||||
# <define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
# <define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
# : $(name)_noit ]
|
||||
;
|
||||
}
|
||||
@@ -149,10 +156,10 @@ rule thread-run2-noit-pthread ( sources : name )
|
||||
rule thread-run2-h ( sources : name )
|
||||
{
|
||||
return
|
||||
[ run $(sources) : : :
|
||||
[ run $(sources) : : :
|
||||
<library>/boost/system//boost_system
|
||||
<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
<define>BOOST_THREAD_VERSION=3
|
||||
<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
<define>BOOST_THREAD_VERSION=3
|
||||
: $(name)_h ]
|
||||
;
|
||||
}
|
||||
@@ -177,6 +184,15 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
;
|
||||
}
|
||||
|
||||
rule thread-compile ( sources : reqs * : name )
|
||||
{
|
||||
return
|
||||
[ compile $(sources)
|
||||
: $(reqs)
|
||||
: $(name) ]
|
||||
;
|
||||
}
|
||||
|
||||
{
|
||||
test-suite t_threads
|
||||
:
|
||||
@@ -204,9 +220,11 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
[ thread-test test_condition_notify_all.cpp ]
|
||||
[ thread-test test_condition.cpp ]
|
||||
[ thread-test test_once.cpp ]
|
||||
[ thread-test test_barrier.cpp ]
|
||||
[ thread-run test_barrier.cpp ]
|
||||
[ thread-test test_lock_concept.cpp ]
|
||||
[ thread-test test_generic_locks.cpp ]
|
||||
[ thread-run test_latch.cpp ]
|
||||
[ thread-run test_completion_latch.cpp ]
|
||||
;
|
||||
|
||||
test-suite t_shared
|
||||
@@ -327,7 +345,10 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/futures/future/move_ctor_pass.cpp : future__move_ctor_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/move_assign_pass.cpp : future__move_asign_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/share_pass.cpp : future__share_p ]
|
||||
#[ thread-run2-noit ./sync/futures/future/then_pass.cpp : future__then_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/wait_pass.cpp : future__wait_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/wait_for_pass.cpp : future__wait_for_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/wait_until_pass.cpp : future__wait_until_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/then_pass.cpp : future__then_p ]
|
||||
;
|
||||
|
||||
#explicit ts_shared_future ;
|
||||
@@ -340,6 +361,9 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/futures/shared_future/get_pass.cpp : shared_future__get_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/move_ctor_pass.cpp : shared_future__move_ctor_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/move_assign_pass.cpp : shared_future__move_asign_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/wait_pass.cpp : shared_future__wait_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/wait_for_pass.cpp : shared_future__wait_for_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/wait_until_pass.cpp : shared_future__wait_until_p ]
|
||||
;
|
||||
|
||||
#explicit ts_packaged_task ;
|
||||
@@ -509,6 +533,15 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
;
|
||||
|
||||
|
||||
#explicit ts_once ;
|
||||
test-suite ts_once
|
||||
:
|
||||
#[ thread-compile-fail ./sync/mutual_exclusion/once/once_flag/assign_fail.cpp : : once_flag__assign_f ]
|
||||
#[ thread-compile-fail ./sync/mutual_exclusion/once/once_flag/copy_fail.cpp : : once_flag__copy_f ]
|
||||
#[ thread-run2-noit ./sync/mutual_exclusion/once/once_flag/default_pass.cpp : once_flag__default_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/once/call_once/call_once_pass.cpp : call_once_p ]
|
||||
;
|
||||
|
||||
#explicit ts_mutex ;
|
||||
test-suite ts_mutex
|
||||
:
|
||||
@@ -571,6 +604,19 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
#[ thread-run2-h ./sync/mutual_exclusion/shared_mutex/default_pass.cpp : shared_mutex__default_p ]
|
||||
;
|
||||
|
||||
#explicit ts_null_mutex ;
|
||||
test-suite ts_null_mutex
|
||||
:
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/null_mutex/assign_fail.cpp : : null_mutex__assign_f ]
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/null_mutex/copy_fail.cpp : : null_mutex__copy_f ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/null_mutex/default_pass.cpp : null_mutex__default_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/null_mutex/lock_pass.cpp : null_mutex__lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/null_mutex/try_lock_for_pass.cpp : null_mutex__try_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/null_mutex/try_lock_pass.cpp : null_mutex__try_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/null_mutex/try_lock_until_pass.cpp : null_mutex__try_lock_until_p ]
|
||||
;
|
||||
|
||||
|
||||
#explicit ts_this_thread ;
|
||||
test-suite ts_this_thread
|
||||
:
|
||||
@@ -586,6 +632,7 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./threads/thread/assign/move_pass.cpp : thread__assign__move_p ]
|
||||
[ thread-compile-fail ./threads/thread/constr/copy_fail.cpp : : thread__constr__copy_f ]
|
||||
[ thread-run2-noit ./threads/thread/constr/default_pass.cpp : thread__constr__default_p ]
|
||||
[ thread-run-lib2 ./threads/thread/constr/lambda_pass.cpp : thread__constr__lambda_p ]
|
||||
[ thread-run-lib2 ./threads/thread/constr/F_pass.cpp : thread__constr__F_p ]
|
||||
[ thread-run-lib2 ./threads/thread/constr/FArgs_pass.cpp : thread__constr__FArgs_p ]
|
||||
[ thread-run2-noit ./threads/thread/constr/Frvalue_pass.cpp : thread__constr__Frvalue_p ]
|
||||
@@ -616,28 +663,32 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
test-suite ts_examples
|
||||
:
|
||||
[ thread-run2-noit ../example/monitor.cpp : ex_monitor ]
|
||||
[ compile ../example/starvephil.cpp ]
|
||||
#[ compile ../example/tennis.cpp ]
|
||||
[ compile ../example/condition.cpp ]
|
||||
[ thread-compile ../example/starvephil.cpp : : ex_starvephil ]
|
||||
[ thread-run2 ../example/tennis.cpp : ex_tennis ]
|
||||
[ thread-compile ../example/condition.cpp : : ex_condition ]
|
||||
[ thread-run2-noit ../example/mutex.cpp : ex_mutex ]
|
||||
[ thread-run2-noit ../example/once.cpp : ex_once ]
|
||||
[ thread-run2-noit ../example/recursive_mutex.cpp : ex_recursive_mutex ]
|
||||
[ thread-run2-noit ../example/thread.cpp : ex_thread ]
|
||||
[ thread-run2-noit ../example/thread_group.cpp : ex_thread_group ]
|
||||
[ thread-run2-noit ../example/tss.cpp : ex_tss ]
|
||||
[ thread-run ../example/xtime.cpp ]
|
||||
[ thread-run ../example/shared_monitor.cpp ]
|
||||
[ thread-run ../example/shared_mutex.cpp ]
|
||||
[ thread-run2 ../example/xtime.cpp : ex_xtime ]
|
||||
[ thread-run2 ../example/shared_monitor.cpp : ex_shared_monitor ]
|
||||
[ thread-run2 ../example/shared_mutex.cpp : ex_shared_mutex ]
|
||||
#[ thread-run ../example/vhh_shared_monitor.cpp ]
|
||||
#[ thread-run ../example/vhh_shared_mutex.cpp ]
|
||||
[ thread-run ../example/make_future.cpp ]
|
||||
#[ thread-run ../example/future_then.cpp ]
|
||||
[ thread-run2 ../example/make_future.cpp : ex_make_future ]
|
||||
[ thread-run2 ../example/future_then.cpp : ex_future_then ]
|
||||
#[ thread-run2-noit ../example/synchronized_value.cpp : ex_synchronized_value ]
|
||||
#[ thread-run2-noit ../example/synchronized_person.cpp : ex_synchronized_person ]
|
||||
[ thread-run2-noit ../example/thread_guard.cpp : ex_thread_guard ]
|
||||
[ thread-run2-noit ../example/scoped_thread.cpp : ex_scoped_thread ]
|
||||
[ thread-run2-noit ../example/strict_lock.cpp : ex_strict_lock ]
|
||||
[ thread-run2-noit ../example/ba_externallly_locked.cpp : ex_ba_externallly_locked ]
|
||||
[ thread-run2 ../example/producer_consumer_bounded.cpp : ex_producer_consumer_bounded ]
|
||||
[ thread-run2 ../example/producer_consumer.cpp : ex_producer_consumer ]
|
||||
[ thread-run2 ../example/not_interleaved.cpp : ex_not_interleaved ]
|
||||
[ thread-run2 ../example/lambda_future.cpp : ex_lambda_future ]
|
||||
|
||||
;
|
||||
|
||||
@@ -673,20 +724,41 @@ rule thread-compile-fail ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/reverse_lock/types_pass.cpp : reverse_lock__types_p ]
|
||||
;
|
||||
|
||||
|
||||
#explicit ts_synchronized_value ;
|
||||
test-suite ts_synchronized_value
|
||||
:
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/copy_assign_pass.cpp : synchronized_value__copy_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/copy_ctor_pass.cpp : synchronized_value__copy_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/copy_T_assign_pass.cpp : synchronized_value__copy_T_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/copy_T_ctor_pass.cpp : synchronized_value__copy_T_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/default_ctor_pass.cpp : synchronized_value__default_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/indirect_pass.cpp : synchronized_value__indirect_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/move_assign_pass.cpp : synchronized_value__move_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/move_ctor_pass.cpp : synchronized_value__move_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/move_T_assign_pass.cpp : synchronized_value__move_T_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/move_T_ctor_pass.cpp : synchronized_value__move_T_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/swap_pass.cpp : synchronized_value__swap_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/swap_T_pass.cpp : synchronized_value__swap_T_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/synchronize_pass.cpp : synchronized_value__synchronize_p ]
|
||||
|
||||
;
|
||||
|
||||
explicit ts_ ;
|
||||
test-suite ts_
|
||||
:
|
||||
|
||||
#[ thread-run2-noit ./sync/futures/future/then_pass.cpp : future__then_p ]
|
||||
#[ thread-run ../example/test_so.cpp ]
|
||||
#[ thread-run ../example/test_so2.cpp ]
|
||||
|
||||
#[ compile virtual_noexcept.cpp ]
|
||||
#[ thread-run test_7665.cpp ]
|
||||
#[ thread-run test_7720.cpp ]
|
||||
#[ thread-run test_7666.cpp ]
|
||||
#[ thread-run test_7755.cpp ]
|
||||
#[ thread-run ../example/unwrap.cpp ]
|
||||
[ thread-run ../example/perf_condition_variable.cpp ]
|
||||
#[ thread-run ../example/not_interleaved.cpp ]
|
||||
#[ thread-run ../example/perf_condition_variable.cpp ]
|
||||
#[ thread-run ../example/perf_shared_mutex.cpp ]
|
||||
#[ thread-run ../example/std_async_test.cpp ]
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
@@ -56,20 +57,40 @@ class MoveOnly
|
||||
public:
|
||||
typedef int result_type;
|
||||
|
||||
int value;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
|
||||
MoveOnly()
|
||||
{
|
||||
value=0;
|
||||
}
|
||||
MoveOnly(BOOST_THREAD_RV_REF(MoveOnly))
|
||||
{}
|
||||
{
|
||||
value=1;
|
||||
}
|
||||
MoveOnly& operator=(BOOST_THREAD_RV_REF(MoveOnly))
|
||||
{
|
||||
value=2;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
return 3;
|
||||
}
|
||||
template <typename OS>
|
||||
friend OS& operator<<(OS& os, MoveOnly const& v)
|
||||
{
|
||||
os << v.value;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost {
|
||||
BOOST_THREAD_DCL_MOVABLE(MoveOnly)
|
||||
}
|
||||
|
||||
int f0()
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
@@ -89,6 +110,19 @@ void f2()
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
}
|
||||
|
||||
boost::interprocess::unique_ptr<int, boost::default_delete<int> > f3_0()
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
boost::interprocess::unique_ptr<int, boost::default_delete<int> > r((new int(3)));
|
||||
return boost::move(r);
|
||||
}
|
||||
MoveOnly f3_1()
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
MoveOnly r;
|
||||
return boost::move(r);
|
||||
}
|
||||
|
||||
boost::interprocess::unique_ptr<int, boost::default_delete<int> > f3(int i)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
@@ -113,8 +147,7 @@ int main()
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(f.get() == 3);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
BOOST_TEST(t1 - t0 < ms(300));
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
@@ -164,12 +197,12 @@ int main()
|
||||
{
|
||||
try {
|
||||
boost::future<int> f = boost::async(boost::launch::async, BOOST_THREAD_MAKE_RV_REF(MoveOnly()));
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(f.get() == 3);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
// boost::this_thread::sleep_for(ms(300));
|
||||
// Clock::time_point t0 = Clock::now();
|
||||
// BOOST_TEST(f.get() == 3);
|
||||
// Clock::time_point t1 = Clock::now();
|
||||
// BOOST_TEST(t1 - t0 < ms(200));
|
||||
// std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
@@ -285,15 +318,10 @@ int main()
|
||||
{
|
||||
try {
|
||||
boost::future<void> f = boost::async(f2);
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
Clock::time_point t0 = Clock::now();
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
f.get();
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
Clock::time_point t1 = Clock::now();
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
} catch (std::exception& ex) {
|
||||
@@ -356,8 +384,59 @@ int main()
|
||||
}
|
||||
#endif
|
||||
|
||||
// todo fixme
|
||||
#if 0 && defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
boost::future<MoveOnly> f = boost::async(&f3_1);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(f.get().value == 1);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
} catch (...) {
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
boost::future<MoveOnly> f;
|
||||
f = boost::async(&f3_1);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(f.get().value == 1);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
} catch (...) {
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
boost::future<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > f = boost::async(&f3_0);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(*f.get() == 3);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
} catch (...) {
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
@@ -375,10 +454,44 @@ int main()
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
boost::future<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > f = boost::async(&f3, 3);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(*f.get() == 3);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
} catch (...) {
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// todo fixme
|
||||
#if 0 && defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
boost::future<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > f = boost::async(boost::launch::async, &f4, boost::interprocess::unique_ptr<int, boost::default_delete<int> >(new int(3)));
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
Clock::time_point t0 = Clock::now();
|
||||
BOOST_TEST(*f.get() == 3);
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(t1 - t0 < ms(200));
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"] "<< (t1 - t0).count() << std::endl;
|
||||
} catch (std::exception& ex) {
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
} catch (...) {
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try {
|
||||
boost::future<boost::interprocess::unique_ptr<int, boost::default_delete<int> > > f = boost::async(&f4, boost::interprocess::unique_ptr<int, boost::default_delete<int> >(new int(3)));
|
||||
|
||||
@@ -93,20 +93,20 @@ int main()
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
typedef int T;
|
||||
// {
|
||||
// boost::promise<T> p;
|
||||
// boost::future<T> f = p.get_future();
|
||||
//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
// boost::thread(func1, boost::move(p)).detach();
|
||||
//#else
|
||||
// p.set_value(3);
|
||||
//#endif
|
||||
// BOOST_TEST(f.valid());
|
||||
// BOOST_TEST(f.get() == 3);
|
||||
//#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
|
||||
// BOOST_TEST(!f.valid());
|
||||
//#endif
|
||||
// }
|
||||
{
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func1, boost::move(p)).detach();
|
||||
#else
|
||||
p.set_value(3);
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(f.get() == 3);
|
||||
#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
|
||||
BOOST_TEST(!f.valid());
|
||||
#endif
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::promise<T> p;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2011 Vicente J. Botet Escriba
|
||||
// Copyright (C) 2012-2013 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)
|
||||
@@ -11,8 +11,7 @@
|
||||
// auto then(F&& func) -> future<decltype(func(*this))>;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
@@ -23,61 +22,68 @@
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int p2(boost::future<int>& f)
|
||||
{
|
||||
return 2 * f.get();
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
return 2 * i;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, p1);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.then(p2);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f2.get()==2);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
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::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
BOOST_TEST(f2.valid());
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
// {
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// boost::future<int> f2 = boost::async(p1).then(p2);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// BOOST_TEST(f2.get()==2);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// }
|
||||
// {
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// boost::future<int> f1 = boost::async(p1);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// boost::future<int> f2 = f1.then(p2).then(p2);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// BOOST_TEST(f2.get()==4);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// }
|
||||
// {
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// boost::future<int> f2 = boost::async(p1).then(p2).then(p2);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// BOOST_TEST(f2.get()==4);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
// }
|
||||
{
|
||||
boost::future<int> f2 = boost::async(p1).then(&p2);
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
boost::future<int> f21 = f1.then(&p2);
|
||||
boost::future<int> f2= f21.then(&p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
boost::future<int> f2= f1.then(&p2).then(&p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f2 = boost::async(p1).then(&p2).then(&p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
163
test/sync/futures/future/wait_for_pass.cpp
Normal file
163
test/sync/futures/future/wait_for_pass.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class future<R>
|
||||
|
||||
// template <class Rep, class Period>
|
||||
// future_status
|
||||
// wait_for(const chrono::duration<Rep, Period>& rel_time) const;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
|
||||
typedef boost::chrono::milliseconds ms;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os , boost::future_status st )
|
||||
{
|
||||
os << int(st) << " ";
|
||||
return os;
|
||||
}
|
||||
template <typename T>
|
||||
struct wrap
|
||||
{
|
||||
wrap(T const& v) :
|
||||
value(v)
|
||||
{
|
||||
}
|
||||
T value;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
exception_ptr make_exception_ptr(T v)
|
||||
{
|
||||
return copy_exception(wrap<T> (v));
|
||||
}
|
||||
}
|
||||
|
||||
void func1(boost::promise<int> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value(3);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
void func3(boost::promise<int&> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
j = 5;
|
||||
p.set_value(j);
|
||||
}
|
||||
|
||||
void func5(boost::promise<void> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
{
|
||||
typedef int T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func1, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::timeout);
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func1(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef int& T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func3, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::timeout);
|
||||
BOOST_TEST(f.valid());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func3(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef void T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func5, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::timeout);
|
||||
BOOST_TEST(f.valid());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func5(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
|
||||
#endif
|
||||
151
test/sync/futures/future/wait_pass.cpp
Normal file
151
test/sync/futures/future/wait_pass.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class future<R>
|
||||
|
||||
// template <class Rep, class Period>
|
||||
// void wait() const;
|
||||
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
|
||||
typedef boost::chrono::milliseconds ms;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os , boost::future_status st )
|
||||
{
|
||||
os << int(st) << " ";
|
||||
return os;
|
||||
}
|
||||
template <typename T>
|
||||
struct wrap
|
||||
{
|
||||
wrap(T const& v) :
|
||||
value(v)
|
||||
{
|
||||
}
|
||||
T value;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
exception_ptr make_exception_ptr(T v)
|
||||
{
|
||||
return copy_exception(wrap<T> (v));
|
||||
}
|
||||
}
|
||||
|
||||
void func1(boost::promise<int> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value(3);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
void func3(boost::promise<int&> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
j = 5;
|
||||
p.set_value(j);
|
||||
}
|
||||
|
||||
void func5(boost::promise<void> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
{
|
||||
typedef int T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func1, boost::move(p)).detach();
|
||||
#else
|
||||
func1(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
f.wait();
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef int& T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func3, boost::move(p)).detach();
|
||||
#else
|
||||
func3(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
f.wait();
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef void T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func5, boost::move(p)).detach();
|
||||
#else
|
||||
func5(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
f.wait();
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
|
||||
#endif
|
||||
164
test/sync/futures/future/wait_until_pass.cpp
Normal file
164
test/sync/futures/future/wait_until_pass.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class future<R>
|
||||
|
||||
// template <class Rep, class Period>
|
||||
// future_status
|
||||
// wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
|
||||
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
|
||||
typedef boost::chrono::milliseconds ms;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os , boost::future_status st )
|
||||
{
|
||||
os << int(st) << " ";
|
||||
return os;
|
||||
}
|
||||
template <typename T>
|
||||
struct wrap
|
||||
{
|
||||
wrap(T const& v) :
|
||||
value(v)
|
||||
{
|
||||
}
|
||||
T value;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
exception_ptr make_exception_ptr(T v)
|
||||
{
|
||||
return copy_exception(wrap<T> (v));
|
||||
}
|
||||
}
|
||||
|
||||
void func1(boost::promise<int> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value(3);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
void func3(boost::promise<int&> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
j = 5;
|
||||
p.set_value(j);
|
||||
}
|
||||
|
||||
void func5(boost::promise<void> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
{
|
||||
typedef int T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func1, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_until(Clock::now() + ms(300)) , boost::future_status::timeout);
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func1(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_until(Clock::now() + ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef int& T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func3, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_until(Clock::now() + ms(300)) , boost::future_status::timeout);
|
||||
BOOST_TEST(f.valid());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func3(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST_EQ(f.wait_until(Clock::now() + ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef void T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func5, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_until(Clock::now() + ms(300)) , boost::future_status::timeout);
|
||||
BOOST_TEST(f.valid());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func5(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST_EQ(f.wait_until(Clock::now() + ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
|
||||
#endif
|
||||
@@ -54,24 +54,43 @@ long lfct()
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
long data_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(A)
|
||||
static int n_moves;
|
||||
static int n_copies;
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(A)
|
||||
static void reset()
|
||||
{
|
||||
n_moves=0;
|
||||
n_copies=0;
|
||||
}
|
||||
|
||||
explicit A(long i) : data_(i)
|
||||
{
|
||||
}
|
||||
A(BOOST_THREAD_RV_REF(A) a) : data_(BOOST_THREAD_RV(a).data_)
|
||||
{
|
||||
++n_moves; BOOST_THREAD_RV(a).data_ = -1;
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
}
|
||||
A& operator=(BOOST_THREAD_RV_REF(A) a)
|
||||
{
|
||||
data_ = BOOST_THREAD_RV(a).data_;
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
return *this;
|
||||
}
|
||||
A(const A& a) : data_(a.data_)
|
||||
{
|
||||
++n_copies;
|
||||
}
|
||||
A& operator=(A const& a)
|
||||
{
|
||||
data_ = a.data_;
|
||||
++n_copies;
|
||||
return *this;
|
||||
}
|
||||
~A()
|
||||
{
|
||||
}
|
||||
@@ -85,6 +104,78 @@ public:
|
||||
int A::n_moves = 0;
|
||||
int A::n_copies = 0;
|
||||
|
||||
class M
|
||||
{
|
||||
|
||||
public:
|
||||
long data_;
|
||||
static int n_moves;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(M)
|
||||
static void reset() {
|
||||
n_moves=0;
|
||||
}
|
||||
explicit M(long i) : data_(i)
|
||||
{
|
||||
}
|
||||
M(BOOST_THREAD_RV_REF(M) a) : data_(BOOST_THREAD_RV(a).data_)
|
||||
{
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
}
|
||||
M& operator=(BOOST_THREAD_RV_REF(M) a)
|
||||
{
|
||||
data_ = BOOST_THREAD_RV(a).data_;
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
return *this;
|
||||
}
|
||||
~M()
|
||||
{
|
||||
}
|
||||
|
||||
long operator()() const
|
||||
{ return data_;}
|
||||
long operator()(long i, long j) const
|
||||
{ return data_ + i + j;}
|
||||
};
|
||||
|
||||
int M::n_moves = 0;
|
||||
|
||||
class C
|
||||
{
|
||||
public:
|
||||
long data_;
|
||||
|
||||
static int n_copies;
|
||||
static void reset()
|
||||
{
|
||||
n_copies=0;
|
||||
}
|
||||
|
||||
explicit C(long i) : data_(i)
|
||||
{
|
||||
}
|
||||
C(const C& a) : data_(a.data_)
|
||||
{
|
||||
++n_copies;
|
||||
}
|
||||
C& operator=(C const& a)
|
||||
{
|
||||
data_ = a.data_;
|
||||
++n_copies;
|
||||
return *this;
|
||||
}
|
||||
~C()
|
||||
{
|
||||
}
|
||||
|
||||
long operator()() const
|
||||
{ return data_;}
|
||||
long operator()(long i, long j) const
|
||||
{ return data_ + i + j;}
|
||||
};
|
||||
int C::n_copies = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -99,11 +190,10 @@ int main()
|
||||
#endif
|
||||
BOOST_TEST(f.get() == BOOST_THREAD_DETAIL_SIGNATURE_2_RES);
|
||||
BOOST_TEST(A::n_copies == 0);
|
||||
BOOST_TEST(A::n_moves > 0);
|
||||
BOOST_TEST_EQ(A::n_moves, 1);
|
||||
}
|
||||
A::n_copies = 0;
|
||||
A::n_moves = 0;
|
||||
{
|
||||
A::reset();
|
||||
A a(5);
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE> p(a);
|
||||
BOOST_TEST(p.valid());
|
||||
@@ -111,13 +201,12 @@ int main()
|
||||
//p(3, 'a');
|
||||
p();
|
||||
BOOST_TEST(f.get() == 5.0);
|
||||
//BOOST_TEST(A::n_copies > 0);
|
||||
//BOOST_TEST(A::n_moves > 0);
|
||||
BOOST_TEST_EQ(A::n_copies, 1);
|
||||
BOOST_TEST_EQ(A::n_moves, 0);
|
||||
}
|
||||
|
||||
A::n_copies = 0;
|
||||
A::n_moves = 0;
|
||||
{
|
||||
A::reset();
|
||||
const A a(5);
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE> p(a);
|
||||
BOOST_TEST(p.valid());
|
||||
@@ -125,8 +214,56 @@ int main()
|
||||
//p(3, 'a');
|
||||
p();
|
||||
BOOST_TEST(f.get() == 5.0);
|
||||
//BOOST_TEST(A::n_copies > 0);
|
||||
//BOOST_TEST(A::n_moves > 0);
|
||||
BOOST_TEST_EQ(A::n_copies, 1);
|
||||
BOOST_TEST_EQ(A::n_moves, 0);
|
||||
}
|
||||
{
|
||||
M::reset();
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE_2> p(BOOST_THREAD_MAKE_RV_REF(M(5)));
|
||||
BOOST_TEST(p.valid());
|
||||
boost::future<double> f = BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
p(3, 'a');
|
||||
#else
|
||||
p();
|
||||
#endif
|
||||
BOOST_TEST(f.get() == BOOST_THREAD_DETAIL_SIGNATURE_2_RES);
|
||||
BOOST_TEST_EQ(M::n_moves, 1);
|
||||
}
|
||||
{
|
||||
M::reset();
|
||||
M a(5);
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE> p(boost::move(a));
|
||||
BOOST_TEST(p.valid());
|
||||
boost::future<double> f = BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
||||
//p(3, 'a');
|
||||
p();
|
||||
BOOST_TEST(f.get() == 5.0);
|
||||
BOOST_TEST_EQ(M::n_moves, 1);
|
||||
}
|
||||
|
||||
{
|
||||
C::reset();
|
||||
C a(5);
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE> p(a);
|
||||
BOOST_TEST(p.valid());
|
||||
boost::future<double> f = BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
||||
//p(3, 'a');
|
||||
p();
|
||||
BOOST_TEST(f.get() == 5.0);
|
||||
BOOST_TEST_EQ(C::n_copies, 1);
|
||||
}
|
||||
|
||||
{
|
||||
C::reset();
|
||||
const C a(5);
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE> p(a);
|
||||
BOOST_TEST(p.valid());
|
||||
boost::future<double> f = BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
||||
//p(3, 'a');
|
||||
p();
|
||||
BOOST_TEST(f.get() == 5.0);
|
||||
BOOST_TEST_EQ(C::n_copies, 1);
|
||||
}
|
||||
{
|
||||
boost::packaged_task<BOOST_THREAD_DETAIL_SIGNATURE> p(fct);
|
||||
|
||||
@@ -57,12 +57,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void func0_mv(BOOST_THREAD_RV_REF(boost::packaged_task<double(int, char)>) p)
|
||||
//void func0(boost::packaged_task<double(int, char)> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
p.make_ready_at_thread_exit(3, 'a');
|
||||
}
|
||||
void func0(boost::packaged_task<double(int, char)> *p)
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
p->make_ready_at_thread_exit(3, 'a');
|
||||
}
|
||||
|
||||
void func1(boost::packaged_task<double(int, char)> *p)
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
@@ -99,8 +104,11 @@ int main()
|
||||
{
|
||||
boost::packaged_task<double(int, char)> p(A(5));
|
||||
boost::future<double> f = p.get_future();
|
||||
// fixme BUG boost::thread(func0, boost::move(p)).detach();
|
||||
#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD
|
||||
boost::thread(func0_mv, boost::move(p)).detach();
|
||||
#else
|
||||
boost::thread(func0, &p).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.get() == 105.0);
|
||||
}
|
||||
{
|
||||
|
||||
@@ -19,11 +19,8 @@
|
||||
// void promise<void>::set_value_at_thread_exit();
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
int i = 0;
|
||||
@@ -35,12 +32,17 @@ void func()
|
||||
i = 1;
|
||||
}
|
||||
|
||||
void func2(boost::promise<void> p2)
|
||||
void func2_mv(BOOST_THREAD_RV_REF(boost::promise<void>) p2)
|
||||
{
|
||||
p2.set_value_at_thread_exit();
|
||||
i = 2;
|
||||
}
|
||||
|
||||
void func2(boost::promise<void> *p2)
|
||||
{
|
||||
p2->set_value_at_thread_exit();
|
||||
i = 2;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
try
|
||||
@@ -51,7 +53,7 @@ int main()
|
||||
BOOST_TEST(i == 1);
|
||||
|
||||
}
|
||||
catch(std::exception ex)
|
||||
catch(std::exception& ex)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
@@ -70,7 +72,29 @@ int main()
|
||||
BOOST_TEST(i == 1);
|
||||
|
||||
}
|
||||
catch(std::exception ex)
|
||||
catch(std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " " << ex.what() << std::endl;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
boost::promise<void> p2;
|
||||
boost::future<void> f = p2.get_future();
|
||||
#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD
|
||||
boost::thread(func2_mv, boost::move(p2)).detach();
|
||||
#else
|
||||
boost::thread(func2, &p2).detach();
|
||||
#endif
|
||||
f.wait();
|
||||
BOOST_TEST(i == 2);
|
||||
}
|
||||
catch(std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " " << ex.what() << std::endl;
|
||||
BOOST_TEST(false);
|
||||
@@ -79,31 +103,6 @@ int main()
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
// BUG when moving promise. fixme
|
||||
// try
|
||||
// {
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
// boost::promise<void> p2; // BUG
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
// boost::future<void> f = p2.get_future();
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
// boost::thread(func2, boost::move(p2)).detach(); // BUG
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
// f.get();
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
// BOOST_TEST(i == 2);
|
||||
// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
//
|
||||
// }
|
||||
// catch(std::exception ex)
|
||||
// {
|
||||
// std::cout << __FILE__ << ":" << __LINE__ << " " << ex.what() << std::endl;
|
||||
// BOOST_TEST(false);
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// BOOST_TEST(false);
|
||||
// }
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
163
test/sync/futures/shared_future/wait_for_pass.cpp
Normal file
163
test/sync/futures/shared_future/wait_for_pass.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class shared_future<R>
|
||||
|
||||
// template <class Rep, class Period>
|
||||
// future_status
|
||||
// wait_for(const chrono::duration<Rep, Period>& rel_time) const;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
|
||||
typedef boost::chrono::milliseconds ms;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os , boost::future_status st )
|
||||
{
|
||||
os << int(st) << " ";
|
||||
return os;
|
||||
}
|
||||
template <typename T>
|
||||
struct wrap
|
||||
{
|
||||
wrap(T const& v) :
|
||||
value(v)
|
||||
{
|
||||
}
|
||||
T value;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
exception_ptr make_exception_ptr(T v)
|
||||
{
|
||||
return copy_exception(wrap<T> (v));
|
||||
}
|
||||
}
|
||||
|
||||
void func1(boost::promise<int> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value(3);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
void func3(boost::promise<int&> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
j = 5;
|
||||
p.set_value(j);
|
||||
}
|
||||
|
||||
void func5(boost::promise<void> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
{
|
||||
typedef int T;
|
||||
boost::promise<T> p;
|
||||
boost::shared_future<T> f((p.get_future()));
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func1, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::timeout);
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func1(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef int& T;
|
||||
boost::promise<T> p;
|
||||
boost::shared_future<T> f((p.get_future()));
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func3, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::timeout);
|
||||
BOOST_TEST(f.valid());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func3(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef void T;
|
||||
boost::promise<T> p;
|
||||
boost::shared_future<T> f((p.get_future()));
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func5, boost::move(p)).detach();
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::timeout);
|
||||
BOOST_TEST(f.valid());
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
func5(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST_EQ(f.wait_for(ms(300)) , boost::future_status::ready);
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
|
||||
#endif
|
||||
151
test/sync/futures/shared_future/wait_pass.cpp
Normal file
151
test/sync/futures/shared_future/wait_pass.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Copyright (C) 2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class shared_future<R>
|
||||
|
||||
// template <class Rep, class Period>
|
||||
// void wait() const;
|
||||
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
|
||||
typedef boost::chrono::milliseconds ms;
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os , boost::future_status st )
|
||||
{
|
||||
os << int(st) << " ";
|
||||
return os;
|
||||
}
|
||||
template <typename T>
|
||||
struct wrap
|
||||
{
|
||||
wrap(T const& v) :
|
||||
value(v)
|
||||
{
|
||||
}
|
||||
T value;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
exception_ptr make_exception_ptr(T v)
|
||||
{
|
||||
return copy_exception(wrap<T> (v));
|
||||
}
|
||||
}
|
||||
|
||||
void func1(boost::promise<int> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value(3);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
||||
void func3(boost::promise<int&> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
j = 5;
|
||||
p.set_value(j);
|
||||
}
|
||||
|
||||
void func5(boost::promise<void> p)
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(500));
|
||||
p.set_value();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
{
|
||||
typedef int T;
|
||||
boost::promise<T> p;
|
||||
boost::shared_future<T> f((p.get_future()));
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func1, boost::move(p)).detach();
|
||||
#else
|
||||
func1(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
f.wait();
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef int& T;
|
||||
boost::promise<T> p;
|
||||
boost::shared_future<T> f((p.get_future()));
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func3, boost::move(p)).detach();
|
||||
#else
|
||||
func3(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
f.wait();
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
{
|
||||
typedef void T;
|
||||
boost::promise<T> p;
|
||||
boost::shared_future<T> f((p.get_future()));
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func5, boost::move(p)).detach();
|
||||
#else
|
||||
func5(boost::move(p));
|
||||
#endif
|
||||
BOOST_TEST(f.valid());
|
||||
f.wait();
|
||||
BOOST_TEST(f.valid());
|
||||
Clock::time_point t0 = Clock::now();
|
||||
f.wait();
|
||||
Clock::time_point t1 = Clock::now();
|
||||
BOOST_TEST(f.valid());
|
||||
BOOST_TEST(t1 - t0 < ms(50));
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user