mirror of
https://github.com/boostorg/thread.git
synced 2026-02-08 23:22:13 +00:00
Compare commits
169 Commits
svn-branch
...
boost-1.55
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94654d4db5 | ||
|
|
88880770d3 | ||
|
|
c17f5d3fc7 | ||
|
|
8c6dcb9709 | ||
|
|
0e2c8ed9e3 | ||
|
|
2da4e8c29e | ||
|
|
8dce737911 | ||
|
|
3a7f0b1e78 | ||
|
|
8f06153f46 | ||
|
|
325d8cf5ca | ||
|
|
134c323958 | ||
|
|
5520763a73 | ||
|
|
ad010e0647 | ||
|
|
73f5c060ca | ||
|
|
3fb971386a | ||
|
|
6225c8309a | ||
|
|
fe8991b7fa | ||
|
|
f4fb2c1ab0 | ||
|
|
582649ed44 | ||
|
|
74891c9836 | ||
|
|
9dd08547f7 | ||
|
|
c6dbb0c9a5 | ||
|
|
0b2c57876f | ||
|
|
ba03de1f06 | ||
|
|
100bd73f03 | ||
|
|
4d2110f5e5 | ||
|
|
e294e6bcc8 | ||
|
|
093a329c1a | ||
|
|
13141f8ada | ||
|
|
64c73fac46 | ||
|
|
22369e9d8c | ||
|
|
677dbe7688 | ||
|
|
b1a674869d | ||
|
|
f9b257e368 | ||
|
|
8416d3e8bb | ||
|
|
8b89d21814 | ||
|
|
8804ab8e73 | ||
|
|
0ba92626f0 | ||
|
|
ce46c31555 | ||
|
|
e160cf0254 | ||
|
|
67da33a182 | ||
|
|
d07835908f | ||
|
|
e618900149 | ||
|
|
e012b8abb2 | ||
|
|
8ee9ed1904 | ||
|
|
565a022a5a | ||
|
|
0f7d406b9f | ||
|
|
4d5474d600 | ||
|
|
233484f254 | ||
|
|
ad3247dd29 | ||
|
|
0ae81b8d4c | ||
|
|
05f02e1476 | ||
|
|
23ea174056 | ||
|
|
ce19b13c43 | ||
|
|
8262d61ff5 | ||
|
|
4d013af927 | ||
|
|
2d8852199b | ||
|
|
12a1c7c71c | ||
|
|
89e944914b | ||
|
|
7bc8c437ab | ||
|
|
c4420d7591 | ||
|
|
6ef2dade3a | ||
|
|
c594f5d9ae | ||
|
|
a73cf83971 | ||
|
|
67a5a6f39e | ||
|
|
348bd080ef | ||
|
|
bca4c3d5fa | ||
|
|
9e6384bf79 | ||
|
|
dcd544082e | ||
|
|
09362f0eac | ||
|
|
32b3f3f569 | ||
|
|
8affa33718 | ||
|
|
b991c9a8a0 | ||
|
|
ab665c8c56 | ||
|
|
7ec9804540 | ||
|
|
7c9116af2e | ||
|
|
70584af9c0 | ||
|
|
381554f8bc | ||
|
|
4dc1cb1ba1 | ||
|
|
506019dd62 | ||
|
|
e30be60bc4 | ||
|
|
7bfafec128 | ||
|
|
e12d2bc486 | ||
|
|
a37d2a1364 | ||
|
|
cc662c102c | ||
|
|
65d2898ff0 | ||
|
|
9087fd904d | ||
|
|
66ac6942b6 | ||
|
|
20980fe54d | ||
|
|
fb54acfe69 | ||
|
|
0e69edd066 | ||
|
|
9255a035f4 | ||
|
|
fbdc23f482 | ||
|
|
8ab0d5acdd | ||
|
|
5af323102a | ||
|
|
0997fad8ec | ||
|
|
8749696538 | ||
|
|
9beea23f63 | ||
|
|
2978d43a5d | ||
|
|
a264766584 | ||
|
|
f03a9bfcf3 | ||
|
|
60fdcddcb5 | ||
|
|
525d190f91 | ||
|
|
1e0154335b | ||
|
|
413c29a5e4 | ||
|
|
30bb6143c1 | ||
|
|
991ac727c6 | ||
|
|
569a78649f | ||
|
|
7caec1ec33 | ||
|
|
7fd3fb48b1 | ||
|
|
a32a3b37db | ||
|
|
88f6076f3c | ||
|
|
b4d12e08dd | ||
|
|
1c0f470032 | ||
|
|
92b8789532 | ||
|
|
8f61694057 | ||
|
|
67f7de5305 | ||
|
|
6faecefb73 | ||
|
|
68c5bd44e8 | ||
|
|
3656277053 | ||
|
|
19846ff356 | ||
|
|
db2aaa04fd | ||
|
|
b48f9aa609 | ||
|
|
7915ab1ec6 | ||
|
|
f0faf88d66 | ||
|
|
7dd7537f5f | ||
|
|
f51680e8d9 | ||
|
|
a6bc072c6d | ||
|
|
85f2508157 | ||
|
|
ebb6c8d637 | ||
|
|
ddc83e270c | ||
|
|
0173148a2e | ||
|
|
69a4ec6c00 | ||
|
|
2d52219af2 | ||
|
|
1f87a9e4c0 | ||
|
|
ba8afde42b | ||
|
|
93f677cba6 | ||
|
|
dfd865d67d | ||
|
|
96a04402db | ||
|
|
78e644c7c1 | ||
|
|
89cc7fc34e | ||
|
|
974754598e | ||
|
|
87acbb406d | ||
|
|
597517157c | ||
|
|
a0b816be8c | ||
|
|
4a056924d2 | ||
|
|
d5a81f990c | ||
|
|
da8c92f057 | ||
|
|
866b33c808 | ||
|
|
182daf0b17 | ||
|
|
2552febc2a | ||
|
|
eb9db9b683 | ||
|
|
11dbdfca4d | ||
|
|
f49de9ec10 | ||
|
|
3a7e569a65 | ||
|
|
c376c1a62a | ||
|
|
fbbc52063a | ||
|
|
78b4fe3d07 | ||
|
|
b8c8b250b1 | ||
|
|
b26d01c8d7 | ||
|
|
4dbd8a66af | ||
|
|
cb4d739fd1 | ||
|
|
11f913e8fb | ||
|
|
0b6054a919 | ||
|
|
e7620a1050 | ||
|
|
811a03f281 | ||
|
|
2528bd0b8f | ||
|
|
ed587be470 | ||
|
|
55b48874a4 |
@@ -36,6 +36,7 @@ import os ;
|
||||
import feature ;
|
||||
import indirect ;
|
||||
import path ;
|
||||
import configure ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
@@ -140,6 +141,8 @@ local rule default_threadapi ( )
|
||||
feature.feature threadapi : pthread win32 : propagated ;
|
||||
feature.set-default threadapi : [ default_threadapi ] ;
|
||||
|
||||
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
|
||||
|
||||
rule tag ( name : type ? : property-set )
|
||||
{
|
||||
local result = $(name) ;
|
||||
@@ -236,10 +239,10 @@ rule usage-requirements ( properties * )
|
||||
}
|
||||
}
|
||||
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.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 ;
|
||||
}
|
||||
#}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -264,16 +267,15 @@ rule requirements ( properties * )
|
||||
}
|
||||
}
|
||||
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
|
||||
if ! [ configure.builds has_atomic_flag_lockfree
|
||||
: $(properties) : "lockfree boost::atomic_flag" ] {
|
||||
result += <library>/boost/atomic//boost_atomic ;
|
||||
}
|
||||
} else {
|
||||
result += <define>BOOST_THREAD_USES_CHRONO ;
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
|
||||
if <toolset>pgi in $(properties) || <toolset>vacpp in $(properties)
|
||||
{
|
||||
result += <library>/boost/atomic//boost_atomic ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
|
||||
13
build/has_atomic_flag_lockfree_test.cpp
Normal file
13
build/has_atomic_flag_lockfree_test.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software
|
||||
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
#include "../../../boost/atomic.hpp"
|
||||
#include "../../../boost/static_assert.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
|
||||
return 0;
|
||||
}
|
||||
@@ -8,24 +8,56 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[/]
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6782 #6782] call_once uses incorrect barrier intrinsic on Visual Studio
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9307 #9307] future::fallback_to assert with ERRORRRRR boost: mutex lock failed in pthread_mutex_lock: Invalid argument
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9308 #9308] future::async fails with terminate called throwing an exception when called with a lambda - clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread trunk regression test] to see the current state.
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries,
|
||||
* The experimental features of boost::future have some severe holes that make the program crash unexpectedly.
|
||||
|
||||
[*New Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro: Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8615 #8615] Async: Replace make_future/make_shared_future by make_ready_future.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8615 #8615] Async: Replace make_future/make_shared_future by make_ready_future.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap and unwrapping constructor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8677 #8677] Async: Add future<>::get_or.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8678 #8678] Async: Add future<>::fallback_to.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8891 #8891] upgrade_to_unique_lock: missing mutex() function.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8955 #8955] Request for more efficient way to get exception_ptr from future.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
[/]
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0 Boost 1.55.0 closed viboes Bugs
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8768 #8768] win32 condition_variable::wait_until infinite wait in rare cases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8817 #8817] Boost Thread Windows CE _createthreadex handling breaks mingw w64.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8943 #8943] Failed to compile code using boost::call_once with Intel C++ Composer XE 2013 on Windows.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8931 #8931] Typos in external_locking reference.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9029 #9029] Misprint in documentation.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9037 #9037] gcc -Wshadow gives warnings in condition_variable{,_fwd}.hpp.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9041 #9041] Boost.Thread DSO's may need to link with Boost.Atomic.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9048 #9048] boost::scoped_thread useless ctor with variadic template arguments.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9079 #9079] Condition variable will wait forever for some timepoint values (Win).
|
||||
|
||||
[heading Version 4.1.0 - boost 1.54]
|
||||
|
||||
@@ -417,6 +449,8 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
|
||||
# Add some features based on C++ proposals, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro: Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
|
||||
* [@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.
|
||||
|
||||
@@ -78,20 +78,28 @@ When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move Boost.Atomic]
|
||||
|
||||
[section:thread_eq `boost::thread::oprator==` deprecated]
|
||||
Boost.Thread uses by default an Boost.Atomic in POSIX platforms to implement call_once..
|
||||
|
||||
The following nested typedefs are deprecated:
|
||||
Define `BOOST_THREAD_USES_ATOMIC ` if you want to use Boost.Atomic.
|
||||
Define `BOOST_THREAD_DONT_USE_ATOMIC ` if you don't want to use Boost.Atomic or if it is not supported in your platform.
|
||||
|
||||
* `boost::thread::oprator==`
|
||||
* `boost::thread::oprator!=`
|
||||
[endsect]
|
||||
|
||||
[section:thread_eq `boost::thread::operator==` deprecated]
|
||||
|
||||
The following operators are deprecated:
|
||||
|
||||
* `boost::thread::operator==`
|
||||
* `boost::thread::operator!=`
|
||||
|
||||
When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature.
|
||||
|
||||
Use instead
|
||||
|
||||
* `boost::thread::id::oprator==`
|
||||
* `boost::thread::id::oprator!=`
|
||||
* `boost::thread::id::operator==`
|
||||
* `boost::thread::id::operator!=`
|
||||
|
||||
[warning This is a breaking change respect to version 1.x.]
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ Silence can be sometimes louder than words-what's forbidden to do with a `strict
|
||||
* You can create a `strict_lock<T>` only starting from a valid T object. Notice that there is no other way you can create a `strict_lock<T>`.
|
||||
|
||||
BankAccount myAccount("John Doe", "123-45-6789");
|
||||
strict_locerk<BankAccount> myLock(myAccount); // ok
|
||||
strict_lock<BankAccount> myLock(myAccount); // ok
|
||||
|
||||
* You cannot copy `strict_lock`s to one another. In particular, you cannot pass `strict_lock`s by value to functions or have them returned by functions:
|
||||
|
||||
@@ -468,7 +468,7 @@ Now imagine that the AccountManager function needs to take a `unique_lock` in or
|
||||
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard(*this, defer_lock);
|
||||
unique_lock<AccountManager> guard1(*this, defer_lock);
|
||||
if (some_condition()) {
|
||||
guard1.lock();
|
||||
}
|
||||
@@ -482,7 +482,7 @@ We need a way to transfer the ownership from the `unique_lock` to a `strict_lock
|
||||
|
||||
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.
|
||||
|
||||
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. Ths is really nice.
|
||||
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.
|
||||
|
||||
Now we need to state that both classes are `strict_lock`s.
|
||||
|
||||
|
||||
@@ -301,6 +301,8 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
// retrieving the value
|
||||
see below get();
|
||||
see below get_or(see below); // EXTENSION
|
||||
|
||||
exception_ptr get_exception_ptr(); // EXTENSION
|
||||
|
||||
// functions to check state
|
||||
bool valid() const noexcept;
|
||||
@@ -758,6 +760,23 @@ stored exception, `false` otherwise.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////////////////////////////////]
|
||||
[section:get_exception_ptr Member function `get_exception_ptr()` EXTENSION]
|
||||
|
||||
exception_ptr get_exception_ptr();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with a shared state, waits until the result is ready. If the result is not ready on
|
||||
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
|
||||
|
||||
[[Returns:] [a exception_ptr, storring or not an exception.]]
|
||||
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////////////////////////]
|
||||
[section:get_state Member function `get_state()` EXTENSION]
|
||||
@@ -925,6 +944,8 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
// retrieving the value
|
||||
see below get();
|
||||
|
||||
exception_ptr get_exception_ptr(); // EXTENSION
|
||||
|
||||
// functions to check state, and wait for ready
|
||||
bool valid() const noexcept;
|
||||
bool is_ready() const noexcept; // EXTENSION
|
||||
@@ -1185,7 +1206,7 @@ otherwise.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state, and that result is ready for retrieval, `false`
|
||||
otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1200,7 +1221,7 @@ otherwise.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state, that result is ready for retrieval, and the result is a
|
||||
stored value, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1215,7 +1236,24 @@ stored value, `false` otherwise.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state, that result is ready for retrieval, and the result is a
|
||||
stored exception, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////////////////////////////////]
|
||||
[section:get_exception_ptr Member function `get_exception_ptr()` EXTENSION]
|
||||
|
||||
exception_ptr get_exception_ptr();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `*this` is associated with a shared state, waits until the result is ready. If the result is not ready on
|
||||
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
|
||||
|
||||
[[Returns:] [a exception_ptr, storring or not an exception.]]
|
||||
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1232,7 +1270,7 @@ stored exception, `false` otherwise.]]
|
||||
[[Returns:] [__uninitialized__ if `*this` is not associated with a shared state. __ready__ if the shared state
|
||||
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -1273,7 +1273,7 @@ The following classes are models of `StrictLock`:
|
||||
explicit operator bool() const noexcept;
|
||||
bool owns_lock() const noexcept;
|
||||
|
||||
Lockable* mutex() const noexcept;
|
||||
mutex_type* mutex() const noexcept;
|
||||
|
||||
#if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
unique_lock(Lockable& m_,system_time const& target_time);
|
||||
@@ -1535,7 +1535,7 @@ object associated with `*this`.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:mutex `Lockable* mutex() const`]
|
||||
[section:mutex `Lockable* mutex() const noexcept`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -1907,7 +1907,7 @@ state (including the destructor) must be called by the same thread that acquired
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`]
|
||||
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock` -- EXTENSION]
|
||||
|
||||
// #include <boost/thread/locks.hpp>
|
||||
// #include <boost/thread/lock_types.hpp>
|
||||
@@ -1930,6 +1930,8 @@ state (including the destructor) must be called by the same thread that acquired
|
||||
|
||||
explicit operator bool() const;
|
||||
bool owns_lock() const;
|
||||
mutex_type* mutex() const;
|
||||
|
||||
};
|
||||
|
||||
__upgrade_to_unique_lock__ allows for a temporary upgrade of an __upgrade_lock__ to exclusive ownership. When constructed with a
|
||||
@@ -1939,7 +1941,7 @@ __lockable_concept_type__ is downgraded back to ['upgrade ownership].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:scoped_try_lock Mutex-specific class `scoped_try_lock`]
|
||||
[section:scoped_try_lock Mutex-specific class `scoped_try_lock` -- DEPRECATED]
|
||||
|
||||
class MutexType::scoped_try_lock
|
||||
{
|
||||
|
||||
@@ -190,7 +190,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
explicit scoped_thread(thread&& th) noexcept;
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
explicit scoped_thread(F&&, Args&&...);
|
||||
|
||||
~scoped_thread();
|
||||
|
||||
@@ -323,7 +323,7 @@ any) to `*this`.
|
||||
[section:call_constructor Move Constructor from a Callable]
|
||||
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
explicit scoped_thread(F&&, Args&&...);
|
||||
|
||||
[variablelist
|
||||
|
||||
|
||||
@@ -23,16 +23,16 @@ In addition to the C++11 standard locks, Boost.Thread provides other locks and s
|
||||
In particular, the library provides some lock factories.
|
||||
|
||||
template <class Lockable, class Function>
|
||||
auto with_lock_guard(Lockable& m, Function f) -> decltype(fn())
|
||||
auto with_lock_guard(Lockable& m, Function f) -> decltype(f())
|
||||
{
|
||||
auto&& _ = boost::make_lock_guard(f);
|
||||
auto&& _ = boost::make_lock_guard(m);
|
||||
f();
|
||||
}
|
||||
|
||||
|
||||
that can be used as
|
||||
|
||||
int i = with_lock_guard(mtx, {}() -> bool
|
||||
int i = with_lock_guard(mtx, []()
|
||||
{
|
||||
// access the protected state
|
||||
return true;
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[include latch.qbk]
|
||||
[/include latch.qbk]
|
||||
[include futures.qbk]
|
||||
[/include async_executors.qbk]
|
||||
[endsect]
|
||||
@@ -249,7 +249,7 @@
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
[include synchronized_value.qbk]
|
||||
[include sync_queues_ref.qbk]
|
||||
[/include sync_queues_ref.qbk]
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -568,7 +568,7 @@ any) to `*this`.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Callable` must by Copyable and `func()` must be a valid expression.]]
|
||||
[[Requires:] [`Callable` must be Copyable and `func()` must be a valid expression.]]
|
||||
|
||||
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -595,7 +595,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`Callable` must by copyable.]]
|
||||
[[Preconditions:] [`Callable` must be copyable.]]
|
||||
|
||||
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -623,7 +623,7 @@ If the attributes declare the native thread as detached, the boost::thread will
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`Callable` must by Movable.]]
|
||||
[[Preconditions:] [`Callable` must be Movable.]]
|
||||
|
||||
[[Effects:] [`func` is moved into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -650,7 +650,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`Callable` must by copyable.]]
|
||||
[[Preconditions:] [`Callable` must be copyable.]]
|
||||
|
||||
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -679,7 +679,7 @@ If the attributes declare the native thread as detached, the boost::thread will
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`F` and each `A`n must by copyable or movable.]]
|
||||
[[Preconditions:] [`F` and each `A`n must be copyable or movable.]]
|
||||
|
||||
[[Effects:] [As if [link
|
||||
thread.thread_management.thread.callable_constructor
|
||||
|
||||
@@ -16,7 +16,7 @@ class bounded_buffer : private boost::noncopyable
|
||||
public:
|
||||
typedef boost::unique_lock<boost::mutex> lock;
|
||||
|
||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
bounded_buffer(int n) : boost::noncopyable(), begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
|
||||
void send (int m) {
|
||||
lock lk(monitor);
|
||||
|
||||
@@ -44,8 +44,8 @@ int main()
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
|
||||
scoped_thread<> t1(thread(use_cerr, boost::ref(mcerr)));
|
||||
scoped_thread<> t2(thread(use_cout, boost::ref(mcout)));
|
||||
scoped_thread<> t1(boost::thread(use_cerr, boost::ref(mcerr)));
|
||||
scoped_thread<> t2(boost::thread(use_cout, boost::ref(mcout)));
|
||||
this_thread::sleep_for(chrono::seconds(2));
|
||||
std::string nm;
|
||||
{
|
||||
|
||||
@@ -110,9 +110,9 @@ int main()
|
||||
|
||||
{
|
||||
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)));
|
||||
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
|
||||
@@ -110,9 +110,9 @@ int main()
|
||||
|
||||
{
|
||||
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)));
|
||||
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ void do_something(int& i)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
void f(int, int)
|
||||
{
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
@@ -81,7 +84,10 @@ int main()
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
|
||||
{
|
||||
boost::scoped_thread<> g( &f, 1, 2 );
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ namespace boost
|
||||
struct void_functor_barrier_reseter
|
||||
{
|
||||
unsigned int size_;
|
||||
void_completion_function fct_;template <typename F>
|
||||
void_completion_function fct_;
|
||||
template <typename F>
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct)
|
||||
: size_(size), fct_(boost::move(funct))
|
||||
@@ -90,7 +91,7 @@ namespace boost
|
||||
}
|
||||
class barrier
|
||||
{
|
||||
static inline unsigned int check(unsigned int count)
|
||||
static inline unsigned int check_counter(unsigned int count)
|
||||
{
|
||||
if (count == 0) boost::throw_exception(
|
||||
thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
|
||||
@@ -104,7 +105,7 @@ namespace boost
|
||||
BOOST_THREAD_NO_COPYABLE( barrier)
|
||||
|
||||
explicit barrier(unsigned int count) :
|
||||
m_count(check(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count))
|
||||
m_count(check_counter(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@ namespace boost
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check(count)),
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(thread_detail::void_functor_barrier_reseter(count,
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
@@ -145,7 +146,7 @@ namespace boost
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check(count)),
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
@@ -158,7 +159,7 @@ namespace boost
|
||||
}
|
||||
|
||||
barrier(unsigned int count, void(*funct)()) :
|
||||
m_count(check(count)), m_generation(0),
|
||||
m_count(check_counter(count)), m_generation(0),
|
||||
fct_(funct
|
||||
? thread_detail::size_completion_function(thread_detail::void_fct_ptr_barrier_reseter(count, funct))
|
||||
: thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
|
||||
@@ -166,7 +167,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
barrier(unsigned int count, unsigned int(*funct)()) :
|
||||
m_count(check(count)), m_generation(0),
|
||||
m_count(check_counter(count)), m_generation(0),
|
||||
fct_(funct
|
||||
? thread_detail::size_completion_function(funct)
|
||||
: thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
|
||||
|
||||
@@ -826,6 +826,19 @@ namespace boost
|
||||
};
|
||||
|
||||
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
|
||||
struct shared_state_base;
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
current_thread_data->make_ready_at_thread_exit(as);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
|
||||
@@ -201,23 +201,19 @@ namespace boost
|
||||
struct shared_state_base : enable_shared_from_this<shared_state_base>
|
||||
{
|
||||
typedef std::list<boost::condition_variable_any*> waiter_list;
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
// This type should be only included conditionally if interruptions are allowed, but is included to maintain the same layout.
|
||||
typedef shared_ptr<shared_state_base> continuation_ptr_type;
|
||||
#else
|
||||
// This type shouldn't be included, but is included to maintain the same layout.
|
||||
typedef shared_ptr<void> continuation_ptr_type;
|
||||
#endif
|
||||
|
||||
boost::exception_ptr exception;
|
||||
bool done;
|
||||
bool is_deferred_;
|
||||
launch policy_;
|
||||
bool is_constructed;
|
||||
boost::mutex mutex;
|
||||
mutable boost::mutex mutex;
|
||||
boost::condition_variable waiters;
|
||||
waiter_list external_waiters;
|
||||
boost::function<void()> callback;
|
||||
// This declaration should be only included conditionally, but is included to maintain the same layout.
|
||||
// This declaration should be only included conditionally if interruptions are allowed, but is included to maintain the same layout.
|
||||
bool thread_was_interrupted;
|
||||
// This declaration should be only included conditionally, but is included to maintain the same layout.
|
||||
continuation_ptr_type continuation_ptr;
|
||||
@@ -418,7 +414,7 @@ namespace boost
|
||||
{
|
||||
throw_exception(promise_already_satisfied());
|
||||
}
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -431,10 +427,11 @@ namespace boost
|
||||
}
|
||||
exception=e;
|
||||
this->is_constructed = true;
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
|
||||
}
|
||||
|
||||
bool has_value()
|
||||
bool has_value() const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mutex);
|
||||
return done && !(exception
|
||||
@@ -444,7 +441,7 @@ namespace boost
|
||||
);
|
||||
}
|
||||
|
||||
bool has_value(unique_lock<boost::mutex>& )
|
||||
bool has_value(unique_lock<boost::mutex>& ) const
|
||||
{
|
||||
return done && !(exception
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
@@ -453,7 +450,7 @@ namespace boost
|
||||
);
|
||||
}
|
||||
|
||||
bool has_exception()
|
||||
bool has_exception() const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mutex);
|
||||
return done && (exception
|
||||
@@ -463,7 +460,7 @@ namespace boost
|
||||
);
|
||||
}
|
||||
|
||||
bool has_exception(unique_lock<boost::mutex>&)
|
||||
bool has_exception(unique_lock<boost::mutex>&) const
|
||||
{
|
||||
return done && (exception
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
@@ -472,16 +469,16 @@ namespace boost
|
||||
);
|
||||
}
|
||||
|
||||
bool is_deferred() const BOOST_NOEXCEPT {
|
||||
bool is_deferred(boost::lock_guard<boost::mutex>&) const {
|
||||
return is_deferred_;
|
||||
}
|
||||
|
||||
launch launch_policy() const BOOST_NOEXCEPT
|
||||
launch launch_policy(boost::unique_lock<boost::mutex>&) const
|
||||
{
|
||||
return policy_;
|
||||
}
|
||||
|
||||
future_state::state get_state()
|
||||
future_state::state get_state() const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> guard(mutex);
|
||||
if(!done)
|
||||
@@ -494,6 +491,23 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
exception_ptr get_exception_ptr()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
return get_exception_ptr(lock);
|
||||
}
|
||||
exception_ptr get_exception_ptr(boost::unique_lock<boost::mutex>& lock)
|
||||
{
|
||||
wait_internal(lock, false);
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
if(thread_was_interrupted)
|
||||
{
|
||||
return copy_exception(boost::thread_interrupted());
|
||||
}
|
||||
#endif
|
||||
return exception;
|
||||
}
|
||||
|
||||
template<typename F,typename U>
|
||||
void set_wait_callback(F f,U* u)
|
||||
{
|
||||
@@ -671,7 +685,7 @@ namespace boost
|
||||
result.reset(new T(result_));
|
||||
|
||||
this->is_constructed = true;
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
//void set_value_at_thread_exit(BOOST_THREAD_RV_REF(T) result_)
|
||||
void set_value_at_thread_exit(rvalue_source_type result_)
|
||||
@@ -682,7 +696,7 @@ namespace boost
|
||||
result.reset(new T(boost::move(result_)));
|
||||
//future_traits<T>::init(result,static_cast<rvalue_source_type>(result_));
|
||||
this->is_constructed = true;
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
|
||||
|
||||
@@ -743,7 +757,7 @@ namespace boost
|
||||
//future_traits<T>::init(result,result_);
|
||||
result= &result_;
|
||||
this->is_constructed = true;
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -789,7 +803,7 @@ namespace boost
|
||||
throw_exception(promise_already_satisfied());
|
||||
}
|
||||
this->is_constructed = true;
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
private:
|
||||
shared_state(shared_state const&);
|
||||
@@ -803,8 +817,12 @@ namespace boost
|
||||
struct future_async_shared_state_base: shared_state<Rp>
|
||||
{
|
||||
typedef shared_state<Rp> base_type;
|
||||
protected:
|
||||
boost::thread thr_;
|
||||
|
||||
void join()
|
||||
{
|
||||
if (thr_.joinable()) thr_.join();
|
||||
}
|
||||
public:
|
||||
future_async_shared_state_base()
|
||||
{
|
||||
@@ -818,12 +836,12 @@ namespace boost
|
||||
|
||||
~future_async_shared_state_base()
|
||||
{
|
||||
if (thr_.joinable()) thr_.join();
|
||||
join();
|
||||
}
|
||||
|
||||
virtual void wait(bool rethrow)
|
||||
{
|
||||
if (thr_.joinable()) thr_.join();
|
||||
join();
|
||||
this->base_type::wait(rethrow);
|
||||
}
|
||||
};
|
||||
@@ -941,7 +959,11 @@ namespace boost
|
||||
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
|
||||
try
|
||||
{
|
||||
this->mark_finished_with_result_internal(func_(), lck);
|
||||
Fp local_fuct=boost::move(func_);
|
||||
relocker relock(lck);
|
||||
Rp res = local_fuct();
|
||||
relock.lock();
|
||||
this->mark_finished_with_result_internal(boost::move(res), lck);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -990,7 +1012,10 @@ namespace boost
|
||||
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
|
||||
try
|
||||
{
|
||||
func_();
|
||||
Fp local_fuct=boost::move(func_);
|
||||
relocker relock(lck);
|
||||
local_fuct();
|
||||
relock.lock();
|
||||
this->mark_finished_with_result_internal(lck);
|
||||
}
|
||||
catch (...)
|
||||
@@ -1294,7 +1319,7 @@ namespace boost
|
||||
future_.swap(that.future_);
|
||||
}
|
||||
// functions to check state, and wait for ready
|
||||
state get_state() const BOOST_NOEXCEPT
|
||||
state get_state() const
|
||||
{
|
||||
if(!future_)
|
||||
{
|
||||
@@ -1303,27 +1328,34 @@ namespace boost
|
||||
return future_->get_state();
|
||||
}
|
||||
|
||||
bool is_ready() const BOOST_NOEXCEPT
|
||||
bool is_ready() const
|
||||
{
|
||||
return get_state()==future_state::ready;
|
||||
}
|
||||
|
||||
bool has_exception() const BOOST_NOEXCEPT
|
||||
bool has_exception() const
|
||||
{
|
||||
return future_ && future_->has_exception();
|
||||
}
|
||||
|
||||
bool has_value() const BOOST_NOEXCEPT
|
||||
bool has_value() const
|
||||
{
|
||||
return future_ && future_->has_value();
|
||||
}
|
||||
|
||||
launch launch_policy() const BOOST_NOEXCEPT
|
||||
launch launch_policy(boost::unique_lock<boost::mutex>& lk) const
|
||||
{
|
||||
if ( future_ ) return future_->launch_policy();
|
||||
if ( future_ ) return future_->launch_policy(lk);
|
||||
else return launch(launch::none);
|
||||
}
|
||||
|
||||
exception_ptr get_exception_ptr()
|
||||
{
|
||||
return future_
|
||||
? future_->get_exception_ptr()
|
||||
: exception_ptr();
|
||||
}
|
||||
|
||||
bool valid() const BOOST_NOEXCEPT
|
||||
{
|
||||
return future_ != 0;
|
||||
@@ -1524,7 +1556,7 @@ namespace boost
|
||||
}
|
||||
|
||||
template <typename R2>
|
||||
typename disable_if< is_void<R2>, move_dest_type>::type
|
||||
typename boost::disable_if< is_void<R2>, move_dest_type>::type
|
||||
get_or(BOOST_THREAD_RV_REF(R2) v)
|
||||
{
|
||||
if(!this->future_)
|
||||
@@ -1545,7 +1577,7 @@ namespace boost
|
||||
}
|
||||
|
||||
template <typename R2>
|
||||
typename disable_if< is_void<R2>, move_dest_type>::type
|
||||
typename boost::disable_if< is_void<R2>, move_dest_type>::type
|
||||
get_or(R2 const& v) // EXTENSION
|
||||
{
|
||||
if(!this->future_)
|
||||
@@ -1585,17 +1617,17 @@ namespace boost
|
||||
then(launch policy, BOOST_THREAD_FWD_REF(F) func); // EXTENSION
|
||||
|
||||
template <typename R2>
|
||||
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
fallback_to(BOOST_THREAD_RV_REF(R2) v); // EXTENSION
|
||||
template <typename R2>
|
||||
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
fallback_to(R2 const& v); // EXTENSION
|
||||
|
||||
#endif
|
||||
|
||||
//#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
// inline
|
||||
// typename enable_if<
|
||||
// typename boost::enable_if<
|
||||
// is_future_type<value_type>,
|
||||
// value_type
|
||||
// //BOOST_THREAD_FUTURE<typename is_future_type<value_type>::type>
|
||||
@@ -1866,7 +1898,7 @@ namespace boost
|
||||
}
|
||||
|
||||
template <typename R2>
|
||||
typename disable_if< is_void<R2>, typename detail::shared_state<R>::shared_future_get_result_type>::type
|
||||
typename boost::disable_if< is_void<R2>, typename detail::shared_state<R>::shared_future_get_result_type>::type
|
||||
get_or(BOOST_THREAD_RV_REF(R2) v) // EXTENSION
|
||||
{
|
||||
if(!this->future_)
|
||||
@@ -1901,7 +1933,7 @@ namespace boost
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
// inline
|
||||
// typename enable_if_c<
|
||||
// typename boost::enable_if_c<
|
||||
// is_future_type<value_type>::value,
|
||||
// BOOST_THREAD_FUTURE<typename is_future_type<value_type>::type>
|
||||
// >::type
|
||||
@@ -3073,7 +3105,7 @@ namespace boost
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class F>
|
||||
explicit packaged_task(BOOST_THREAD_FWD_REF(F) f
|
||||
, typename disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
|
||||
, typename boost::disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
|
||||
)
|
||||
{
|
||||
typedef typename remove_cv<typename remove_reference<F>::type>::type FR;
|
||||
@@ -3094,7 +3126,7 @@ namespace boost
|
||||
#else
|
||||
template <class F>
|
||||
explicit packaged_task(F const& f
|
||||
, typename disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
|
||||
, typename boost::disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
|
||||
)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
|
||||
@@ -3744,6 +3776,10 @@ namespace boost
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
}
|
||||
~future_async_continuation_shared_state()
|
||||
{
|
||||
this->join();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F, typename Fp>
|
||||
@@ -3785,6 +3821,10 @@ namespace boost
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
}
|
||||
~future_async_continuation_shared_state()
|
||||
{
|
||||
this->join();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3815,7 +3855,12 @@ namespace boost
|
||||
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
|
||||
try
|
||||
{
|
||||
this->mark_finished_with_result_internal(continuation(boost::move(parent)), lck);
|
||||
Fp local_fuct=boost::move(continuation);
|
||||
F ftmp = boost::move(parent);
|
||||
relocker relock(lck);
|
||||
Rp res = local_fuct(boost::move(ftmp));
|
||||
relock.lock();
|
||||
this->mark_finished_with_result_internal(boost::move(res), lck);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -3847,7 +3892,11 @@ namespace boost
|
||||
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
|
||||
try
|
||||
{
|
||||
continuation(boost::move(parent));
|
||||
Fp local_fuct=boost::move(continuation);
|
||||
F ftmp = boost::move(parent);
|
||||
relocker relock(lck);
|
||||
local_fuct(boost::move(ftmp));
|
||||
relock.lock();
|
||||
this->mark_finished_with_result_internal(lck);
|
||||
}
|
||||
catch (...)
|
||||
@@ -3920,7 +3969,6 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
|
||||
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||
lock, boost::move(*this), boost::forward<F>(func)
|
||||
)));
|
||||
@@ -3938,13 +3986,13 @@ namespace boost
|
||||
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
|
||||
|
||||
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
||||
if (int(this->launch_policy()) & int(launch::async))
|
||||
if (int(this->launch_policy(lock)) & int(launch::async))
|
||||
{
|
||||
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||
lock, boost::move(*this), boost::forward<F>(func)
|
||||
);
|
||||
}
|
||||
else if (int(this->launch_policy()) & int(launch::deferred))
|
||||
else if (int(this->launch_policy(lock)) & int(launch::deferred))
|
||||
{
|
||||
this->future_->wait_internal(lock);
|
||||
return boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||
@@ -3953,7 +4001,6 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
|
||||
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||
lock, boost::move(*this), boost::forward<F>(func)
|
||||
);
|
||||
@@ -4038,7 +4085,6 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
|
||||
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<shared_future<R>, future_type, F>(
|
||||
lock, boost::move(*this), boost::forward<F>(func)
|
||||
)));
|
||||
@@ -4056,13 +4102,13 @@ namespace boost
|
||||
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
|
||||
|
||||
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
||||
if (int(this->launch_policy()) & int(launch::async))
|
||||
if (int(this->launch_policy(lock)) & int(launch::async))
|
||||
{
|
||||
return boost::detail::make_future_async_continuation_shared_state<shared_future<R>, future_type, F>(
|
||||
lock, boost::move(*this), boost::forward<F>(func)
|
||||
);
|
||||
}
|
||||
else if (int(this->launch_policy()) & int(launch::deferred))
|
||||
else if (int(this->launch_policy(lock)) & int(launch::deferred))
|
||||
{
|
||||
this->future_->wait_internal(lock);
|
||||
return boost::detail::make_future_deferred_continuation_shared_state<shared_future<R>, future_type, F>(
|
||||
@@ -4071,7 +4117,6 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
|
||||
return boost::detail::make_future_async_continuation_shared_state<shared_future<R>, future_type, F>(
|
||||
lock, boost::move(*this), boost::forward<F>(func)
|
||||
);
|
||||
@@ -4116,7 +4161,7 @@ namespace boost
|
||||
|
||||
template <typename R>
|
||||
template <typename R2>
|
||||
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
BOOST_THREAD_FUTURE<R>::fallback_to(BOOST_THREAD_RV_REF(R2) v)
|
||||
{
|
||||
return then(detail::mfallbacker_to<R>(boost::move(v)));
|
||||
@@ -4124,7 +4169,7 @@ namespace boost
|
||||
|
||||
template <typename R>
|
||||
template <typename R2>
|
||||
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
|
||||
BOOST_THREAD_FUTURE<R>::fallback_to(R2 const& v)
|
||||
{
|
||||
return then(detail::cfallbacker_to<R>(v));
|
||||
@@ -4169,8 +4214,6 @@ namespace boost
|
||||
make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f)
|
||||
{
|
||||
shared_ptr<future_unwrap_shared_state<F, Rp> >
|
||||
//shared_ptr<basic_future<Rp> >
|
||||
//typename boost::detail::basic_future<Rp>::future_ptr
|
||||
h(new future_unwrap_shared_state<F, Rp>(boost::move(f)));
|
||||
h->parent.future_->set_continuation_ptr(h, lock);
|
||||
return BOOST_THREAD_FUTURE<Rp>(h);
|
||||
|
||||
@@ -1112,6 +1112,10 @@ namespace boost
|
||||
{
|
||||
return exclusive.owns_lock();
|
||||
}
|
||||
Mutex* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return exclusive.mutex();
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END
|
||||
@@ -1187,7 +1191,7 @@ private unique_lock<Mutex>
|
||||
{
|
||||
return base::owns_lock();
|
||||
}
|
||||
Mutex* mutex() const
|
||||
Mutex* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return base::mutex();
|
||||
}
|
||||
|
||||
@@ -200,15 +200,15 @@ namespace boost
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
bool timed_wait(lock_type& m,boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::to_timespec(wait_until);
|
||||
struct timespec const timeout=detail::to_timespec(abs_time);
|
||||
return do_wait_until(m, timeout);
|
||||
}
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until)
|
||||
bool timed_wait(lock_type& m,xtime const& abs_time)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
return timed_wait(m,system_time(abs_time));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
@@ -218,20 +218,20 @@ namespace boost
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
if(!timed_wait(m, abs_time))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
|
||||
bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
return timed_wait(m,system_time(abs_time),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
|
||||
@@ -98,21 +98,21 @@ namespace boost
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until)
|
||||
boost::system_time const& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_WAIT_BUG
|
||||
struct timespec const timeout=detail::to_timespec(wait_until + BOOST_THREAD_WAIT_BUG);
|
||||
struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG);
|
||||
return do_wait_until(m, timeout);
|
||||
#else
|
||||
struct timespec const timeout=detail::to_timespec(wait_until);
|
||||
struct timespec const timeout=detail::to_timespec(abs_time);
|
||||
return do_wait_until(m, timeout);
|
||||
#endif
|
||||
}
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
xtime const& wait_until)
|
||||
xtime const& abs_time)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
return timed_wait(m,system_time(abs_time));
|
||||
}
|
||||
|
||||
template<typename duration_type>
|
||||
@@ -126,11 +126,11 @@ namespace boost
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until,predicate_type pred)
|
||||
boost::system_time const& abs_time,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
if(!timed_wait(m, abs_time))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
@@ -139,9 +139,9 @@ namespace boost
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
xtime const& wait_until,predicate_type pred)
|
||||
xtime const& abs_time,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
return timed_wait(m,system_time(abs_time),pred);
|
||||
}
|
||||
|
||||
template<typename duration_type,typename predicate_type>
|
||||
|
||||
@@ -47,9 +47,8 @@ namespace boost
|
||||
*
|
||||
*/
|
||||
#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) :
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
@@ -138,9 +137,8 @@ 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) :
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
//#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 <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics on C++98 compilers.
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
#include <boost/utility/result_of.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -593,8 +595,6 @@ namespace boost
|
||||
boost::swap(value_, rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -613,14 +613,81 @@ namespace boost
|
||||
return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call function on a locked block.
|
||||
*
|
||||
* @requires fct(value_) is well formed.
|
||||
*
|
||||
* Example
|
||||
* void fun(synchronized_value<vector<int>> & v) {
|
||||
* v ( [](vector<int>> & vec)
|
||||
* {
|
||||
* vec.push_back(42);
|
||||
* assert(vec.back() == 42);
|
||||
* } );
|
||||
* }
|
||||
*/
|
||||
template <typename F>
|
||||
inline
|
||||
typename boost::result_of<F(value_type&)>::type
|
||||
operator()(BOOST_THREAD_RV_REF(F) fct)
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return fct(value_);
|
||||
}
|
||||
template <typename F>
|
||||
inline
|
||||
typename boost::result_of<F(value_type const&)>::type
|
||||
operator()(BOOST_THREAD_RV_REF(F) fct) const
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return fct(value_);
|
||||
}
|
||||
|
||||
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <typename F>
|
||||
inline
|
||||
typename boost::result_of<F(value_type&)>::type
|
||||
operator()(F const & fct)
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return fct(value_);
|
||||
}
|
||||
template <typename F>
|
||||
inline
|
||||
typename boost::result_of<F(value_type const&)>::type
|
||||
operator()(F const & fct) const
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return fct(value_);
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
inline
|
||||
R operator()(R(*fct)(value_type&))
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return fct(value_);
|
||||
}
|
||||
template <typename R>
|
||||
inline
|
||||
R operator()(R(*fct)(value_type const&)) const
|
||||
{
|
||||
strict_lock<mutex_type> lk(mtx_);
|
||||
return fct(value_);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* The synchronize() factory make easier to lock on a scope.
|
||||
* As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations.
|
||||
* With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope.
|
||||
*
|
||||
* Example
|
||||
* void fun(synchronized_value<vector<int>> & vec) {
|
||||
* auto&& vec=vec.synchronize();
|
||||
* void fun(synchronized_value<vector<int>> & v) {
|
||||
* auto&& vec=v.synchronize();
|
||||
* vec.push_back(42);
|
||||
* assert(vec.back() == 42);
|
||||
* }
|
||||
@@ -880,9 +947,9 @@ namespace boost
|
||||
|
||||
//Hash support
|
||||
|
||||
template <class T> struct hash;
|
||||
template <typename T, typename L>
|
||||
struct hash<synchronized_value<T,L> >;
|
||||
// template <class T> struct hash;
|
||||
// template <typename T, typename L>
|
||||
// struct hash<synchronized_value<T,L> >;
|
||||
|
||||
// Comparison with T
|
||||
template <typename T, typename L>
|
||||
|
||||
@@ -191,18 +191,17 @@ namespace boost
|
||||
struct entry_manager
|
||||
{
|
||||
entry_ptr const entry;
|
||||
boost::mutex& internal_mutex;
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE(entry_manager)
|
||||
entry_manager(entry_ptr const& entry_):
|
||||
entry(entry_)
|
||||
entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
|
||||
entry(entry_), internal_mutex(mutex_)
|
||||
{}
|
||||
|
||||
~entry_manager()
|
||||
{
|
||||
//if(! entry->is_notified()) // several regression #7657
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
entry->remove_waiter();
|
||||
}
|
||||
}
|
||||
|
||||
list_entry* operator->()
|
||||
@@ -218,7 +217,7 @@ namespace boost
|
||||
{
|
||||
relocker<lock_type> locker(lock);
|
||||
|
||||
entry_manager entry(get_wait_entry());
|
||||
entry_manager entry(get_wait_entry(), internal_mutex);
|
||||
|
||||
locker.unlock();
|
||||
|
||||
@@ -366,7 +365,11 @@ namespace boost
|
||||
const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
do_wait(lock, ceil<milliseconds>(t-Clock::now()).count());
|
||||
chrono::time_point<Clock, Duration> now = Clock::now();
|
||||
if (t<=now) {
|
||||
return cv_status::timeout;
|
||||
}
|
||||
do_wait(lock, ceil<milliseconds>(t-now).count());
|
||||
return Clock::now() < t ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
@@ -378,6 +381,10 @@ namespace boost
|
||||
const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
if (d<=chrono::duration<Rep, Period>::zero()) {
|
||||
return cv_status::timeout;
|
||||
}
|
||||
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
do_wait(lock, ceil<milliseconds>(d).count());
|
||||
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
|
||||
@@ -479,7 +486,11 @@ namespace boost
|
||||
const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
do_wait(lock, ceil<milliseconds>(t-Clock::now()).count());
|
||||
chrono::time_point<Clock, Duration> now = Clock::now();
|
||||
if (t<=now) {
|
||||
return cv_status::timeout;
|
||||
}
|
||||
do_wait(lock, ceil<milliseconds>(t-now).count());
|
||||
return Clock::now() < t ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
@@ -491,6 +502,9 @@ namespace boost
|
||||
const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
if (d<=chrono::duration<Rep, Period>::zero()) {
|
||||
return cv_status::timeout;
|
||||
}
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
do_wait(lock, ceil<milliseconds>(d).count());
|
||||
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
|
||||
|
||||
@@ -9,33 +9,32 @@
|
||||
|
||||
// check if we use MFC
|
||||
#ifdef _AFXDLL
|
||||
# if defined(_AFXEXT)
|
||||
# if defined(_AFXEXT)
|
||||
|
||||
// can't use ExtRawDllMain from afxdllx.h as it also defines the symbol _pRawDllMain
|
||||
extern "C"
|
||||
inline BOOL WINAPI ExtRawDllMain(HINSTANCE, DWORD dwReason, LPVOID)
|
||||
{
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
// save critical data pointers before running the constructors
|
||||
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
|
||||
pModuleState->m_pClassInit = pModuleState->m_classList;
|
||||
pModuleState->m_pFactoryInit = pModuleState->m_factoryList;
|
||||
pModuleState->m_classList.m_pHead = NULL;
|
||||
pModuleState->m_factoryList.m_pHead = NULL;
|
||||
}
|
||||
return TRUE; // ok
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
// save critical data pointers before running the constructors
|
||||
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
|
||||
pModuleState->m_pClassInit = pModuleState->m_classList;
|
||||
pModuleState->m_pFactoryInit = pModuleState->m_factoryList;
|
||||
pModuleState->m_classList.m_pHead = NULL;
|
||||
pModuleState->m_factoryList.m_pHead = NULL;
|
||||
}
|
||||
return TRUE; // ok
|
||||
}
|
||||
|
||||
extern "C" __declspec(selectany) BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID) = &ExtRawDllMain;
|
||||
|
||||
# elif defined(_USRDLL)
|
||||
# elif defined(_USRDLL)
|
||||
|
||||
extern "C" BOOL WINAPI RawDllMain(HANDLE, DWORD dwReason, LPVOID);
|
||||
extern "C" __declspec(selectany) BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID) = &RawDllMain;
|
||||
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -363,7 +363,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifndef BOOST_MSVC
|
||||
#if ! defined(BOOST_MSVC) && ! defined(BOOST_INTEL)
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace boost
|
||||
|
||||
virtual void run()=0;
|
||||
|
||||
void notify_all_at_thread_exit(condition_variable* cv, mutex* m)
|
||||
virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m)
|
||||
{
|
||||
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
|
||||
}
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
//#include <boost/detail/winapi/synchronization.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
|
||||
#if _WIN32_WINNT >= 0x0600 && ! defined _WIN32_WINNT_WS08
|
||||
#define BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -187,7 +187,9 @@ namespace boost
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
namespace detail
|
||||
{
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
@@ -197,7 +199,12 @@ namespace boost
|
||||
interrupt_enabled=false;
|
||||
#endif
|
||||
}
|
||||
|
||||
~externally_launched_thread() {
|
||||
BOOST_ASSERT(notify.empty());
|
||||
notify.clear();
|
||||
BOOST_ASSERT(async_states_.empty());
|
||||
async_states_.clear();
|
||||
}
|
||||
void run()
|
||||
{}
|
||||
void notify_all_at_thread_exit(condition_variable*, mutex*)
|
||||
@@ -208,18 +215,18 @@ namespace boost
|
||||
void operator=(externally_launched_thread&);
|
||||
};
|
||||
|
||||
detail::thread_data_base* make_external_thread_data()
|
||||
thread_data_base* make_external_thread_data()
|
||||
{
|
||||
detail::thread_data_base* const me(new externally_launched_thread());
|
||||
thread_data_base* const me(new externally_launched_thread());
|
||||
me->self.reset(me);
|
||||
set_current_thread_data(me);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
|
||||
thread_data_base* current_thread_data(get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
current_thread_data=make_external_thread_data();
|
||||
@@ -701,8 +708,11 @@ namespace boost
|
||||
|
||||
void erase_tss_node(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.erase(key);
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
current_thread_data->tss_data.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,
|
||||
@@ -740,6 +750,17 @@ namespace boost
|
||||
current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
|
||||
}
|
||||
}
|
||||
namespace detail {
|
||||
|
||||
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
current_thread_data->make_ready_at_thread_exit(as);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,328 +0,0 @@
|
||||
// Copyright Howard Hinnant 2007-2010.
|
||||
// Copyright Vicente J. Botet Escriba 2012.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/v2/shared_mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace thread_v2
|
||||
{
|
||||
|
||||
// shared_mutex
|
||||
|
||||
shared_mutex::shared_mutex()
|
||||
: state_(0)
|
||||
{
|
||||
}
|
||||
|
||||
shared_mutex::~shared_mutex()
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
}
|
||||
|
||||
// Exclusive ownership
|
||||
|
||||
void
|
||||
shared_mutex::lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
while (state_ & write_entered_)
|
||||
gate1_.wait(lk);
|
||||
state_ |= write_entered_;
|
||||
while (state_ & n_readers_)
|
||||
gate2_.wait(lk);
|
||||
}
|
||||
|
||||
bool
|
||||
shared_mutex::try_lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
if (state_ == 0)
|
||||
{
|
||||
state_ = write_entered_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
shared_mutex::unlock()
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
state_ = 0;
|
||||
gate1_.notify_all();
|
||||
}
|
||||
|
||||
// Shared ownership
|
||||
|
||||
void
|
||||
shared_mutex::lock_shared()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
|
||||
gate1_.wait(lk);
|
||||
count_t num_readers = (state_ & n_readers_) + 1;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= num_readers;
|
||||
}
|
||||
|
||||
bool
|
||||
shared_mutex::try_lock_shared()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
count_t num_readers = state_ & n_readers_;
|
||||
if (!(state_ & write_entered_) && num_readers != n_readers_)
|
||||
{
|
||||
++num_readers;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= num_readers;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
shared_mutex::unlock_shared()
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
count_t num_readers = (state_ & n_readers_) - 1;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= num_readers;
|
||||
if (state_ & write_entered_)
|
||||
{
|
||||
if (num_readers == 0)
|
||||
gate2_.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_readers == n_readers_ - 1)
|
||||
gate1_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
// upgrade_mutex
|
||||
|
||||
upgrade_mutex::upgrade_mutex()
|
||||
: gate1_(),
|
||||
gate2_(),
|
||||
state_(0)
|
||||
{
|
||||
}
|
||||
|
||||
upgrade_mutex::~upgrade_mutex()
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
}
|
||||
|
||||
// Exclusive ownership
|
||||
|
||||
void
|
||||
upgrade_mutex::lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
while (state_ & (write_entered_ | upgradable_entered_))
|
||||
gate1_.wait(lk);
|
||||
state_ |= write_entered_;
|
||||
while (state_ & n_readers_)
|
||||
gate2_.wait(lk);
|
||||
}
|
||||
|
||||
bool
|
||||
upgrade_mutex::try_lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
if (state_ == 0)
|
||||
{
|
||||
state_ = write_entered_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock()
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
state_ = 0;
|
||||
gate1_.notify_all();
|
||||
}
|
||||
|
||||
// Shared ownership
|
||||
|
||||
void
|
||||
upgrade_mutex::lock_shared()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
|
||||
gate1_.wait(lk);
|
||||
count_t num_readers = (state_ & n_readers_) + 1;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= num_readers;
|
||||
}
|
||||
|
||||
bool
|
||||
upgrade_mutex::try_lock_shared()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
count_t num_readers = state_ & n_readers_;
|
||||
if (!(state_ & write_entered_) && num_readers != n_readers_)
|
||||
{
|
||||
++num_readers;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= num_readers;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock_shared()
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
count_t num_readers = (state_ & n_readers_) - 1;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= num_readers;
|
||||
if (state_ & write_entered_)
|
||||
{
|
||||
if (num_readers == 0)
|
||||
gate2_.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_readers == n_readers_ - 1)
|
||||
gate1_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade ownership
|
||||
|
||||
void
|
||||
upgrade_mutex::lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
while ((state_ & (write_entered_ | upgradable_entered_)) ||
|
||||
(state_ & n_readers_) == n_readers_)
|
||||
gate1_.wait(lk);
|
||||
count_t num_readers = (state_ & n_readers_) + 1;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= upgradable_entered_ | num_readers;
|
||||
}
|
||||
|
||||
bool
|
||||
upgrade_mutex::try_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
count_t num_readers = state_ & n_readers_;
|
||||
if (!(state_ & (write_entered_ | upgradable_entered_))
|
||||
&& num_readers != n_readers_)
|
||||
{
|
||||
++num_readers;
|
||||
state_ &= ~n_readers_;
|
||||
state_ |= upgradable_entered_ | num_readers;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock_upgrade()
|
||||
{
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
count_t num_readers = (state_ & n_readers_) - 1;
|
||||
state_ &= ~(upgradable_entered_ | n_readers_);
|
||||
state_ |= num_readers;
|
||||
}
|
||||
gate1_.notify_all();
|
||||
}
|
||||
|
||||
// Shared <-> Exclusive
|
||||
|
||||
bool
|
||||
upgrade_mutex::try_unlock_shared_and_lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
if (state_ == 1)
|
||||
{
|
||||
state_ = write_entered_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock_and_lock_shared()
|
||||
{
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
state_ = 1;
|
||||
}
|
||||
gate1_.notify_all();
|
||||
}
|
||||
|
||||
// Shared <-> Upgrade
|
||||
|
||||
bool
|
||||
upgrade_mutex::try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
if (!(state_ & (write_entered_ | upgradable_entered_)))
|
||||
{
|
||||
state_ |= upgradable_entered_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
state_ &= ~upgradable_entered_;
|
||||
}
|
||||
gate1_.notify_all();
|
||||
}
|
||||
|
||||
// Upgrade <-> Exclusive
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
count_t num_readers = (state_ & n_readers_) - 1;
|
||||
state_ &= ~(upgradable_entered_ | n_readers_);
|
||||
state_ |= write_entered_ | num_readers;
|
||||
while (state_ & n_readers_)
|
||||
gate2_.wait(lk);
|
||||
}
|
||||
|
||||
bool
|
||||
upgrade_mutex::try_unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::unique_lock<mutex_t> lk(mut_);
|
||||
if (state_ == (upgradable_entered_ | 1))
|
||||
{
|
||||
state_ = write_entered_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
upgrade_mutex::unlock_and_lock_upgrade()
|
||||
{
|
||||
{
|
||||
boost::lock_guard<mutex_t> _(mut_);
|
||||
state_ = upgradable_entered_ | 1;
|
||||
}
|
||||
gate1_.notify_all();
|
||||
}
|
||||
|
||||
} // thread_v2
|
||||
} // boost
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#endif
|
||||
@@ -128,7 +129,7 @@ namespace boost
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef void* uintptr_t;
|
||||
//typedef void* uintptr_t;
|
||||
|
||||
inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
|
||||
void* arglist, unsigned initflag, unsigned* thrdaddr)
|
||||
@@ -278,6 +279,12 @@ namespace boost
|
||||
interruption_enabled=false;
|
||||
#endif
|
||||
}
|
||||
~externally_launched_thread() {
|
||||
BOOST_ASSERT(notify.empty());
|
||||
notify.clear();
|
||||
BOOST_ASSERT(async_states_.empty());
|
||||
async_states_.clear();
|
||||
}
|
||||
|
||||
void run()
|
||||
{}
|
||||
@@ -429,7 +436,7 @@ namespace boost
|
||||
LARGE_INTEGER due_time={{0,0}};
|
||||
if(target_time.relative)
|
||||
{
|
||||
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
|
||||
unsigned long const elapsed_milliseconds=detail::win32::GetTickCount64()-target_time.start;
|
||||
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
|
||||
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
|
||||
|
||||
@@ -747,5 +754,16 @@ namespace boost
|
||||
current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
|
||||
}
|
||||
}
|
||||
//namespace detail {
|
||||
//
|
||||
// void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
||||
// {
|
||||
// detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
|
||||
// if(current_thread_data)
|
||||
// {
|
||||
// current_thread_data->make_ready_at_thread_exit(as);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
@@ -768,6 +768,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ 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 ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/synchronized_value/call_pass.cpp : synchronized_value__call_p ]
|
||||
|
||||
;
|
||||
|
||||
@@ -789,8 +790,11 @@ rule thread-compile ( sources : reqs * : name )
|
||||
#[ thread-run test_8586.cpp ]
|
||||
#[ thread-run test_8596.cpp ]
|
||||
#[ thread-run test_8600.cpp ]
|
||||
#[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_queue__multi_thread_p ]
|
||||
|
||||
#[ thread-run test_8943.cpp ]
|
||||
#[ thread-run test_8960.cpp ]
|
||||
[ thread-run test_9079_a.cpp ]
|
||||
[ thread-run test_9079_b.cpp ]
|
||||
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -189,6 +189,26 @@ int main()
|
||||
BOOST_TEST(!f.valid());
|
||||
#endif
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
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(func4, boost::move(p)).detach();
|
||||
#else
|
||||
p.set_exception(boost::make_exception_ptr(3.5));
|
||||
#endif
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f.valid());
|
||||
boost::exception_ptr ptr = f.get_exception_ptr();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
BOOST_TEST(f.valid());
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
|
||||
|
||||
144
test/sync/mutual_exclusion/synchronized_value/call_pass.cpp
Normal file
144
test/sync/mutual_exclusion/synchronized_value/call_pass.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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/synchronized_value.hpp>
|
||||
|
||||
// class synchronized_value<T,M>
|
||||
|
||||
// template <typename F>
|
||||
// inline typename boost::result_of<F(value_type&)>::type
|
||||
// operator()(BOOST_THREAD_RV_REF(F) fct);
|
||||
// template <typename F>
|
||||
// inline typename boost::result_of<F(value_type const&)>::type
|
||||
// operator()(BOOST_THREAD_RV_REF(F) fct) const;
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/synchronized_value.hpp>
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
struct S {
|
||||
int f() const {return 1;}
|
||||
int g() {return 1;}
|
||||
};
|
||||
|
||||
void c(S const& s)
|
||||
{
|
||||
BOOST_TEST(s.f()==1);
|
||||
}
|
||||
|
||||
void nc(S & s)
|
||||
{
|
||||
BOOST_TEST(s.f()==1);
|
||||
BOOST_TEST(s.g()==1);
|
||||
}
|
||||
|
||||
struct cfctr {
|
||||
typedef void result_type;
|
||||
void operator()(S const& s) const {
|
||||
BOOST_TEST(s.f()==1);
|
||||
}
|
||||
};
|
||||
struct ncfctr {
|
||||
typedef void result_type;
|
||||
void operator()(S& s) const {
|
||||
BOOST_TEST(s.f()==1);
|
||||
BOOST_TEST(s.g()==1);
|
||||
}
|
||||
};
|
||||
|
||||
struct cfctr3 {
|
||||
typedef void result_type;
|
||||
BOOST_THREAD_MOVABLE_ONLY(cfctr3)
|
||||
cfctr3()
|
||||
{}
|
||||
cfctr3(BOOST_THREAD_RV_REF(cfctr3))
|
||||
{}
|
||||
void operator()(S const& s) const {
|
||||
BOOST_TEST(s.f()==1);
|
||||
}
|
||||
};
|
||||
struct ncfctr3 {
|
||||
typedef void result_type;
|
||||
BOOST_THREAD_MOVABLE_ONLY(ncfctr3)
|
||||
ncfctr3()
|
||||
{}
|
||||
ncfctr3(BOOST_THREAD_RV_REF(ncfctr3))
|
||||
{}
|
||||
void operator()(S& s) const {
|
||||
BOOST_TEST(s.f()==1);
|
||||
BOOST_TEST(s.g()==1);
|
||||
}
|
||||
};
|
||||
|
||||
cfctr3 make_cfctr3() {
|
||||
return BOOST_THREAD_MAKE_RV_REF(cfctr3());
|
||||
}
|
||||
|
||||
ncfctr3 make_ncfctr3() {
|
||||
return BOOST_THREAD_MAKE_RV_REF(ncfctr3());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
boost::synchronized_value<S> v;
|
||||
v(&nc);
|
||||
//v(&c);
|
||||
}
|
||||
{
|
||||
const boost::synchronized_value<S> v;
|
||||
v(&c);
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<S> v;
|
||||
v(ncfctr());
|
||||
}
|
||||
{
|
||||
const boost::synchronized_value<S> v;
|
||||
v(cfctr());
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<S> v;
|
||||
ncfctr fct;
|
||||
v(fct);
|
||||
}
|
||||
{
|
||||
const boost::synchronized_value<S> v;
|
||||
cfctr fct;
|
||||
v(fct);
|
||||
}
|
||||
{
|
||||
boost::synchronized_value<S> v;
|
||||
v(make_ncfctr3());
|
||||
}
|
||||
{
|
||||
const boost::synchronized_value<S> v;
|
||||
v(make_cfctr3());
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
{
|
||||
boost::synchronized_value<S> v;
|
||||
v([](S& s) {
|
||||
BOOST_TEST(s.f()==1);
|
||||
BOOST_TEST(s.g()==1);
|
||||
});
|
||||
}
|
||||
{
|
||||
const boost::synchronized_value<S> v;
|
||||
v([](S const& s) {
|
||||
BOOST_TEST(s.f()==1);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
57
test/test_9079_a.cpp
Normal file
57
test/test_9079_a.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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)
|
||||
|
||||
// A
|
||||
|
||||
//#include <boost/log/trivial.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
//#if !defined(BOOST_NO_CXX11_ALIGNAS)
|
||||
//#error
|
||||
//# define BOOST_ALIGNMENT2(x) alignas(x)
|
||||
//#elif defined(_MSC_VER)
|
||||
//#error
|
||||
//# define BOOST_ALIGNMENT2(x) __declspec(align(x))
|
||||
//#elif defined(__GNUC__)
|
||||
//#error
|
||||
//# define BOOST_ALIGNMENT(x) __attribute__ ((__aligned__(x)))
|
||||
//#else
|
||||
//#error
|
||||
//# define BOOST_NO_ALIGNMENT2
|
||||
//# define BOOST_ALIGNMENT2(x)
|
||||
//#endif
|
||||
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
typedef Clock::time_point TimePoint;
|
||||
|
||||
inline TimePoint real_time_now()
|
||||
{
|
||||
return Clock::now();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::chrono;
|
||||
|
||||
boost::condition_variable m_task_spawn_condition;
|
||||
|
||||
boost::mutex main_thread_mutex;
|
||||
boost::unique_lock < boost::mutex > main_thread_lock(main_thread_mutex);
|
||||
|
||||
//BOOST_LOG_TRIVIAL(info) << "[TaskScheduler::run_and_wait] Scheduling loop - BEGIN";
|
||||
|
||||
//while (true)
|
||||
{
|
||||
static const milliseconds TIME_BACK = milliseconds(1);
|
||||
m_task_spawn_condition.wait_until(
|
||||
main_thread_lock,
|
||||
real_time_now() - TIME_BACK); // wait forever
|
||||
m_task_spawn_condition.wait_for( main_thread_lock, - TIME_BACK ); // same problem
|
||||
//BOOST_LOG_TRIVIAL(trace) << "TICK";
|
||||
}
|
||||
|
||||
}
|
||||
81
test/test_9079_b.cpp
Normal file
81
test/test_9079_b.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// 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)
|
||||
|
||||
// B
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
//#include <boost/log/trivial.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
typedef Clock::time_point TimePoint;
|
||||
|
||||
inline TimePoint real_time_now()
|
||||
{
|
||||
return Clock::now();
|
||||
}
|
||||
|
||||
class Foo {
|
||||
boost::atomic<bool> m_is_exiting;
|
||||
TimePoint m_next_tick_time;
|
||||
|
||||
public:
|
||||
|
||||
bool is_exiting() const
|
||||
{
|
||||
return m_is_exiting;
|
||||
}
|
||||
|
||||
TimePoint spawn_tasks() // note that in my app, this call takes more time than here
|
||||
{
|
||||
using namespace boost::chrono;
|
||||
const TimePoint now = real_time_now();
|
||||
|
||||
if (m_next_tick_time < now) {
|
||||
m_next_tick_time = now + seconds(1);
|
||||
//BOOST_LOG_TRIVIAL(info) << "TICK!";
|
||||
}
|
||||
|
||||
return m_next_tick_time;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost::chrono;
|
||||
static const milliseconds MIN_TIME_TASKS_SPAWN_FREQUENCY = milliseconds(1);
|
||||
//microseconds(1); // THE SHORTER THE QUICKER TO REPRODUCE THE BUG
|
||||
|
||||
boost::condition_variable m_task_spawn_condition;
|
||||
Foo foo;
|
||||
|
||||
boost::mutex main_thread_mutex;
|
||||
boost::unique_lock < boost::mutex > main_thread_lock(main_thread_mutex);
|
||||
|
||||
//BOOST_LOG_TRIVIAL(info) << "[TaskScheduler::run_and_wait] Scheduling loop - BEGIN";
|
||||
|
||||
while (!foo.is_exiting()) {
|
||||
const TimePoint next_task_spawn_time = foo.spawn_tasks();
|
||||
|
||||
const TimePoint now = real_time_now();
|
||||
const TimePoint next_minimum_spawn_time = now + MIN_TIME_TASKS_SPAWN_FREQUENCY;
|
||||
const TimePoint next_spawn_time = next_task_spawn_time > TimePoint()
|
||||
&& next_task_spawn_time < next_minimum_spawn_time
|
||||
? next_task_spawn_time : next_minimum_spawn_time;
|
||||
|
||||
const TimePoint::duration wait_time = next_spawn_time - now;
|
||||
if (wait_time > wait_time.zero()) {
|
||||
// BOOST_LOG_TRIVIAL(trace) << "WAIT TIME: " << wait_time; // UNCOMMENT THIS: MAKES IT WORKS. WAT??????
|
||||
m_task_spawn_condition.wait_until(
|
||||
main_thread_lock,
|
||||
next_spawn_time); // DON'T WORK: WILL WAIT IF next_spawn_time is too close!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -129,7 +129,7 @@ struct non_copyable_functor:
|
||||
{
|
||||
unsigned value;
|
||||
|
||||
non_copyable_functor():
|
||||
non_copyable_functor(): boost::noncopyable(),
|
||||
value(0)
|
||||
{}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ void test_thread_callable_object_no_arguments()
|
||||
struct callable_noncopyable_no_args:
|
||||
boost::noncopyable
|
||||
{
|
||||
callable_noncopyable_no_args() : boost::noncopyable() {}
|
||||
static bool called;
|
||||
|
||||
void operator()() const
|
||||
|
||||
Reference in New Issue
Block a user