mirror of
https://github.com/boostorg/thread.git
synced 2026-02-08 11:12:23 +00:00
Compare commits
38 Commits
boost-1.55
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd51f97e44 | ||
|
|
04e3d918fb | ||
|
|
0073516f0a | ||
|
|
89de3dcf4f | ||
|
|
47f40f991f | ||
|
|
8b351fe473 | ||
|
|
24f1e620e8 | ||
|
|
ed6459ecd2 | ||
|
|
858816b2d2 | ||
|
|
4bc70444a4 | ||
|
|
fcc027369f | ||
|
|
5c78582794 | ||
|
|
7f479a1dec | ||
|
|
4f2a7b2256 | ||
|
|
5c88e6ce61 | ||
|
|
650e374492 | ||
|
|
6319080ef2 | ||
|
|
3ac48bdd65 | ||
|
|
c3c8ada97d | ||
|
|
fd5dd0c2ed | ||
|
|
4a83aa58ed | ||
|
|
7d96aa625c | ||
|
|
d57a4c6565 | ||
|
|
c67e39f126 | ||
|
|
5a3c301582 | ||
|
|
dc5a8a9c4e | ||
|
|
1e49343ff4 | ||
|
|
93d1855e64 | ||
|
|
a39dd7e8b3 | ||
|
|
7e5cb92bab | ||
|
|
62cf0f86f6 | ||
|
|
c12e07754a | ||
|
|
cbc4266774 | ||
|
|
3a038d33e5 | ||
|
|
51ba4be998 | ||
|
|
2d50af8481 | ||
|
|
e438c98070 | ||
|
|
1e2a76de47 |
@@ -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,32 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[/]
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
|
||||
[*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/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/8955 #8955] Request for more efficient way to get exception_ptr from future.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8891 #8891] upgrade_to_unique_lock: missing mutex() function.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
[/]
|
||||
* [@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 +425,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();
|
||||
|
||||
@@ -216,6 +216,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
static unsigned physical_concurrency() noexcept;
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
@@ -323,7 +324,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
|
||||
|
||||
@@ -458,6 +459,20 @@ any) to `*this`.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `thread::physical_concurrency()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -470,6 +470,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
static unsigned physical_concurrency() noexcept;
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
@@ -568,7 +569,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 +596,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 +624,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 +651,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 +680,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
|
||||
@@ -991,6 +992,21 @@ or 0 if this information is not available.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The number of physical cores available on the current system. In contrast to `hardware_concurrency()` it does not return
|
||||
the number of virtual cores, but it counts only physical cores.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
|
||||
@@ -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;
|
||||
{
|
||||
|
||||
61
example/not_interleaved2.cpp
Normal file
61
example/not_interleaved2.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// (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/ostream_buffer.hpp>
|
||||
|
||||
void use_cerr()
|
||||
{
|
||||
using namespace boost;
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
int i = 0;
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
ostream_buffer<std::ostream> mcerr(std::cerr);
|
||||
mcerr.stream() << "logging data to cerr " << i++ << "\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
|
||||
void use_cout()
|
||||
{
|
||||
using namespace boost;
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
int i = 0;
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << "logging data to cout " << i++ << "\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
scoped_thread<> t1(&use_cerr);
|
||||
scoped_thread<> t2(&use_cout);
|
||||
this_thread::sleep_for(chrono::seconds(2));
|
||||
std::string nm = "he, he\n";
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << "Enter name: \n";
|
||||
}
|
||||
t1.join();
|
||||
t2.join();
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << nm;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
147
example/thread_pool.cpp
Normal file
147
example/thread_pool.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
// 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_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/thread_pool.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void push(boost::container::deque<boost::detail::function_wrapper> &data_, BOOST_THREAD_RV_REF(boost::detail::function_wrapper) closure)
|
||||
{
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
boost::detail::function_wrapper v;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
//v = boost::move(closure);
|
||||
//v = boost::forward<boost::detail::function_wrapper>(closure);
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
data_.push_back(boost::move(closure));
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
//data_.push_back(boost::forward<boost::detail::function_wrapper>(closure));
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(boost::container::deque<boost::detail::function_wrapper> &data_, BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
//work w =boost::move(closure);
|
||||
//work_queue.push(boost::move(w));
|
||||
//push(data_, boost::detail::function_wrapper(boost::forward<Closure>(closure)));
|
||||
boost::detail::function_wrapper v =boost::forward<Closure>(closure);
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
push(data_, boost::move(v));
|
||||
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
#if 0
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::detail::function_wrapper f(&p1);
|
||||
|
||||
boost::container::deque<boost::detail::function_wrapper> data_;
|
||||
data_.push_back(boost::move(f));
|
||||
data_.push_back(boost::detail::function_wrapper(&p1));
|
||||
submit(data_, &p1);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
typedef boost::container::vector<boost::thread> thread_vector;
|
||||
thread_vector threads;
|
||||
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread_pool tp;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
tp.submit(&p1);
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
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))
|
||||
|
||||
94
include/boost/thread/detail/function_wrapper.hpp
Normal file
94
include/boost/thread/detail/function_wrapper.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// Make use of Boost.Move
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
|
||||
#define BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class function_wrapper
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual void call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
//typedef boost::interprocess::unique_ptr<impl_base, boost::default_delete<impl_base> > impl_base_type;
|
||||
impl_base* impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
impl_type(F const &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(function_wrapper)
|
||||
|
||||
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
function_wrapper(F const& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
//#endif
|
||||
template<typename F>
|
||||
function_wrapper(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<F>(boost::forward<F>(f)))
|
||||
{}
|
||||
function_wrapper(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
other.impl = 0;
|
||||
}
|
||||
function_wrapper()
|
||||
: impl(0)
|
||||
{
|
||||
}
|
||||
~function_wrapper()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
function_wrapper& operator=(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
other.impl=0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{ impl->call();}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -546,6 +546,7 @@ namespace boost
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
|
||||
static unsigned physical_concurrency() BOOST_NOEXCEPT;
|
||||
|
||||
#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
|
||||
typedef detail::thread_data_base::native_handle_type native_handle_type;
|
||||
@@ -826,6 +827,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
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace boost
|
||||
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;
|
||||
@@ -418,7 +418,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 +431,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 +445,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 +454,7 @@ namespace boost
|
||||
);
|
||||
}
|
||||
|
||||
bool has_exception()
|
||||
bool has_exception() const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mutex);
|
||||
return done && (exception
|
||||
@@ -463,7 +464,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 +473,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 +495,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 +689,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 +700,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 +761,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 +807,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&);
|
||||
@@ -1294,7 +1312,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 +1321,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;
|
||||
@@ -3938,13 +3963,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>(
|
||||
@@ -4056,13 +4081,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>(
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
35
include/boost/thread/ostream_buffer.hpp
Normal file
35
include/boost/thread/ostream_buffer.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// (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)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_OSTREAM_BUFFER_HPP
|
||||
#define BOOST_THREAD_OSTREAM_BUFFER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename OStream>
|
||||
class ostream_buffer
|
||||
{
|
||||
public:
|
||||
typedef std::basic_ostringstream<typename OStream::char_type, typename OStream::traits_type> stream_type;
|
||||
ostream_buffer(OStream& os) : os_(os) {}
|
||||
~ostream_buffer() { os_ << o_str_.str(); }
|
||||
stream_type& stream() { return o_str_; }
|
||||
private:
|
||||
OStream& os_;
|
||||
stream_type o_str_;
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -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>
|
||||
@@ -263,11 +261,15 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned hardware_concurrency()BOOST_NOEXCEPT
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
static unsigned physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::physical_concurrency();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,9 @@ namespace boost
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
|
||||
struct sync_queue_is_closed : std::exception {};
|
||||
struct sync_queue_is_closed : std::exception
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
@@ -155,6 +157,13 @@ namespace boost
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
@@ -408,9 +417,9 @@ namespace boost
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -529,7 +538,7 @@ namespace boost
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -548,7 +557,7 @@ namespace boost
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -563,7 +572,7 @@ namespace boost
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -575,7 +584,7 @@ namespace boost
|
||||
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));
|
||||
sbq.push(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ namespace boost
|
||||
inline void close();
|
||||
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
@@ -114,6 +115,12 @@ namespace boost
|
||||
elem = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front()));
|
||||
@@ -129,7 +136,7 @@ namespace boost
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push(boost::move(elem));
|
||||
data_.push_back(boost::move(elem));
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
@@ -346,9 +353,9 @@ namespace boost
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -431,7 +438,7 @@ namespace boost
|
||||
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);
|
||||
push(boost::move(elem), lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -441,7 +448,7 @@ namespace boost
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -460,7 +467,7 @@ namespace boost
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -476,7 +483,7 @@ namespace boost
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
push(boost::move(elem), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -488,7 +495,7 @@ namespace boost
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::forward<ValueType>(elem));
|
||||
sbq.push(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
192
include/boost/thread/thread_pool.hpp
Normal file
192
include/boost/thread/thread_pool.hpp
Normal file
@@ -0,0 +1,192 @@
|
||||
// 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)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// first implementation of a simple pool thread using a vector of threads and a sync_queue.
|
||||
|
||||
#ifndef BOOST_THREAD_THREAD_POOL_HPP
|
||||
#define BOOST_THREAD_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/detail/function_wrapper.hpp>
|
||||
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <boost/function.hpp>
|
||||
#else
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#include <boost/container/vector.hpp>
|
||||
#else
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class thread_pool
|
||||
{
|
||||
/// type-erasure to store the works to do
|
||||
typedef detail::function_wrapper work;
|
||||
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
|
||||
/// A move aware vector type
|
||||
typedef scoped_thread<> thread_t;
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
typedef container::vector<thread_t> thread_vector;
|
||||
#else
|
||||
typedef std::vector<thread_t> thread_vector;
|
||||
#endif
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
/// A move aware vector
|
||||
thread_vector threads;
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull(task))
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The main loop of the worker threads
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!is_closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// thread_pool is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(thread_pool)
|
||||
|
||||
/**
|
||||
* Effects: creates a thread pool that runs closures on @c thread_count threads.
|
||||
*/
|
||||
thread_pool(unsigned const thread_count = thread::hardware_concurrency())
|
||||
{
|
||||
try
|
||||
{
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
threads.push_back(thread_t(&thread_pool::worker_thread, this));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Effects: Destroys the thread pool.
|
||||
* Synchronization: The completion of all the closures happen before the completion of the thread pool destructor.
|
||||
*/
|
||||
~thread_pool()
|
||||
{
|
||||
// signal to all the worker threads that there will be no more submissions.
|
||||
close();
|
||||
// joins all the threads as the threads were scoped_threads
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: close the thread_pool for submissions. The worker threads will work until
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool is_closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: The specified function will be scheduled for execution at some point in the future.
|
||||
* If invoking closure throws an exception the thread pool will call std::terminate, as is the case with threads.
|
||||
* Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
* Throws: sync_queue_is_closed if the thread pool is closed.
|
||||
*
|
||||
*/
|
||||
template <typename Closure>
|
||||
void submit(Closure const& closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push(boost::move(w));
|
||||
//work_queue.push(work(closure));
|
||||
}
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push(boost::move(w));
|
||||
//work_queue.push(work(boost::move(closure)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be called from an scheduled task.
|
||||
* Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
void reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
schedule_one_or_yield();
|
||||
} while (! pred());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -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/win/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
|
||||
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "./timeconv.inl"
|
||||
|
||||
namespace boost
|
||||
@@ -187,7 +196,9 @@ namespace boost
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
namespace detail
|
||||
{
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
@@ -197,7 +208,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 +224,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(detail::heap_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();
|
||||
@@ -536,6 +552,56 @@ namespace boost
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
#ifdef __linux__
|
||||
try {
|
||||
using namespace std;
|
||||
|
||||
ifstream proc_cpuinfo ("/proc/cpuinfo");
|
||||
|
||||
unsigned current_processor = 0;
|
||||
const string physical_id("physical id"), core_id("core id");
|
||||
|
||||
typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
|
||||
|
||||
std::set<core_entry> cores;
|
||||
|
||||
core_entry current_core_entry;
|
||||
|
||||
for (string line; getline(proc_cpuinfo, line); ) {
|
||||
vector<string> key_val(2);
|
||||
boost::split(key_val, line, boost::is_any_of(":"));
|
||||
|
||||
string key = key_val[0];
|
||||
string value = key_val[1];
|
||||
boost::trim(key);
|
||||
boost::trim(value);
|
||||
|
||||
if (key == physical_id) {
|
||||
current_core_entry.first = boost::lexical_cast<unsigned>(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == core_id) {
|
||||
current_core_entry.second = boost::lexical_cast<unsigned>(value);
|
||||
cores.insert(current_core_entry);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return cores.size();
|
||||
} catch(...) {
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
|
||||
#else
|
||||
return hardware_concurrency();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void thread::interrupt()
|
||||
{
|
||||
@@ -663,7 +729,7 @@ namespace boost
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
|
||||
heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
@@ -701,8 +767,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 +809,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
{}
|
||||
@@ -400,6 +407,8 @@ namespace boost
|
||||
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
//SYSTEM_INFO info={{0}};
|
||||
@@ -407,7 +416,28 @@ namespace boost
|
||||
GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned cores = 0;
|
||||
DWORD size = 0;
|
||||
|
||||
GetLogicalProcessorInformation(NULL, &size);
|
||||
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
||||
return 0;
|
||||
|
||||
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
|
||||
if (GetLogicalProcessorInformation(buffer.data(), &size) == FALSE)
|
||||
return 0;
|
||||
|
||||
const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||
|
||||
for (size_t i = 0; i < Elements; ++i) {
|
||||
if (buffer[i].Relationship == RelationProcessorCore)
|
||||
++cores;
|
||||
}
|
||||
return cores;
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
@@ -429,7 +459,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 +777,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);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
@@ -209,6 +209,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-test test_thread.cpp ]
|
||||
[ thread-test test_thread_id.cpp ]
|
||||
[ thread-test test_hardware_concurrency.cpp ]
|
||||
[ thread-test test_physical_concurrency.cpp ]
|
||||
[ thread-test test_thread_move.cpp ]
|
||||
[ thread-test test_thread_return_local.cpp ]
|
||||
[ thread-test test_thread_move_return.cpp ]
|
||||
@@ -716,6 +717,8 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ 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 ]
|
||||
[ thread-run2 ../example/not_interleaved2.cpp : ex_not_interleaved2 ]
|
||||
[ thread-run2 ../example/thread_pool.cpp : ex_thread_pool ]
|
||||
|
||||
;
|
||||
|
||||
@@ -768,6 +771,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 +793,14 @@ 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 ]
|
||||
#[ thread-run clang_main.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;
|
||||
|
||||
|
||||
@@ -15,6 +15,26 @@
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
class non_copyable
|
||||
{
|
||||
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
||||
int val;
|
||||
public:
|
||||
non_copyable() {}
|
||||
non_copyable(int v) : val(v){}
|
||||
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
|
||||
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
|
||||
bool operator==(non_copyable const& x) const {return val==x.val;}
|
||||
template <typename OSTREAM>
|
||||
friend OSTREAM& operator <<(OSTREAM& os, non_copyable const&x )
|
||||
{
|
||||
os << x.val;
|
||||
return os;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
@@ -55,6 +75,16 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue push rvalue succeeds
|
||||
boost::sync_bounded_queue<non_copyable> q(2);
|
||||
non_copyable nc(1);
|
||||
q.push(boost::move(nc));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue push rvalue succeeds
|
||||
boost::sync_bounded_queue<int> q(2);
|
||||
@@ -84,6 +114,16 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue try_push rvalue succeeds
|
||||
boost::sync_bounded_queue<non_copyable> q(2);
|
||||
non_copyable nc(1);
|
||||
BOOST_TEST(q.try_push(boost::move(nc)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue try_push value succeeds
|
||||
boost::sync_bounded_queue<int> q(2);
|
||||
@@ -103,6 +143,16 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue try_push rvalue succeeds
|
||||
boost::sync_bounded_queue<non_copyable> q(2);
|
||||
non_copyable nc(1);
|
||||
BOOST_TEST(q.try_push(boost::no_block, boost::move(nc)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_bounded_queue<int> q(2);
|
||||
@@ -115,6 +165,19 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_bounded_queue<non_copyable> q(2);
|
||||
non_copyable nc(1);
|
||||
q.push(boost::move(nc));
|
||||
non_copyable nc2(2);
|
||||
q.pull(nc2);
|
||||
BOOST_TEST_EQ(nc, nc2);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_bounded_queue<int> q(2);
|
||||
|
||||
@@ -15,6 +15,26 @@
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
class non_copyable
|
||||
{
|
||||
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
||||
int val;
|
||||
public:
|
||||
non_copyable(int v) : val(v){}
|
||||
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
|
||||
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
|
||||
bool operator==(non_copyable const& x) const {return val==x.val;}
|
||||
template <typename OSTREAM>
|
||||
friend OSTREAM& operator <<(OSTREAM& os, non_copyable const&x )
|
||||
{
|
||||
os << x.val;
|
||||
return os;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
@@ -46,7 +66,7 @@ int main()
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue push rvalue succeeds
|
||||
// empty queue push rvalue/copyable succeeds
|
||||
boost::sync_queue<int> q;
|
||||
q.push(1);
|
||||
BOOST_TEST(! q.empty());
|
||||
@@ -54,6 +74,38 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue push lvalue/copyable succeeds
|
||||
boost::sync_queue<int> q;
|
||||
int i;
|
||||
q.push(i);
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
// empty queue push rvalue/non_copyable succeeds
|
||||
boost::sync_queue<non_copyable> q;
|
||||
q.push(non_copyable(1));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// empty queue push rvalue/non_copyable succeeds
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc(1);
|
||||
q.push(boost::move(nc));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
|
||||
{
|
||||
// empty queue push rvalue succeeds
|
||||
boost::sync_queue<int> q;
|
||||
@@ -65,7 +117,7 @@ int main()
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue push value succeeds
|
||||
// empty queue push lvalue succeeds
|
||||
boost::sync_queue<int> q;
|
||||
int i;
|
||||
q.push(i);
|
||||
@@ -75,7 +127,7 @@ int main()
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue try_push rvalue succeeds
|
||||
// empty queue try_push rvalue/copyable succeeds
|
||||
boost::sync_queue<int> q;
|
||||
BOOST_TEST(q.try_push(1));
|
||||
BOOST_TEST(! q.empty());
|
||||
@@ -84,7 +136,38 @@ int main()
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// empty queue try_push value succeeds
|
||||
// empty queue try_push rvalue/copyable succeeds
|
||||
boost::sync_queue<int> q;
|
||||
BOOST_TEST(q.try_push(1));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
// empty queue try_push rvalue/non-copyable succeeds
|
||||
boost::sync_queue<non_copyable> q;
|
||||
BOOST_TEST(q.try_push(non_copyable()));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// empty queue try_push rvalue/non-copyable succeeds
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc(1);
|
||||
BOOST_TEST(q.try_push(boost::move(nc)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
|
||||
{
|
||||
// empty queue try_push lvalue succeeds
|
||||
boost::sync_queue<int> q;
|
||||
int i;
|
||||
BOOST_TEST(q.try_push(i));
|
||||
@@ -102,6 +185,27 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
// empty queue try_push rvalue/non-copyable succeeds
|
||||
boost::sync_queue<non_copyable> q;
|
||||
BOOST_TEST(q.try_push(boost::no_block, non_copyable(1)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// empty queue try_push rvalue/non-copyable succeeds
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc(1);
|
||||
BOOST_TEST(q.try_push(boost::no_block, boost::move(nc)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_queue<int> q;
|
||||
@@ -114,6 +218,19 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc2(2);
|
||||
q.pull(nc2);
|
||||
BOOST_TEST_EQ(nc1, nc2);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_queue<int> q;
|
||||
@@ -125,6 +242,18 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc = q.pull();
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::sync_queue<int> q;
|
||||
@@ -137,6 +266,19 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc(2);
|
||||
BOOST_TEST(q.try_pull(nc));
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::sync_queue<int> q;
|
||||
@@ -149,6 +291,19 @@ int main()
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::sync_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc(2);
|
||||
BOOST_TEST(q.try_pull(boost::no_block, nc));
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::sync_queue<int> q;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
18
test/test_8586.cpp
Normal file
18
test/test_8586.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
void hello_world()
|
||||
{
|
||||
std::cout << "Hello from thread!" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread my_thread(&hello_world);
|
||||
my_thread.join();
|
||||
}
|
||||
140
test/test_8600.cpp
Normal file
140
test/test_8600.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
// 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/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#if 1
|
||||
|
||||
struct B {
|
||||
int v;
|
||||
B(int i) : v(i) {}
|
||||
};
|
||||
|
||||
struct D: B {
|
||||
D(int i) : B(i) {}
|
||||
};
|
||||
|
||||
void fb(B const&) {}
|
||||
void fd(D const&) {}
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(B)==sizeof(D));
|
||||
|
||||
template <class T, class Allocator=std::allocator<T> >
|
||||
class new_vector;
|
||||
template <class T, class Allocator>
|
||||
class new_vector : public std::vector<T,Allocator>
|
||||
{
|
||||
typedef std::vector<T,Allocator> base_type;
|
||||
public:
|
||||
new_vector() : base_type() {}
|
||||
new_vector(unsigned s) : base_type(s) {}
|
||||
};
|
||||
|
||||
template <class Allocator >
|
||||
class new_vector<bool, Allocator>
|
||||
{
|
||||
//std::vector<char,typename Allocator::template rebind<char>::other > v;
|
||||
int i;
|
||||
public:
|
||||
};
|
||||
|
||||
template <class T, class A>
|
||||
typename std::enable_if<!std::is_same<T, bool>::value,
|
||||
new_vector<T,A>&
|
||||
>::type
|
||||
new_vector_cast(std::vector<T,A> & v) {
|
||||
return reinterpret_cast<new_vector<T,A>&>(v);
|
||||
}
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(std::vector<int>)==sizeof(new_vector<int>));
|
||||
BOOST_STATIC_ASSERT(sizeof(std::vector<bool>)!=sizeof(new_vector<bool>));
|
||||
|
||||
void fb(std::vector<int> const&) {}
|
||||
void fd(new_vector<int> const&) {}
|
||||
|
||||
int main() {
|
||||
{
|
||||
std::vector<int> b(1);
|
||||
b[0] = 1;
|
||||
new_vector<int> d = new_vector_cast(b);
|
||||
BOOST_ASSERT(b[0] == d[0]);
|
||||
}
|
||||
{
|
||||
//std::vector<bool> b;
|
||||
//new_vector<bool> d = new_vector_cast(b); // compile fail
|
||||
}
|
||||
{
|
||||
std::vector<int> b(1);
|
||||
b[0] = 1;
|
||||
fd(new_vector_cast(b));
|
||||
}
|
||||
{
|
||||
new_vector<int> d(1);
|
||||
d[0] = 1;
|
||||
std::vector<int> b = d;
|
||||
BOOST_ASSERT(b[0] == d[0]);
|
||||
}
|
||||
{
|
||||
//new_vector<bool> d;
|
||||
//std::vector<bool> b = d; // compile fail
|
||||
}
|
||||
{
|
||||
new_vector<int> d(1);
|
||||
d[0] = 1;
|
||||
fd(d);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
int main() {
|
||||
{
|
||||
B b(1);
|
||||
D d = reinterpret_cast<D&>(b);
|
||||
BOOST_ASSERT(b.v == d.v);
|
||||
}
|
||||
{
|
||||
B b(1);
|
||||
fd(reinterpret_cast<D&>(b));
|
||||
}
|
||||
{
|
||||
D d(2);
|
||||
B b = d;
|
||||
BOOST_ASSERT(b.v == d.v);
|
||||
}
|
||||
{
|
||||
D d(2);
|
||||
fd(d);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
int calculate_the_answer_to_life_the_universe_and_everything()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::packaged_task<int()> pt(calculate_the_answer_to_life_the_universe_and_everything);
|
||||
boost::shared_future<int> fi1 = boost::shared_future<int>(pt.get_future());
|
||||
boost::shared_future<int> fi2 = fi1;
|
||||
|
||||
boost::thread task(boost::move(pt)); // launch task on a thread
|
||||
|
||||
boost::wait_for_any(fi1, fi2);
|
||||
std::cout << "Wait for any returned\n";
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
47
test/test_8943.cpp
Normal file
47
test/test_8943.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
class foo
|
||||
{
|
||||
public:
|
||||
void operator()() const
|
||||
{
|
||||
std::cout << "foo" << std::endl;
|
||||
}
|
||||
}; // class foo
|
||||
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
|
||||
#else
|
||||
int main(int /*argc*/, char* /*argv*/[])
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::once_flag once_flag = BOOST_ONCE_INIT;
|
||||
boost::call_once(once_flag, foo());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown exception" << std::endl;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
return boost::report_errors();
|
||||
}
|
||||
53
test/test_8960.cpp
Normal file
53
test/test_8960.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
//#include <boost/bind.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
|
||||
void do_thread()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
boost::condition_variable c1;
|
||||
boost::mutex m1;
|
||||
boost::unique_lock<boost::mutex> l1(m1);
|
||||
|
||||
c1.wait_for(l1, boost::chrono::seconds(1));
|
||||
}
|
||||
catch (std::runtime_error& ex)
|
||||
{
|
||||
std::cout << "EXCEPTION ! " << ex.what() << std::endl;
|
||||
BOOST_TEST(false);
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "EXCEPTION ! " << std::endl;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
boost::thread th1(&do_thread);
|
||||
th1.join();
|
||||
|
||||
//std::string s1;
|
||||
//std::cin >> s1;
|
||||
|
||||
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!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
24
test/test_physical_concurrency.cpp
Normal file
24
test/test_physical_concurrency.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
// Copyright (C) 2013 Tim Blechmann
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
void test_physical_concurrency_is_non_zero()
|
||||
{
|
||||
BOOST_CHECK(boost::thread::physical_concurrency()!=0);
|
||||
}
|
||||
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: physical concurrency test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_physical_concurrency_is_non_zero));
|
||||
return test;
|
||||
}
|
||||
|
||||
|
||||
@@ -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