diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 88233740..d29e0fec 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -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) ; @@ -264,16 +267,15 @@ rule requirements ( properties * ) } } result += BOOST_THREAD_DONT_USE_CHRONO ; + if ! [ configure.builds has_atomic_flag_lockfree + : $(properties) : "lockfree boost::atomic_flag" ] { + result += /boost/atomic//boost_atomic ; + } } else { result += BOOST_THREAD_USES_CHRONO ; result += /boost/chrono//boost_chrono ; } - #if pgi in $(properties) || vacpp in $(properties) - #{ - result += /boost/atomic//boost_atomic ; - #} - return $(result) ; } diff --git a/build/has_atomic_flag_lockfree_test.cpp b/build/has_atomic_flag_lockfree_test.cpp new file mode 100644 index 00000000..3190745f --- /dev/null +++ b/build/has_atomic_flag_lockfree_test.cpp @@ -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; +} \ No newline at end of file diff --git a/doc/changes.qbk b/doc/changes.qbk index ebbf9d5b..80d397f8 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -12,8 +12,6 @@ [*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/8515 #8515] Async: Add shared_future::then. @@ -21,15 +19,21 @@ * [@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 +* [@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/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] [thread] gcc -Wshadow gives warnings in condition_variable{,_fwd}.hpp -* [@http://svn.boost.org/trac/boost/ticket/9041 #9041] [thread] Boost.Thread DSO's may need to link with Boost.Atomic +* [@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] @@ -421,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. diff --git a/doc/future_ref.qbk b/doc/future_ref.qbk index 60cde1fc..4e6032a0 100644 --- a/doc/future_ref.qbk +++ b/doc/future_ref.qbk @@ -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.]] ] diff --git a/doc/sync_tutorial.qbk b/doc/sync_tutorial.qbk index d1ba29c5..5561bcb6 100644 --- a/doc/sync_tutorial.qbk +++ b/doc/sync_tutorial.qbk @@ -32,7 +32,7 @@ In particular, the library provides some lock factories. that can be used as - int i = with_lock_guard(mtx, {}() -> bool + int i = with_lock_guard(mtx, []() { // access the protected state return true; diff --git a/doc/thread.qbk b/doc/thread.qbk index e210b4c2..877591ec 100644 --- a/doc/thread.qbk +++ b/doc/thread.qbk @@ -239,7 +239,7 @@ [include condition_variables.qbk] [include once.qbk] [include barrier.qbk] -[include latch.qbk] +[/include latch.qbk] [include futures.qbk] [/include async_executors.qbk] [endsect] @@ -249,7 +249,7 @@ [section:sds Synchronized Data Structures] [include synchronized_value.qbk] -[include sync_queues_ref.qbk] +[/include sync_queues_ref.qbk] [/include sync_streams.qbk] [endsect] diff --git a/example/scoped_thread.cpp b/example/scoped_thread.cpp index f494bf2f..d345651c 100644 --- a/example/scoped_thread.cpp +++ b/example/scoped_thread.cpp @@ -85,7 +85,7 @@ int main() do_something_in_current_thread(); } { - boost::scoped_thread<> g( f, 1, 2 ); + boost::scoped_thread<> g( &f, 1, 2 ); do_something_in_current_thread(); } return 0; diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 7736156c..635d2022 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -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 callback; @@ -434,7 +434,7 @@ namespace boost get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); } - bool has_value() + bool has_value() const { boost::lock_guard lock(mutex); return done && !(exception @@ -444,7 +444,7 @@ namespace boost ); } - bool has_value(unique_lock& ) + bool has_value(unique_lock& ) const { return done && !(exception #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS @@ -453,7 +453,7 @@ namespace boost ); } - bool has_exception() + bool has_exception() const { boost::lock_guard lock(mutex); return done && (exception @@ -463,7 +463,7 @@ namespace boost ); } - bool has_exception(unique_lock&) + bool has_exception(unique_lock&) const { return done && (exception #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS @@ -472,16 +472,16 @@ namespace boost ); } - bool is_deferred() const BOOST_NOEXCEPT { + bool is_deferred(boost::lock_guard&) const { return is_deferred_; } - launch launch_policy() const BOOST_NOEXCEPT + launch launch_policy(boost::unique_lock&) const { return policy_; } - future_state::state get_state() + future_state::state get_state() const { boost::lock_guard guard(mutex); if(!done) @@ -494,6 +494,23 @@ namespace boost } } + exception_ptr get_exception_ptr() + { + boost::unique_lock lock(mutex); + return get_exception_ptr(lock); + } + exception_ptr get_exception_ptr(boost::unique_lock& 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 void set_wait_callback(F f,U* u) { @@ -1294,7 +1311,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 +1320,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& 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 +3962,13 @@ namespace boost BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock 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, future_type, F>( lock, boost::move(*this), boost::forward(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, future_type, F>( @@ -4056,13 +4080,13 @@ namespace boost BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock 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, future_type, F>( lock, boost::move(*this), boost::forward(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, future_type, F>(