mirror of
https://github.com/boostorg/thread.git
synced 2026-02-07 23:02:13 +00:00
Compare commits
8 Commits
boost-1.54
...
boost-1.54
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57bd3b0769 | ||
|
|
6225c8309a | ||
|
|
fe8991b7fa | ||
|
|
f4fb2c1ab0 | ||
|
|
582649ed44 | ||
|
|
74891c9836 | ||
|
|
9dd08547f7 | ||
|
|
c6dbb0c9a5 |
@@ -263,8 +263,11 @@ rule requirements ( properties * )
|
||||
result = <build>no ;
|
||||
}
|
||||
}
|
||||
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
|
||||
} else {
|
||||
result += <define>BOOST_THREAD_USES_CHRONO ;
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
|
||||
|
||||
if <toolset>pgi in $(properties) || <toolset>vacpp in $(properties)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-12 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-13 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).
|
||||
@@ -13,9 +13,14 @@
|
||||
|
||||
[*New Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro:Add externally locked streams.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro:Add concurrent queue.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
|
||||
* [@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.
|
||||
* [@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.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
@@ -50,10 +55,19 @@
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8323 #8323] boost::thread::try_join_for/try_join_until may block indefinitely due to a combination of problems in Boost.Thread and Boost.Chrono
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8337 #8337] The internal representation of "std::string(this->code()->message())" escapes, but is destroyed when it exits scope.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8371 #8371] C++11 once_flag enabled when constexpr is not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8422 #8422] Assertion in win32::WaitForSingleObject()
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8443 #8443] Header file inclusion order may cause crashes
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8451 #8451] Missing documented function 'boost::scoped_thread::joinable'
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8458 #8458] -DBOOST_THREAD_DONT_USE_CHRONO in thread.obj.rsp but not explicitly set
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8530 #8530] [Coverity] Unused variable thread_handle, uninitialized variable cond_mutex in thread/pthread/thread_data.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8550 #8550] static linking of Boost.Thread with an MFC-Dll
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8576 #8576] "sur parolle" should be "sur parole".
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8596 #8596] With C++0x enabled, boost::packaged_task stores a reference to function objects, instead of a copy.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8626 #8626] Reintroduce BOOST_VERIFY on pthread_mutex_destroy return type
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8645 #8645] Typo in Strict lock definition
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8671 #8671] promise: set_..._at_thread_exit
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8672 #8672] future<>::then(void()) doesn't works
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8674 #8674] Futures as local named objects can't be returned with implicit move.
|
||||
|
||||
[heading Version 4.0.0 - boost 1.53]
|
||||
|
||||
@@ -405,7 +419,7 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/XXXX #XXXX] Sync: Add a completion_latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Sync: Add a completion_latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
|
||||
|
||||
@@ -414,11 +428,15 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic future/shared_future::then
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap.
|
||||
|
||||
# And some additional extensions related to futures as:
|
||||
|
||||
* [@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/8517 #8517] Async: Add a variadic shared_future::then.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
[[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Yes] [-] [-]]
|
||||
[[30.4.2.2.2] [unique_lock locking] [Yes] [-] [-]]
|
||||
[[30.4.2.2.3] [unique_lock modifiers] [Yes] [-] [-]]
|
||||
[[30.4.2.2.4] [unique_lock observers] [Yes] [] [-]]
|
||||
[[30.4.2.2.4] [unique_lock observers] [Yes] [ - ] [-]]
|
||||
[[30.4.3] [Generic locking algorithms] [Partial] [variadic] [#6227]]
|
||||
[[30.4.4] [Call once] [Yes] [-] [-]]
|
||||
[[30.4.4.1] [Struct once_flag] [Yes] [-] [-]]
|
||||
@@ -107,6 +107,7 @@
|
||||
[section:latch C++ Latches and Barriers]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3659 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3666.html N3659 C++ Latches and Barriers]]
|
||||
|
||||
[table C++ Latches and Barriers Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
@@ -125,10 +126,10 @@
|
||||
[[X.1.1] [Basic Operations] [Partial] [ - ]]
|
||||
[[X.1.1.1] [push] [yes] [ - ]]
|
||||
[[X.1.1.2] [value_pop] [no] [ renamed pull with two flavors + a ptr_pull that returns a sharted_ptr<>. ]]
|
||||
[[X.1.2] [Non-waiting operations] [] [ - ]]
|
||||
[[X.1.2] [Non-waiting operations] [ - ] [ - ]]
|
||||
[[X.1.2.1] [try_push] [Partial] [ return bool instead ]]
|
||||
[[X.1.2.2] [try_pop] [Partial] [ renamed try_pull, returns null ]]
|
||||
[[X.1.3] [Non-blocking operations] [] [ - ]]
|
||||
[[X.1.3] [Non-blocking operations] [ - ] [ - ]]
|
||||
[[X.1.3.1] [nonblocking_push] [Partial] [ renamed try_push(no_block, ]]
|
||||
[[X.1.3.2] [nonblocking_pop] [Partial] [ renamed try_pop(no_block, ]]
|
||||
[[X.1.4] [Push-front operations] [No] [ - ]]
|
||||
@@ -148,15 +149,15 @@
|
||||
[[X.1.9] [Exception Handling] [Yes?] [ - ]]
|
||||
[[X.1.10] [Queue Ordering] [Yes?] [ - ]]
|
||||
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Move aware. ]]
|
||||
[[X.2] [Concrete queues] [Partial] [ ]]
|
||||
[[X.2] [Concrete queues] [Partial] [ - ]]
|
||||
[[X.2.1] [Locking Buffer Queue] [Partial] [ classes sync_queue and a sync_bounded_queue. ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ ]]
|
||||
[[X.3] [Additional Conceptual Tools] [No] [ ]]
|
||||
[[X.3.1] [Fronts and Backs] [No] [ ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ ]]
|
||||
[[X.3.3] [Storage Iterators] [No] [ ]]
|
||||
[[X.3.4] [Binary Interfaces] [No] [ ]]
|
||||
[[X.3.4] [Managed Indirection] [No] [ ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ - ]]
|
||||
[[X.3] [Additional Conceptual Tools] [No] [ - ]]
|
||||
[[X.3.1] [Fronts and Backs] [No] [ - ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ - ]]
|
||||
[[X.3.3] [Storage Iterators] [No] [ - ]]
|
||||
[[X.3.4] [Binary Interfaces] [No] [ - ]]
|
||||
[[X.3.4] [Managed Indirection] [No] [ - ]]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
@@ -192,17 +193,18 @@ While Boost.Thread implementation of executors would not use dynamic polymorphis
|
||||
[section:async A Standardized Representation of Asynchronous Operations]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf N3558 A Standardized Representation of Asynchronous Operations]]
|
||||
[note These functions are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
|
||||
[table A Standardized Representation of Asynchronous Operations Conformance
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.6.6] [Class template future] [Partial] [ - ]]
|
||||
[[30.6.6.1] [then] [Partial] [ executor interface missing #8516 ]]
|
||||
[[30.6.6.2] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.6.3] [ready] [yes] [ is_ready ]]
|
||||
[[30.6.6.2] [unwrap] [Yes] [ - ]]
|
||||
[[30.6.6.3] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
|
||||
[[30.6.7.1] [then] [No] [ #8515 ]]
|
||||
[[30.6.7.1] [then] [Yes] [ executor interface missing #8516 ]]
|
||||
[[30.6.7.2] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7.3] [ready] [Yes] [ is_ready ]]
|
||||
[[30.6.7.3] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_any] [No] [ #7446 ]]
|
||||
[[30.6.X] [Function template when_all] [No] [ #7447 ]]
|
||||
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
|
||||
@@ -211,11 +213,11 @@ While Boost.Thread implementation of executors would not use dynamic polymorphis
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stream_mutex C++ Stream Mutexes]
|
||||
[section:stream_mutex C++ Stream Mutexes - C++ Stream Guards]
|
||||
|
||||
While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html N3535 - C++ Stream Mutexes]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html N3535 - C++ Stream Mutexes]. This has been replaced already by N3678 - C++ Stream Guards.]
|
||||
|
||||
[table C++ C++ Stream MutexesConformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
@@ -234,6 +236,9 @@ While Boost.Thread implementation of stream mutexes differ in the approach, it i
|
||||
[[X.4] [Predefined Objects] [No] [.]]
|
||||
]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3678 - C++ Stream Guards]]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
[table Default Values for Configurable Features
|
||||
[[Feature] [Anti-Feature] [V2] [V3] [V4] ]
|
||||
[[USES_CHRONO] [DONT_USE_CHRONO] [YES] [YES] [YES] ]
|
||||
[[USES_CHRONO] [DONT_USE_CHRONO] [YES/NO] [YES/NO] [YES/NO] ]
|
||||
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ]
|
||||
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ]
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] ]
|
||||
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] ]
|
||||
|
||||
[[USES_DATETIME] [DONT_USE_DATETIME] [YES] [YES] [YES/NO] ]
|
||||
[[USES_DATETIME] [DONT_USE_DATETIME] [YES/NO] [YES/NO] [YES/NO] ]
|
||||
[[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] ]
|
||||
@@ -47,6 +47,8 @@
|
||||
|
||||
Boost.Thread uses by default Boost.Chrono for the time related functions and define `BOOST_THREAD_USES_CHRONO` if `BOOST_THREAD_DONT_USE_CHRONO` is not defined. The user should define `BOOST_THREAD_DONT_USE_CHRONO` for compilers that don't work well with Boost.Chrono.
|
||||
|
||||
[warning When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_CHRONO is defined independently of user settings.]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -72,7 +74,7 @@ The Boost.DateTime time related functions introduced in Boost 1.35.0, using the
|
||||
When `BOOST_THREAD_VERSION<=3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `BOOST_THREAD_DONT_USE_DATETIME` if you don't want to use Boost.DateTime related interfaces.
|
||||
When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `BOOST_THREAD_USES_DATETIME` if you want to use Boost.DateTime related interfaces.
|
||||
|
||||
When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_DATETIME is defined by default.
|
||||
[warning When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_DATETIME is defined independently of user settings.]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -182,10 +182,12 @@ For now, let's make a couple of enhancements to the `lock_guard` class template
|
||||
We'll call the enhanced version `strict_lock`. Essentially, a `strict_lock`'s role is only to live on the stack as an automatic variable.
|
||||
`strict_lock` must adhere to a non-copy and non-alias policy.
|
||||
`strict_lock` disables copying by making the copy constructor and the assignment operator private.
|
||||
While we're at it, let's disable operator new and operator delete;
|
||||
While we're at it, let's disable operator new and operator delete.
|
||||
|
||||
[/
|
||||
`strict_lock` are not intended to be allocated on the heap.
|
||||
`strict_lock` avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.
|
||||
|
||||
]
|
||||
|
||||
template <typename Lockable>
|
||||
class strict_lock {
|
||||
@@ -229,6 +231,7 @@ Silence can be sometimes louder than words-what's forbidden to do with a `strict
|
||||
// ok, Bar takes a reference to strict_lock<BankAccount>
|
||||
extern void Bar(strict_lock<BankAccount>&);
|
||||
|
||||
[/
|
||||
* You cannot allocate a `strict_lock` on the heap. However, you still can put `strict_lock`s on the heap if they're members of a class.
|
||||
|
||||
strict_lock<BankAccount>* pL =
|
||||
@@ -250,8 +253,9 @@ Silence can be sometimes louder than words-what's forbidden to do with a `strict
|
||||
strict_lock<BankAccount>& rAlias = myLock; // ok
|
||||
|
||||
Fortunately, references don't engender as bad aliasing as pointers because they're much less versatile (references cannot be copied or reseated).
|
||||
|
||||
* You can even make `strict_lock` final; that is, impossible to derive from. This task is left in the form of an exercise to the reader.
|
||||
]
|
||||
[/* You can even make `strict_lock` final; that is, impossible to derive from. This task is left in the form of an exercise to the reader.
|
||||
]
|
||||
|
||||
All these rules were put in place with one purpose-enforcing that owning a `strict_lock<T>` is a reasonably strong guarantee that
|
||||
|
||||
@@ -398,8 +402,8 @@ The solution is to use a little bridge template `externally_locked` that control
|
||||
|
||||
T& get(strict_lock<Lockable>& lock) {
|
||||
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME // define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME if you don't want to check locker check the same lockable
|
||||
if (!lock.is_locking(&lockable_)) throw lock_error(); run time check throw if not locks the same
|
||||
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if (!lock.owns_lock(&lockable_)) throw lock_error(); run time check throw if not locks the same
|
||||
#endif
|
||||
return obj_;
|
||||
}
|
||||
@@ -478,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 parolle". 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. Ths is really nice.
|
||||
|
||||
Now we need to state that both classes are `strict_lock`s.
|
||||
|
||||
@@ -508,7 +512,7 @@ First `nested_strict_lock` class will store on a temporary lock the `Locker`, an
|
||||
: lock_(lock) // Store reference to locker
|
||||
, tmp_lock_(lock.move()) // Move ownership to temporaty locker
|
||||
{
|
||||
#ifndef BOOST_THREAD_STRCIT_LOCKER_DONT_CHECK_OWNERSHIP // Define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP if you don't want to check locker ownership
|
||||
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if (tmp_lock_.mutex()==0) {
|
||||
lock_=tmp_lock_.move(); // Rollback for coherency purposes
|
||||
throw lock_error();
|
||||
@@ -519,24 +523,29 @@ First `nested_strict_lock` class will store on a temporary lock the `Locker`, an
|
||||
~nested_strict_lock() {
|
||||
lock_=tmp_lock_.move(); // Move ownership to nesting locker
|
||||
}
|
||||
typedef bool (nested_strict_lock::*bool_type)() const;
|
||||
operator bool_type() const { return &nested_strict_lock::owns_lock; }
|
||||
bool operator!() const { return false; }
|
||||
bool owns_lock() const { return true; }
|
||||
const lockable_type* mutex() const { return tmp_lock_.mutex(); }
|
||||
bool is_locking(lockable_type* l) const { return l==mutex(); }
|
||||
lockable_type* mutex() const { return tmp_lock_.mutex(); }
|
||||
bool owns_lock(lockable_type* l) const { return l==mutex(); }
|
||||
|
||||
BOOST_ADRESS_OF_DELETE(nested_strict_lock)
|
||||
BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
|
||||
BOOST_DEFAULT_CONSTRUCTOR_DELETE(nested_strict_lock) 8
|
||||
BOOST_COPY_CONSTRUCTOR_DELETE(nested_strict_lock) 9
|
||||
BOOST_COPY_ASSIGNEMENT_DELETE(nested_strict_lock) 10
|
||||
|
||||
private:
|
||||
Locker& lock_;
|
||||
Locker tmp_lock_;
|
||||
};
|
||||
|
||||
[/
|
||||
typedef bool (nested_strict_lock::*bool_type)() const;
|
||||
operator bool_type() const { return &nested_strict_lock::owns_lock; }
|
||||
bool operator!() const { return false; }
|
||||
|
||||
BOOST_ADRESS_OF_DELETE(nested_strict_lock)
|
||||
BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
|
||||
BOOST_DEFAULT_CONSTRUCTOR_DELETE(nested_strict_lock)
|
||||
BOOST_COPY_CONSTRUCTOR_DELETE(nested_strict_lock)
|
||||
BOOST_COPY_ASSIGNEMENT_DELETE(nested_strict_lock)
|
||||
|
||||
]
|
||||
|
||||
The `externally_locked` get function is now a template function taking a Locker as parameters instead of a `strict_lock`.
|
||||
We can add test in debug mode that ensure that the Lockable object is locked.
|
||||
|
||||
@@ -548,14 +557,14 @@ We can add test in debug mode that ensure that the Lockable object is locked.
|
||||
T& get(Locker& lock) {
|
||||
BOOST_CONCEPT_ASSERT((StrictLockerConcept<Locker>));
|
||||
|
||||
BOOST_STATIC_ASSERT((is_strict_lock<Locker>::value)); // locker is a strict locker "sur parolle"
|
||||
BOOST_STATIC_ASSERT((is_strict_lock<Locker>::value)); // locker is a strict locker "sur parole"
|
||||
BOOST_STATIC_ASSERT((is_same<Lockable,
|
||||
typename lockable_type<Locker>::type>::value)); // that locks the same type
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP // define BOOST_THREAD_EXTERNALLY_LOCKED_NO_CHECK_OWNERSHIP if you don't want to check locker ownership
|
||||
if (! lock ) throw lock_error(); // run time check throw if no locked
|
||||
#endif
|
||||
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME
|
||||
if (!lock.is_locking(&lockable_)) throw lock_error();
|
||||
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if (!lock.owns_lock(&lockable_)) throw lock_error();
|
||||
#endif
|
||||
return obj_;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ This trait is true_type if the parameter L meets the __Lockable requirements.
|
||||
The user could require that the mutex passed to an algorithm is a recursive one. Whether a lockable is recursive or not can not be checked using template meta-programming. This is the motivation for the following trait.
|
||||
|
||||
|
||||
[section:is_recursive_mutex_sur_parolle `is_recursive_mutex_sur_parolle` trait -- EXTENSION]
|
||||
[section:is_recursive_mutex_sur_parole `is_recursive_mutex_sur_parole` trait -- EXTENSION]
|
||||
|
||||
// #include <boost/thread/lockable_traits.hpp>
|
||||
|
||||
@@ -185,15 +185,15 @@ The user could require that the mutex passed to an algorithm is a recursive one.
|
||||
namespace sync
|
||||
{
|
||||
template<typename L>
|
||||
class is_recursive_mutex_sur_parolle: false_type; // EXTENSION
|
||||
class is_recursive_mutex_sur_parole: false_type; // EXTENSION
|
||||
template<>
|
||||
class is_recursive_mutex_sur_parolle<recursive_mutex>: true_type; // EXTENSION
|
||||
class is_recursive_mutex_sur_parole<recursive_mutex>: true_type; // EXTENSION
|
||||
template<>
|
||||
class is_recursive_mutex_sur_parolle<timed_recursive_mutex>: true_type; // EXTENSION
|
||||
class is_recursive_mutex_sur_parole<timed_recursive_mutex>: true_type; // EXTENSION
|
||||
}
|
||||
}
|
||||
|
||||
The trait `is_recursive_mutex_sur_parolle` is `false_type` by default and is specialized for the provide `recursive_mutex` and `timed_recursive_mutex`.
|
||||
The trait `is_recursive_mutex_sur_parole` is `false_type` by default and is specialized for the provide `recursive_mutex` and `timed_recursive_mutex`.
|
||||
|
||||
It should be specialized by the user providing other model of recursive lockable.
|
||||
|
||||
@@ -211,7 +211,7 @@ It should be specialized by the user providing other model of recursive lockable
|
||||
}
|
||||
}
|
||||
|
||||
This traits is true_type if is_basic_lockable and is_recursive_mutex_sur_parolle.
|
||||
This traits is true_type if is_basic_lockable and is_recursive_mutex_sur_parole.
|
||||
|
||||
[endsect]
|
||||
[section:is_recursive_lockable `is_recursive_lockable` trait -- EXTENSION]
|
||||
@@ -226,7 +226,7 @@ This traits is true_type if is_basic_lockable and is_recursive_mutex_sur_parolle
|
||||
}
|
||||
}
|
||||
|
||||
This traits is true_type if is_lockable and is_recursive_mutex_sur_parolle.
|
||||
This traits is true_type if is_lockable and is_recursive_mutex_sur_parole.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -344,14 +344,14 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared_lockable `SharedLockable` Concept -- EXTENSION]
|
||||
[section:shared_lockable `SharedLockable` Concept -- C++14]
|
||||
|
||||
// #include <boost/thread/lockable_concepts.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<typename L>
|
||||
class SharedLockable; // EXTENSION
|
||||
class SharedLockable; // C++14
|
||||
}
|
||||
|
||||
|
||||
@@ -1135,7 +1135,7 @@ object passed to the constructor.]]
|
||||
}
|
||||
|
||||
|
||||
A StrictLock is a lock that ensures that the associated mutex is locked during the lifetime if the lock.
|
||||
A StrictLock is a lock that ensures that the associated mutex is locked during the lifetime of the lock.
|
||||
|
||||
A type `L` meets the StrictLock requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
@@ -1156,13 +1156,13 @@ The type L::mutex_type denotes the mutex that is locked by this lock.
|
||||
|
||||
[endsect] [/ mutex_type]
|
||||
|
||||
[section:is_strict_lock_sur_parolle `is_strict_lock_sur_parolle<L>`]
|
||||
[section:is_strict_lock_sur_parole `is_strict_lock_sur_parole<L>`]
|
||||
|
||||
As the semantic "ensures that the associated mutex is locked during the lifetime if the lock. " can not be described by syntactic requirements a `is_strict_lock_sur_parolle` trait must be specialized by the user defining the lock so that the following assertion is true:
|
||||
As the semantic "ensures that the associated mutex is locked during the lifetime of the lock. " can not be described by syntactic requirements a `is_strict_lock_sur_parole` trait must be specialized by the user defining the lock so that the following assertion is true:
|
||||
|
||||
is_strict_lock_sur_parolle<L>::value == true
|
||||
is_strict_lock_sur_parole<L>::value == true
|
||||
|
||||
[endsect] [/ is_strict_lock_sur_parolle]
|
||||
[endsect] [/ is_strict_lock_sur_parole]
|
||||
|
||||
[section:owns_lock `cl.owns_lock(m);`]
|
||||
|
||||
@@ -1183,8 +1183,8 @@ As the semantic "ensures that the associated mutex is locked during the lifetime
|
||||
The following classes are models of `StrictLock`:
|
||||
|
||||
* strict_lock: ensured by construction,
|
||||
* nested_strict_lock: "sur parolle" as the user could use adopt_lock_t on unique_lock constructor overload without having locked the mutex,
|
||||
* __lock_guard__: "sur parolle" as the user could use adopt_lock_t constructor overload without having locked the mutex.
|
||||
* nested_strict_lock: "sur parole" as the user could use adopt_lock_t on unique_lock constructor overload without having locked the mutex,
|
||||
* __lock_guard__: "sur parole" as the user could use adopt_lock_t constructor overload without having locked the mutex.
|
||||
|
||||
[endsect] [/ Models]
|
||||
|
||||
@@ -1205,9 +1205,9 @@ The following classes are models of `StrictLock`:
|
||||
template<typename Mutex>
|
||||
void swap(unique_lock <Mutex>& lhs, unique_lock <Mutex>& rhs);
|
||||
template<typename Lockable>
|
||||
class shared_lock; // EXTENSION
|
||||
class shared_lock; // C++14
|
||||
template<typename Mutex>
|
||||
void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs); // EXTENSION
|
||||
void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs); // C++14
|
||||
template<typename Lockable>
|
||||
class upgrade_lock; // EXTENSION
|
||||
template<typename Mutex>
|
||||
@@ -1235,13 +1235,13 @@ The following classes are models of `StrictLock`:
|
||||
unique_lock(Lockable& m_,try_to_lock_t);
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION
|
||||
unique_lock(shared_lock<mutex_type>&& sl, try_to_lock_t)
|
||||
unique_lock(shared_lock<mutex_type>&& sl, try_to_lock_t); // C++14
|
||||
template <class Clock, class Duration>
|
||||
unique_lock(shared_lock<mutex_type>&& sl,
|
||||
const chrono::time_point<Clock, Duration>& abs_time);
|
||||
const chrono::time_point<Clock, Duration>& abs_time); // C++14
|
||||
template <class Rep, class Period>
|
||||
unique_lock(shared_lock<mutex_type>&& sl,
|
||||
const chrono::duration<Rep, Period>& rel_time)
|
||||
const chrono::duration<Rep, Period>& rel_time); // C++14
|
||||
#endif
|
||||
|
||||
template <class Clock, class Duration>
|
||||
@@ -1253,7 +1253,7 @@ The following classes are models of `StrictLock`:
|
||||
unique_lock(unique_lock const&) = delete;
|
||||
unique_lock& operator=(unique_lock const&) = delete;
|
||||
unique_lock(unique_lock<Lockable>&& other) noexcept;
|
||||
explicit unique_lock(upgrade_lock<Lockable>&& other) noexcept;
|
||||
explicit unique_lock(upgrade_lock<Lockable>&& other) noexcept; // EXTENSION
|
||||
|
||||
unique_lock& operator=(unique_lock<Lockable>&& other) noexcept;
|
||||
|
||||
@@ -1583,7 +1583,7 @@ __owns_lock_ref__ returns `false`.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared_lock Class template `shared_lock` - EXTENSION]
|
||||
[section:shared_lock Class template `shared_lock` - C++14]
|
||||
|
||||
// #include <boost/thread/locks.hpp>
|
||||
// #include <boost/thread/lock_types.hpp>
|
||||
@@ -1621,7 +1621,7 @@ __owns_lock_ref__ returns `false`.]]
|
||||
void unlock();
|
||||
|
||||
// Conversion from upgrade locking
|
||||
explicit shared_lock(upgrade_lock<Lockable> && other);
|
||||
explicit shared_lock(upgrade_lock<Lockable> && other); // EXTENSION
|
||||
|
||||
// Conversion from exclusive locking
|
||||
explicit shared_lock(unique_lock<Lockable> && other);
|
||||
@@ -2026,9 +2026,9 @@ __reverse_mutex reverse the operations of a __BasicLockable, that unlocks the lo
|
||||
template <typename Lock>
|
||||
class nested_strict_lock;
|
||||
template <typename Lockable>
|
||||
struct is_strict_lock_sur_parolle<strict_lock<Lockable> >;
|
||||
struct is_strict_lock_sur_parole<strict_lock<Lockable> >;
|
||||
template <typename Lock>
|
||||
struct is_strict_lock_sur_parolle<nested_strict_lock<Lock> >;
|
||||
struct is_strict_lock_sur_parole<nested_strict_lock<Lock> >;
|
||||
|
||||
#if ! defined BOOST_THREAD_NO_MAKE_STRICT_LOCK
|
||||
template <typename Lockable>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:shared_mutex Class `shared_mutex` -- EXTENSION]
|
||||
[section:shared_mutex Class `shared_mutex` -- C++14]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
@@ -36,18 +36,18 @@
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
// use upgrade_mutex instead.
|
||||
void lock_upgrade();
|
||||
void unlock_upgrade();
|
||||
void lock_upgrade(); // EXTENSION
|
||||
void unlock_upgrade(); // EXTENSION
|
||||
|
||||
void unlock_upgrade_and_lock();
|
||||
void unlock_and_lock_upgrade();
|
||||
void unlock_and_lock_shared();
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
void unlock_upgrade_and_lock(); // EXTENSION
|
||||
void unlock_and_lock_upgrade(); // EXTENSION
|
||||
void unlock_and_lock_shared(); // EXTENSION
|
||||
void unlock_upgrade_and_lock_shared(); // EXTENSION
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_lock_shared(system_time const& timeout);
|
||||
bool timed_lock(system_time const& timeout);
|
||||
bool timed_lock_shared(system_time const& timeout); // DEPRECATED
|
||||
bool timed_lock(system_time const& timeout); // DEPRECATED
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
[/
|
||||
/ Copyright (c) 2013 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[section:synchronized_queues Synchronized Queues -- EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
template <class Stream, typename RecursiveMutex=recursive_mutex>
|
||||
class stream_guard;
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
struct is_strict_lock_sur_parolle<stream_guard<Stream, RecursiveMutex> > : true_type {};
|
||||
struct is_strict_lock_sur_parole<stream_guard<Stream, RecursiveMutex> > : true_type {};
|
||||
|
||||
// Stream-like operators
|
||||
template <typename Stream, typename RecursiveMutex, typename T>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
[/
|
||||
/ Copyright (c) 2013 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[section:synchronized_value_ref Reference ]
|
||||
|
||||
|
||||
|
||||
@@ -318,6 +318,11 @@
|
||||
#define BOOST_THREAD_USES_DATETIME
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#undef BOOST_THREAD_DONT_USE_CHRONO
|
||||
#define BOOST_THREAD_USES_CHRONO
|
||||
#endif
|
||||
|
||||
// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
|
||||
// BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
|
||||
@@ -23,6 +23,17 @@
|
||||
CLASS& operator=(CLASS const&) = delete;
|
||||
|
||||
#else // BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#if defined(BOOST_MSVC) && _MSC_VER >= 1600
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
private: \
|
||||
CLASS(CLASS const&); \
|
||||
public:
|
||||
|
||||
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
|
||||
private: \
|
||||
CLASS& operator=(CLASS const&); \
|
||||
public:
|
||||
#else
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
private: \
|
||||
CLASS(CLASS&); \
|
||||
@@ -32,6 +43,7 @@
|
||||
private: \
|
||||
CLASS& operator=(CLASS&); \
|
||||
public:
|
||||
#endif
|
||||
#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace boost
|
||||
};
|
||||
|
||||
template <typename Stream, typename RecursiveMutex>
|
||||
struct is_strict_lock_sur_parolle<stream_guard<Stream, RecursiveMutex> > : true_type
|
||||
struct is_strict_lock_sur_parole<stream_guard<Stream, RecursiveMutex> > : true_type
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
@@ -443,6 +443,7 @@ namespace boost
|
||||
throw_exception(promise_already_satisfied());
|
||||
}
|
||||
exception=e;
|
||||
this->is_constructed = true;
|
||||
get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
bool has_value()
|
||||
@@ -1746,7 +1747,7 @@ namespace boost
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(future_->mutex);
|
||||
|
||||
if(!future_->done)
|
||||
if(!future_->done && !future_->is_constructed)
|
||||
{
|
||||
future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
|
||||
}
|
||||
@@ -1915,7 +1916,7 @@ namespace boost
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(future_->mutex);
|
||||
|
||||
if(!future_->done)
|
||||
if(!future_->done && !future_->is_constructed)
|
||||
{
|
||||
future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
|
||||
}
|
||||
@@ -2057,7 +2058,7 @@ namespace boost
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(future_->mutex);
|
||||
|
||||
if(!future_->done)
|
||||
if(!future_->done && !future_->is_constructed)
|
||||
{
|
||||
future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
|
||||
}
|
||||
@@ -2362,18 +2363,12 @@ namespace boost
|
||||
task_object(task_object&);
|
||||
public:
|
||||
F f;
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
task_object(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(boost::forward<F>(f_))
|
||||
{}
|
||||
#else
|
||||
task_object(F const& f_):
|
||||
f(f_)
|
||||
{}
|
||||
task_object(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(boost::move(f_)) // TODO forward
|
||||
f(boost::move(f_))
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)
|
||||
@@ -2616,18 +2611,12 @@ namespace boost
|
||||
task_object(task_object&);
|
||||
public:
|
||||
F f;
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
task_object(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(boost::forward<F>(f_))
|
||||
{}
|
||||
#else
|
||||
task_object(F const& f_):
|
||||
f(f_)
|
||||
{}
|
||||
task_object(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(boost::move(f_)) // TODO forward
|
||||
f(boost::move(f_))
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)
|
||||
@@ -3481,7 +3470,7 @@ namespace boost
|
||||
boost::thread thr_;
|
||||
|
||||
public:
|
||||
explicit future_async_continuation(
|
||||
future_async_continuation(
|
||||
F& f, BOOST_THREAD_FWD_REF(Fp) c
|
||||
) :
|
||||
parent(f.future_),
|
||||
@@ -3544,15 +3533,15 @@ namespace boost
|
||||
struct future_async_continuation<F, void, Fp>: public future_object<void>
|
||||
{
|
||||
typedef future_object<void> base_type;
|
||||
F& parent;
|
||||
F parent;
|
||||
Fp continuation;
|
||||
boost::thread thr_;
|
||||
|
||||
public:
|
||||
explicit future_async_continuation(
|
||||
future_async_continuation(
|
||||
F& f, BOOST_THREAD_FWD_REF(Fp) c
|
||||
) :
|
||||
parent(f),
|
||||
parent(f.future_),
|
||||
continuation(boost::move(c)),
|
||||
thr_()
|
||||
{
|
||||
@@ -3602,14 +3591,14 @@ namespace boost
|
||||
struct future_deferred_continuation: future_object<Rp>
|
||||
{
|
||||
typedef future_object<Rp> base_type;
|
||||
F& parent;
|
||||
F parent;
|
||||
Fp continuation;
|
||||
|
||||
public:
|
||||
explicit future_deferred_continuation(
|
||||
future_deferred_continuation(
|
||||
F& f, BOOST_THREAD_FWD_REF(Fp) c
|
||||
) :
|
||||
parent(f),
|
||||
parent(f.future_),
|
||||
//continuation(boost::move(c))
|
||||
continuation(c)
|
||||
{
|
||||
@@ -3637,14 +3626,14 @@ namespace boost
|
||||
struct future_deferred_continuation<F,void,Fp>: future_object<void>
|
||||
{
|
||||
typedef future_object<void> base_type;
|
||||
F& parent;
|
||||
F parent;
|
||||
Fp continuation;
|
||||
|
||||
public:
|
||||
explicit future_deferred_continuation(
|
||||
future_deferred_continuation(
|
||||
F& f, BOOST_THREAD_FWD_REF(Fp) c
|
||||
):
|
||||
parent(f),
|
||||
parent(f.future_),
|
||||
continuation(boost::move(c))
|
||||
{
|
||||
this->set_deferred();
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace boost
|
||||
* An strict lock is a lock ensuring the mutex is locked on the scope of the lock
|
||||
* There is no single way to define a strict lock as the strict_lock and
|
||||
* nesteed_strict_lock shows. So we need a metafunction that states if a
|
||||
* lock is a strict lock "sur parolle".
|
||||
* lock is a strict lock "sur parole".
|
||||
*/
|
||||
|
||||
template <typename Lock>
|
||||
@@ -34,7 +34,10 @@ struct is_strict_lock_sur_parolle : false_type {};
|
||||
|
||||
|
||||
template <typename Lock>
|
||||
struct is_strict_lock : is_strict_lock_sur_parolle<Lock> {};
|
||||
struct is_strict_lock_sur_parole : is_strict_lock_sur_parolle<Lock> {};
|
||||
|
||||
template <typename Lock>
|
||||
struct is_strict_lock : is_strict_lock_sur_parole<Lock> {};
|
||||
|
||||
}
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -173,10 +173,15 @@ namespace boost
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
struct is_recursive_mutex_sur_parolle
|
||||
struct is_recursive_mutex_sur_parole
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
template<typename T>
|
||||
struct is_recursive_mutex_sur_parolle : is_recursive_mutex_sur_parole<T>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_recursive_basic_lockable
|
||||
{
|
||||
|
||||
@@ -33,10 +33,61 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
|
||||
#define BOOST_THREAD_HAS_EINTR_BUG
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace posix {
|
||||
#ifdef BOOST_THREAD_HAS_EINTR_BUG
|
||||
BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = ::pthread_mutex_destroy(m);
|
||||
} while (ret == EINTR);
|
||||
return ret;
|
||||
}
|
||||
BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = ::pthread_mutex_lock(m);
|
||||
} while (ret == EINTR);
|
||||
return ret;
|
||||
}
|
||||
BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = ::pthread_mutex_unlock(m);
|
||||
} while (ret == EINTR);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
|
||||
{
|
||||
return ::pthread_mutex_destroy(m);
|
||||
}
|
||||
BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
|
||||
{
|
||||
return ::pthread_mutex_lock(m);
|
||||
}
|
||||
BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
|
||||
{
|
||||
return ::pthread_mutex_unlock(m);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
class mutex
|
||||
{
|
||||
private:
|
||||
@@ -54,20 +105,12 @@ namespace boost
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_destroy(&m);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_lock(&m);
|
||||
} while (res == EINTR);
|
||||
int res = posix::pthread_mutex_lock(&m);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
|
||||
@@ -76,14 +119,10 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_unlock(&m);
|
||||
} while (res == EINTR);
|
||||
int res = posix::pthread_mutex_unlock(&m);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_lock"));
|
||||
boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +177,8 @@ namespace boost
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
|
||||
//BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
|
||||
}
|
||||
is_locked=false;
|
||||
@@ -146,7 +186,7 @@ namespace boost
|
||||
}
|
||||
~timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
@@ -166,11 +206,7 @@ namespace boost
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_lock(&m);
|
||||
} while (res == EINTR);
|
||||
int res = posix::pthread_mutex_lock(&m);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
|
||||
@@ -179,14 +215,10 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_unlock(&m);
|
||||
} while (res == EINTR);
|
||||
int res = posix::pthread_mutex_unlock(&m);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_lock"));
|
||||
boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace boost
|
||||
/**
|
||||
* @return the owned mutex.
|
||||
*/
|
||||
const mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return &mtx_;
|
||||
}
|
||||
@@ -108,7 +108,7 @@ namespace boost
|
||||
};
|
||||
//]
|
||||
template <typename Lockable>
|
||||
struct is_strict_lock_sur_parolle<strict_lock<Lockable> > : true_type
|
||||
struct is_strict_lock_sur_parole<strict_lock<Lockable> > : true_type
|
||||
{
|
||||
};
|
||||
|
||||
@@ -182,7 +182,7 @@ namespace boost
|
||||
/**
|
||||
* return @c the owned mutex.
|
||||
*/
|
||||
const mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
mutex_type* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return tmp_lk_.mutex();
|
||||
}
|
||||
@@ -213,7 +213,7 @@ namespace boost
|
||||
//]
|
||||
|
||||
template <typename Lock>
|
||||
struct is_strict_lock_sur_parolle<nested_strict_lock<Lock> > : true_type
|
||||
struct is_strict_lock_sur_parole<nested_strict_lock<Lock> > : true_type
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
@@ -81,8 +81,10 @@ namespace boost
|
||||
|
||||
do
|
||||
{
|
||||
BOOST_VERIFY(win32::WaitForSingleObject(
|
||||
sem,::boost::detail::win32::infinite)==0);
|
||||
unsigned const retval(win32::WaitForSingleObject(sem, ::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval);
|
||||
// BOOST_VERIFY(win32::WaitForSingleObject(
|
||||
// sem,::boost::detail::win32::infinite)==0);
|
||||
clear_waiting_and_try_lock(old_count);
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
|
||||
41
include/boost/thread/win32/mfc_thread_init.hpp
Normal file
41
include/boost/thread/win32/mfc_thread_init.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef BOOST_THREAD_WIN32_MFC_THREAD_INIT_HPP
|
||||
#define BOOST_THREAD_WIN32_MFC_THREAD_INIT_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
|
||||
// check if we use MFC
|
||||
#ifdef _AFXDLL
|
||||
# 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
|
||||
}
|
||||
|
||||
extern "C" __declspec(selectany) BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID) = &ExtRawDllMain;
|
||||
|
||||
# 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
|
||||
@@ -44,6 +44,8 @@ namespace boost
|
||||
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
||||
unsigned const event_modify_state=EVENT_MODIFY_STATE;
|
||||
unsigned const synchronize=SYNCHRONIZE;
|
||||
unsigned const wait_abandoned=WAIT_ABANDONED;
|
||||
|
||||
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
using ::CreateMutexW;
|
||||
@@ -127,6 +129,7 @@ namespace boost
|
||||
handle const invalid_handle_value=(handle)(-1);
|
||||
unsigned const event_modify_state=2;
|
||||
unsigned const synchronize=0x100000u;
|
||||
unsigned const wait_abandoned=0x00000080u;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -80,6 +80,36 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
// _pRawDllMainOrig can be defined by including boost/thread/win32/mfc_thread_init.hpp
|
||||
// into your dll; it ensures that MFC-Dll-initialization will be done properly
|
||||
// The following code is adapted from the MFC-Dll-init code
|
||||
/*
|
||||
* _pRawDllMainOrig MUST be an extern const variable, which will be aliased to
|
||||
* _pDefaultRawDllMainOrig if no real user definition is present, thanks to the
|
||||
* alternatename directive.
|
||||
*/
|
||||
|
||||
// work at least with _MSC_VER 1500 (MSVC++ 9.0, VS 2008)
|
||||
#if (_MSC_VER >= 1500)
|
||||
|
||||
extern "C" {
|
||||
extern BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID);
|
||||
extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HANDLE, DWORD, LPVOID) = NULL;
|
||||
#if defined (_M_IX86)
|
||||
#pragma comment(linker, "/alternatename:__pRawDllMainOrig=__pDefaultRawDllMainOrig")
|
||||
#elif defined (_M_X64) || defined (_M_ARM)
|
||||
#pragma comment(linker, "/alternatename:_pRawDllMainOrig=_pDefaultRawDllMainOrig")
|
||||
#else /* defined (_M_X64) || defined (_M_ARM) */
|
||||
#error Unsupported platform
|
||||
#endif /* defined (_M_X64) || defined (_M_ARM) */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
//Definitions required by implementation
|
||||
|
||||
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
|
||||
@@ -240,7 +270,11 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
}
|
||||
}
|
||||
|
||||
#if (_MSC_VER >= 1500)
|
||||
BOOL WINAPI dll_callback(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||
#else
|
||||
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
|
||||
#endif
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
@@ -251,6 +285,13 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
boost::on_process_exit();
|
||||
break;
|
||||
}
|
||||
|
||||
#if (_MSC_VER >= 1500)
|
||||
if( _pRawDllMainOrig )
|
||||
{
|
||||
return _pRawDllMainOrig(hInstance, dwReason, lpReserved);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
} //namespace
|
||||
|
||||
@@ -759,6 +759,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
#[ thread-run ../example/perf_condition_variable.cpp ]
|
||||
#[ thread-run ../example/perf_shared_mutex.cpp ]
|
||||
#[ thread-run ../example/std_async_test.cpp ]
|
||||
[ thread-run test_8596.cpp ]
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -44,10 +44,14 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
//void func(boost::promise<int> p)
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
void func(boost::promise<int> p)
|
||||
#else
|
||||
boost::promise<int> p;
|
||||
void func()
|
||||
#endif
|
||||
{
|
||||
//p.set_exception(boost::make_exception_ptr(3));
|
||||
p.set_exception_at_thread_exit(boost::make_exception_ptr(3));
|
||||
}
|
||||
|
||||
@@ -55,10 +59,14 @@ int main()
|
||||
{
|
||||
{
|
||||
typedef int T;
|
||||
//boost::promise<T> p;
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
boost::thread(func, boost::move(p)).detach();
|
||||
#else
|
||||
boost::future<T> f = p.get_future();
|
||||
//boost::thread(func, boost::move(p)).detach();
|
||||
boost::thread(func).detach();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
f.get();
|
||||
@@ -77,9 +85,12 @@ int main()
|
||||
typedef int T;
|
||||
boost::promise<T> p2;
|
||||
boost::future<T> f = p2.get_future();
|
||||
//boost::thread(func, boost::move(p)).detach();
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::thread(func, boost::move(p2)).detach();
|
||||
#else
|
||||
p = boost::move(p2);
|
||||
boost::thread(func).detach();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
f.get();
|
||||
|
||||
@@ -23,9 +23,12 @@
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
void func(boost::promise<int> p)
|
||||
#else
|
||||
boost::promise<int> p;
|
||||
//void func(boost::promise<int> p)
|
||||
void func()
|
||||
#endif
|
||||
{
|
||||
const int i = 5;
|
||||
p.set_value_at_thread_exit(i);
|
||||
@@ -34,18 +37,32 @@ void func()
|
||||
int main()
|
||||
{
|
||||
{
|
||||
//boost::promise<int> p;
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
boost::promise<int> p;
|
||||
boost::future<int> f = p.get_future();
|
||||
boost::thread(func, boost::move(p)).detach();
|
||||
#else
|
||||
boost::future<int> f = p.get_future();
|
||||
//boost::thread(func, boost::move(p)).detach();
|
||||
boost::thread(func).detach();
|
||||
BOOST_TEST(f.get() == 5);
|
||||
#endif
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f.get() == 5);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
#else
|
||||
boost::promise<int> p2;
|
||||
boost::future<int> f = p2.get_future();
|
||||
p = boost::move(p2);
|
||||
boost::thread(func).detach();
|
||||
BOOST_TEST(f.get() == 5);
|
||||
#endif
|
||||
}
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ void func()
|
||||
i = 1;
|
||||
}
|
||||
|
||||
void func2_mv(BOOST_THREAD_RV_REF(boost::promise<void>) p2)
|
||||
//void func2_mv(BOOST_THREAD_RV_REF(boost::promise<void>) p2)
|
||||
void func2_mv(boost::promise<void> p2)
|
||||
{
|
||||
p2.set_value_at_thread_exit();
|
||||
i = 2;
|
||||
@@ -92,6 +93,7 @@ int main()
|
||||
boost::thread(func2, &p2).detach();
|
||||
#endif
|
||||
f.wait();
|
||||
f.get();
|
||||
BOOST_TEST(i == 2);
|
||||
}
|
||||
catch(std::exception& ex)
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
int main()
|
||||
{
|
||||
boost::mutex m;
|
||||
m.lock();
|
||||
boost::unique_lock<boost::mutex> lk(m, boost::defer_lock);
|
||||
BOOST_TEST(lk.mutex() == &m);
|
||||
BOOST_TEST(lk.owns_lock() == false);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
int main()
|
||||
{
|
||||
boost::mutex m;
|
||||
m.lock();
|
||||
#if ! defined(BOOST_NO_CXX11_AUTO_DECLARATIONS)
|
||||
auto
|
||||
#else
|
||||
|
||||
52
test/test_8596.cpp
Normal file
52
test/test_8596.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
int f()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
boost::packaged_task<int()>* schedule(boost::function<int ()> const& fn)
|
||||
{
|
||||
// Normally, the pointer to the packaged task is stored in a queue
|
||||
// for execution on a separate thread, and the schedule function
|
||||
// would return just a future<T>
|
||||
|
||||
boost::function<int ()> copy(fn);
|
||||
boost::packaged_task<int()>* result = new boost::packaged_task<int()>(copy);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct MyFunc
|
||||
{
|
||||
void operator()()const {}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::packaged_task<int()>* p(schedule(f));
|
||||
(*p)();
|
||||
|
||||
boost::future<int> fut = p->get_future();
|
||||
std::cout << "The answer to the ultimate question: " << fut.get() << std::endl;
|
||||
|
||||
{
|
||||
//boost::function<void()> f;
|
||||
MyFunc mf;
|
||||
|
||||
//boost::packaged_task<void()> t1(f); // error 1
|
||||
boost::packaged_task<void()> t2(mf); // error 2
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -40,6 +40,51 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class M
|
||||
{
|
||||
|
||||
public:
|
||||
long data_;
|
||||
static int n_moves;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(M)
|
||||
static void reset() {
|
||||
n_moves=0;
|
||||
}
|
||||
explicit M(long i) : data_(i)
|
||||
{
|
||||
}
|
||||
M(BOOST_THREAD_RV_REF(M) a) : data_(BOOST_THREAD_RV(a).data_)
|
||||
{
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
}
|
||||
M& operator=(BOOST_THREAD_RV_REF(M) a)
|
||||
{
|
||||
data_ = BOOST_THREAD_RV(a).data_;
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
return *this;
|
||||
}
|
||||
~M()
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(int) const
|
||||
{ }
|
||||
long operator()() const
|
||||
{ return data_;}
|
||||
long operator()(long i, long j) const
|
||||
{ return data_ + i + j;}
|
||||
};
|
||||
|
||||
int M::n_moves = 0;
|
||||
|
||||
void fct(BOOST_THREAD_RV_REF(M) v)
|
||||
{
|
||||
BOOST_TEST_EQ(v.data_, 1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
@@ -47,6 +92,12 @@ int main()
|
||||
boost::thread t = boost::thread( MoveOnly(), MoveOnly() );
|
||||
t.join();
|
||||
}
|
||||
{
|
||||
M::reset();
|
||||
boost::thread t = boost::thread( fct, M(1) );
|
||||
t.join();
|
||||
BOOST_TEST_EQ(M::n_moves, 2);
|
||||
}
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user