diff options
Diffstat (limited to 'boost/thread/future.hpp')
-rw-r--r-- | boost/thread/future.hpp | 970 |
1 files changed, 615 insertions, 355 deletions
diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp index bd87158338..8cad994de5 100644 --- a/boost/thread/future.hpp +++ b/boost/thread/future.hpp @@ -1,4 +1,5 @@ // (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -6,6 +7,15 @@ #ifndef BOOST_THREAD_FUTURE_HPP #define BOOST_THREAD_FUTURE_HPP + +#include <boost/thread/detail/config.hpp> + +// boost::thread::future requires exception handling +// due to boost::exception::exception_ptr dependency + +#ifndef BOOST_NO_EXCEPTIONS + +#include <boost/detail/scoped_enum_emulation.hpp> #include <stdexcept> #include <boost/thread/detail/move.hpp> #include <boost/thread/thread_time.hpp> @@ -16,6 +26,8 @@ #include <boost/scoped_ptr.hpp> #include <boost/type_traits/is_fundamental.hpp> #include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/type_traits/remove_cv.hpp> #include <boost/mpl/if.hpp> #include <boost/config.hpp> #include <boost/throw_exception.hpp> @@ -28,59 +40,168 @@ #include <list> #include <boost/next_prior.hpp> #include <vector> +#include <boost/system/error_code.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#include <boost/thread/detail/memory.hpp> +#endif + +#include <boost/utility/result_of.hpp> +//#include <boost/thread.hpp> + +#if defined BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_THREAD_FUTURE future +#else +#define BOOST_THREAD_FUTURE unique_future +#endif + namespace boost { - class future_uninitialized: - public std::logic_error + + //enum class future_errc + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) + { + broken_promise, + future_already_retrieved, + promise_already_satisfied, + no_state + } + BOOST_SCOPED_ENUM_DECLARE_END(future_errc) + + namespace system + { + template <> + struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type {}; + + #ifdef BOOST_NO_SCOPED_ENUMS + template <> + struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { }; + #endif + } + + //enum class launch + BOOST_SCOPED_ENUM_DECLARE_BEGIN(launch) + { + async = 1, + deferred = 2, + any = async | deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(launch) + + //enum class future_status + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_status) + { + ready, + timeout, + deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(future_status) + + BOOST_THREAD_DECL + const system::error_category& future_category(); + + namespace system + { + inline BOOST_THREAD_DECL + error_code + make_error_code(future_errc e) + { + return error_code(underlying_cast<int>(e), boost::future_category()); + } + + inline BOOST_THREAD_DECL + error_condition + make_error_condition(future_errc e) + { + return error_condition(underlying_cast<int>(e), future_category()); + } + } + + class BOOST_SYMBOL_VISIBLE future_error + : public std::logic_error + { + system::error_code ec_; + public: + future_error(system::error_code ec) + : logic_error(ec.message()), + ec_(ec) + { + } + + const system::error_code& code() const BOOST_NOEXCEPT + { + return ec_; + } + + //virtual ~future_error() BOOST_NOEXCEPT; + }; + + class BOOST_SYMBOL_VISIBLE future_uninitialized: + public future_error { public: future_uninitialized(): - std::logic_error("Future Uninitialized") + future_error(system::make_error_code(future_errc::no_state)) {} }; - class broken_promise: - public std::logic_error + class BOOST_SYMBOL_VISIBLE broken_promise: + public future_error { public: broken_promise(): - std::logic_error("Broken promise") + future_error(system::make_error_code(future_errc::broken_promise)) {} }; - class future_already_retrieved: - public std::logic_error + class BOOST_SYMBOL_VISIBLE future_already_retrieved: + public future_error { public: future_already_retrieved(): - std::logic_error("Future already retrieved") + future_error(system::make_error_code(future_errc::future_already_retrieved)) {} }; - class promise_already_satisfied: - public std::logic_error + class BOOST_SYMBOL_VISIBLE promise_already_satisfied: + public future_error { public: promise_already_satisfied(): - std::logic_error("Promise already satisfied") + future_error(system::make_error_code(future_errc::promise_already_satisfied)) {} }; - class task_already_started: - public std::logic_error + class BOOST_SYMBOL_VISIBLE task_already_started: + public future_error { public: task_already_started(): - std::logic_error("Task already started") + future_error(system::make_error_code(future_errc::promise_already_satisfied)) + //std::logic_error("Task already started") {} }; - class task_moved: - public std::logic_error - { - public: - task_moved(): - std::logic_error("Task moved") - {} - }; + class BOOST_SYMBOL_VISIBLE task_moved: + public future_error + { + public: + task_moved(): + future_error(system::make_error_code(future_errc::no_state)) + //std::logic_error("Task moved") + {} + }; + + class promise_moved: + public future_error + { + public: + promise_moved(): + future_error(system::make_error_code(future_errc::no_state)) + //std::logic_error("Promise moved") + {} + }; namespace future_state { @@ -93,6 +214,7 @@ namespace boost { boost::exception_ptr exception; bool done; + bool thread_was_interrupted; boost::mutex mutex; boost::condition_variable waiters; typedef std::list<boost::condition_variable_any*> waiter_list; @@ -100,7 +222,8 @@ namespace boost boost::function<void()> callback; future_object_base(): - done(false) + done(false), + thread_was_interrupted(false) {} virtual ~future_object_base() {} @@ -165,6 +288,10 @@ namespace boost { waiters.wait(lock); } + if(rethrow && thread_was_interrupted) + { + throw boost::thread_interrupted(); + } if(rethrow && exception) { boost::rethrow_exception(exception); @@ -186,6 +313,25 @@ namespace boost return true; } +#ifdef BOOST_THREAD_USES_CHRONO + + template <class Clock, class Duration> + future_status + wait_until(const chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<boost::mutex> lock(mutex); + do_callback(lock); + while(!done) + { + cv_status const st=waiters.wait_until(lock,abs_time); + if(st==cv_status::timeout && !done) + { + return future_status::timeout; + } + } + return future_status::ready; + } +#endif void mark_exceptional_finish_internal(boost::exception_ptr const& e) { exception=e; @@ -196,16 +342,21 @@ namespace boost boost::lock_guard<boost::mutex> lock(mutex); mark_exceptional_finish_internal(boost::current_exception()); } - + void mark_interrupted_finish() + { + boost::lock_guard<boost::mutex> lock(mutex); + thread_was_interrupted=true; + mark_finished_internal(); + } bool has_value() { boost::lock_guard<boost::mutex> lock(mutex); - return done && !exception; + return done && !(exception || thread_was_interrupted); } bool has_exception() { boost::lock_guard<boost::mutex> lock(mutex); - return done && exception; + return done && (exception || thread_was_interrupted); } template<typename F,typename U> @@ -226,14 +377,20 @@ namespace boost #ifndef BOOST_NO_RVALUE_REFERENCES typedef T const& source_reference_type; struct dummy; - typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,T&&>::type move_dest_type; + typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,BOOST_THREAD_RV_REF(T)>::type rvalue_source_type; + typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,BOOST_THREAD_RV_REF(T)>::type move_dest_type; +#elif defined BOOST_THREAD_USES_MOVE + typedef T& source_reference_type; + typedef typename boost::mpl::if_<boost::has_move_emulation_enabled<T>,BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; + typedef typename boost::mpl::if_<boost::has_move_emulation_enabled<T>,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; #else typedef T& source_reference_type; - typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T const&>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T>::type move_dest_type; + typedef typename boost::mpl::if_<boost::is_convertible<T&,BOOST_THREAD_RV_REF(T) >,BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; + typedef typename boost::mpl::if_<boost::is_convertible<T&,BOOST_THREAD_RV_REF(T) >,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; #endif + typedef const T& shared_future_get_result_type; + static void init(storage_type& storage,source_reference_type t) { storage.reset(new T(t)); @@ -241,7 +398,7 @@ namespace boost static void init(storage_type& storage,rvalue_source_type t) { - storage.reset(new T(static_cast<rvalue_source_type>(t))); + storage.reset(new T(static_cast<rvalue_source_type>(t))); } static void cleanup(storage_type& storage) @@ -258,6 +415,7 @@ namespace boost struct rvalue_source_type {}; typedef T& move_dest_type; + typedef T& shared_future_get_result_type; static void init(storage_type& storage,T& t) { @@ -275,6 +433,7 @@ namespace boost { typedef bool storage_type; typedef void move_dest_type; + typedef void shared_future_get_result_type; static void init(storage_type& storage) { @@ -296,6 +455,7 @@ namespace boost typedef typename future_traits<T>::source_reference_type source_reference_type; typedef typename future_traits<T>::rvalue_source_type rvalue_source_type; typedef typename future_traits<T>::move_dest_type move_dest_type; + typedef typename future_traits<T>::shared_future_get_result_type shared_future_get_result_type; storage_type result; @@ -308,6 +468,7 @@ namespace boost future_traits<T>::init(result,result_); mark_finished_internal(); } + void mark_finished_with_result_internal(rvalue_source_type result_) { future_traits<T>::init(result,static_cast<rvalue_source_type>(result_)); @@ -319,10 +480,11 @@ namespace boost boost::lock_guard<boost::mutex> lock(mutex); mark_finished_with_result_internal(result_); } + void mark_finished_with_result(rvalue_source_type result_) { boost::lock_guard<boost::mutex> lock(mutex); - mark_finished_with_result_internal(result_); + mark_finished_with_result_internal(static_cast<rvalue_source_type>(result_)); } move_dest_type get() @@ -331,6 +493,12 @@ namespace boost return static_cast<move_dest_type>(*result); } + shared_future_get_result_type get_sh() + { + wait(); + return static_cast<shared_future_get_result_type>(*result); + } + future_state::state get_state() { boost::lock_guard<boost::mutex> guard(mutex); @@ -353,7 +521,7 @@ namespace boost struct future_object<void>: detail::future_object_base { - typedef void move_dest_type; + typedef void shared_future_get_result_type; future_object() {} @@ -373,7 +541,10 @@ namespace boost { wait(); } - + void get_sh() + { + wait(); + } future_state::state get_state() { boost::lock_guard<boost::mutex> guard(mutex); @@ -386,12 +557,22 @@ namespace boost return future_state::ready; } } - private: future_object(future_object const&); future_object& operator=(future_object const&); }; +// template<typename T, typename Allocator> +// struct future_object_alloc: public future_object<T> +// { +// typedef future_object<T> base; +// Allocator alloc_; +// +// public: +// explicit future_object_alloc(const Allocator& a) +// : alloc_(a) {} +// +// }; class future_waiter { struct registered_waiter; @@ -399,38 +580,32 @@ namespace boost struct registered_waiter { - boost::shared_ptr<detail::future_object_base> future; + boost::shared_ptr<detail::future_object_base> future_; detail::future_object_base::waiter_list::iterator wait_iterator; count_type index; - registered_waiter(boost::shared_ptr<detail::future_object_base> const& future_, + registered_waiter(boost::shared_ptr<detail::future_object_base> const& a_future, detail::future_object_base::waiter_list::iterator wait_iterator_, count_type index_): - future(future_),wait_iterator(wait_iterator_),index(index_) + future_(a_future),wait_iterator(wait_iterator_),index(index_) {} }; struct all_futures_lock { -#ifdef _MANAGED - typedef std::ptrdiff_t count_type_portable; -#else - typedef count_type count_type_portable; -#endif - count_type_portable count; - + count_type count; boost::scoped_array<boost::unique_lock<boost::mutex> > locks; all_futures_lock(std::vector<registered_waiter>& futures): count(futures.size()),locks(new boost::unique_lock<boost::mutex>[count]) { - for(count_type_portable i=0;i<count;++i) + for(count_type i=0;i<count;++i) { #if defined __DECCXX || defined __SUNPRO_CC - locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex).move(); + locks[i]=boost::unique_lock<boost::mutex>(futures[i].future_->mutex).move(); #else - locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex); + locks[i]=boost::unique_lock<boost::mutex>(futures[i].future_->mutex); #endif } } @@ -442,7 +617,7 @@ namespace boost void unlock() { - for(count_type_portable i=0;i<count;++i) + for(count_type i=0;i<count;++i) { locks[i].unlock(); } @@ -461,9 +636,9 @@ namespace boost template<typename F> void add(F& f) { - if(f.future) + if(f.future_) { - futures.push_back(registered_waiter(f.future,f.future->register_external_waiter(cv),future_count)); + futures.push_back(registered_waiter(f.future_,f.future_->register_external_waiter(cv),future_count)); } ++future_count; } @@ -475,7 +650,7 @@ namespace boost { for(count_type i=0;i<futures.size();++i) { - if(futures[i].future->done) + if(futures[i].future_->done) { return futures[i].index; } @@ -488,7 +663,7 @@ namespace boost { for(count_type i=0;i<futures.size();++i) { - futures[i].future->remove_external_waiter(futures[i].wait_iterator); + futures[i].future_->remove_external_waiter(futures[i].wait_iterator); } } @@ -497,7 +672,7 @@ namespace boost } template <typename R> - class unique_future; + class BOOST_THREAD_FUTURE; template <typename R> class shared_future; @@ -509,7 +684,7 @@ namespace boost }; template<typename T> - struct is_future_type<unique_future<T> > + struct is_future_type<BOOST_THREAD_FUTURE<T> > { BOOST_STATIC_CONSTANT(bool, value=true); }; @@ -626,14 +801,13 @@ namespace boost class packaged_task; template <typename R> - class unique_future + class BOOST_THREAD_FUTURE { - unique_future(unique_future & rhs);// = delete; - unique_future& operator=(unique_future& rhs);// = delete; + private: typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - future_ptr future; + future_ptr future_; friend class shared_future<R>; friend class promise<R>; @@ -642,99 +816,92 @@ namespace boost typedef typename detail::future_traits<R>::move_dest_type move_dest_type; - unique_future(future_ptr future_): - future(future_) + BOOST_THREAD_FUTURE(future_ptr a_future): + future_(a_future) {} public: + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) typedef future_state::state state; - unique_future() + BOOST_THREAD_FUTURE() {} - ~unique_future() + ~BOOST_THREAD_FUTURE() {} -#ifndef BOOST_NO_RVALUE_REFERENCES - unique_future(unique_future && other) - { - future.swap(other.future); - } - unique_future& operator=(unique_future && other) - { - future=other.future; - other.future.reset(); - return *this; - } -#else - unique_future(boost::detail::thread_move_t<unique_future> other): - future(other->future) + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + future_(BOOST_THREAD_RV(other).future_) { - other->future.reset(); + BOOST_THREAD_RV(other).future_.reset(); } - unique_future& operator=(boost::detail::thread_move_t<unique_future> other) + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT { - future=other->future; - other->future.reset(); + future_=BOOST_THREAD_RV(other).future_; + BOOST_THREAD_RV(other).future_.reset(); return *this; } - operator boost::detail::thread_move_t<unique_future>() + shared_future<R> share() { - return boost::detail::thread_move_t<unique_future>(*this); + return shared_future<R>(::boost::move(*this)); } -#endif - void swap(unique_future& other) + void swap(BOOST_THREAD_FUTURE& other) { - future.swap(other.future); + future_.swap(other.future_); } // retrieving the value move_dest_type get() { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->get(); + return future_->get(); } // functions to check state, and wait for ready - state get_state() const + state get_state() const BOOST_NOEXCEPT { - if(!future) + if(!future_) { return future_state::uninitialized; } - return future->get_state(); + return future_->get_state(); } - - bool is_ready() const + bool is_ready() const BOOST_NOEXCEPT { return get_state()==future_state::ready; } - bool has_exception() const + bool has_exception() const BOOST_NOEXCEPT { - return future && future->has_exception(); + return future_ && future_->has_exception(); } - bool has_value() const + bool has_value() const BOOST_NOEXCEPT { - return future && future->has_value(); + return future_ && future_->has_value(); } + bool valid() const BOOST_NOEXCEPT + { + return future_ != 0; + } + + void wait() const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - future->wait(false); + future_->wait(false); } template<typename Duration> @@ -745,43 +912,55 @@ namespace boost bool timed_wait_until(boost::system_time const& abs_time) const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->timed_wait_until(abs_time); + return future_->timed_wait_until(abs_time); } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + future_status + wait_for(const chrono::duration<Rep, Period>& rel_time) const + { + return wait_until(chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + future_status + wait_until(const chrono::time_point<Clock, Duration>& abs_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->wait_until(abs_time); + } +#endif }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<unique_future<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif + BOOST_THREAD_DCL_MOVABLE_BEG(T) BOOST_THREAD_FUTURE<T> BOOST_THREAD_DCL_MOVABLE_END template <typename R> class shared_future { typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - future_ptr future; - -// shared_future(const unique_future<R>& other); -// shared_future& operator=(const unique_future<R>& other); + future_ptr future_; friend class detail::future_waiter; friend class promise<R>; friend class packaged_task<R>; - shared_future(future_ptr future_): - future(future_) + shared_future(future_ptr a_future): + future_(a_future) {} public: + BOOST_THREAD_MOVABLE(shared_future) + shared_future(shared_future const& other): - future(other.future) + future_(other.future_) {} typedef future_state::state state; @@ -794,112 +973,85 @@ namespace boost shared_future& operator=(shared_future const& other) { - future=other.future; + future_=other.future_; return *this; } -#ifndef BOOST_NO_RVALUE_REFERENCES - shared_future(shared_future && other) - { - future.swap(other.future); - } - shared_future(unique_future<R> && other) - { - future.swap(other.future); - } - shared_future& operator=(shared_future && other) - { - future.swap(other.future); - other.future.reset(); - return *this; - } - shared_future& operator=(unique_future<R> && other) + shared_future(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(other).future_) { - future.swap(other.future); - other.future.reset(); - return *this; + BOOST_THREAD_RV(other).future_.reset(); } -#else - shared_future(boost::detail::thread_move_t<shared_future> other): - future(other->future) + shared_future(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE<R> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(other).future_) { - other->future.reset(); + BOOST_THREAD_RV(other).future_.reset(); } -// shared_future(const unique_future<R> &) = delete; - shared_future(boost::detail::thread_move_t<unique_future<R> > other): - future(other->future) + shared_future& operator=(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT { - other->future.reset(); - } - shared_future& operator=(boost::detail::thread_move_t<shared_future> other) - { - future.swap(other->future); - other->future.reset(); + future_.swap(BOOST_THREAD_RV(other).future_); + BOOST_THREAD_RV(other).future_.reset(); return *this; } - shared_future& operator=(boost::detail::thread_move_t<unique_future<R> > other) + shared_future& operator=(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE<R> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT { - future.swap(other->future); - other->future.reset(); + future_.swap(BOOST_THREAD_RV(other).future_); + BOOST_THREAD_RV(other).future_.reset(); return *this; } - operator boost::detail::thread_move_t<shared_future>() - { - return boost::detail::thread_move_t<shared_future>(*this); - } - -#endif - - void swap(shared_future& other) + void swap(shared_future& other) BOOST_NOEXCEPT { - future.swap(other.future); + future_.swap(other.future_); } // retrieving the value - //typename detail::future_object<R>::move_dest_type get() - R get() + typename detail::future_object<R>::shared_future_get_result_type get() { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->get(); + return future_->get_sh(); } // functions to check state, and wait for ready - state get_state() const + state get_state() const BOOST_NOEXCEPT { - if(!future) + if(!future_) { return future_state::uninitialized; } - return future->get_state(); + return future_->get_state(); } + bool valid() const BOOST_NOEXCEPT + { + return future_ != 0; + } - bool is_ready() const + bool is_ready() const BOOST_NOEXCEPT { return get_state()==future_state::ready; } - bool has_exception() const + bool has_exception() const BOOST_NOEXCEPT { - return future && future->has_exception(); + return future_ && future_->has_exception(); } - bool has_value() const + bool has_value() const BOOST_NOEXCEPT { - return future && future->has_value(); + return future_ && future_->has_value(); } void wait() const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - future->wait(false); + future_->wait(false); } template<typename Duration> @@ -910,157 +1062,168 @@ namespace boost bool timed_wait_until(boost::system_time const& abs_time) const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->timed_wait_until(abs_time); + return future_->timed_wait_until(abs_time); } +#ifdef BOOST_THREAD_USES_CHRONO - }; + template <class Rep, class Period> + future_status + wait_for(const chrono::duration<Rep, Period>& rel_time) const + { + return wait_until(chrono::steady_clock::now() + rel_time); -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<shared_future<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; + } + template <class Clock, class Duration> + future_status + wait_until(const chrono::time_point<Clock, Duration>& abs_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->wait_until(abs_time); + } #endif + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future<T> BOOST_THREAD_DCL_MOVABLE_END template <typename R> class promise { typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - future_ptr future; + future_ptr future_; bool future_obtained; - promise(promise & rhs);// = delete; - promise & operator=(promise & rhs);// = delete; - void lazy_init() { - if(!atomic_load(&future)) +#if defined BOOST_THREAD_PROMISE_LAZY + if(!atomic_load(&future_)) { future_ptr blank; - atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<R>)); + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object<R>)); } +#endif } public: -// template <class Allocator> explicit promise(Allocator a); + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template <class Allocator> + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind<detail::future_object<R> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + future_ = future_ptr(::new(a2.allocate(1)) detail::future_object<R>(), D(a2, 1) ); + future_obtained = false; + } +#endif promise(): - future(),future_obtained(false) +#if defined BOOST_THREAD_PROMISE_LAZY + future_(), +#else + future_(new detail::future_object<R>()), +#endif + future_obtained(false) {} ~promise() { - if(future) + if(future_) { - boost::lock_guard<boost::mutex> lock(future->mutex); + boost::lock_guard<boost::mutex> lock(future_->mutex); - if(!future->done) + if(!future_->done) { - future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); } } } // Assignment -#ifndef BOOST_NO_RVALUE_REFERENCES - promise(promise && rhs): - future_obtained(rhs.future_obtained) + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) { - future.swap(rhs.future); - rhs.future_obtained=false; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; } - promise & operator=(promise&& rhs) + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT { - future.swap(rhs.future); - future_obtained=rhs.future_obtained; - rhs.future.reset(); - rhs.future_obtained=false; + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; return *this; } -#else - promise(boost::detail::thread_move_t<promise> rhs): - future(rhs->future),future_obtained(rhs->future_obtained) - { - rhs->future.reset(); - rhs->future_obtained=false; - } - promise & operator=(boost::detail::thread_move_t<promise> rhs) - { - future=rhs->future; - future_obtained=rhs->future_obtained; - rhs->future.reset(); - rhs->future_obtained=false; - return *this; - } - - operator boost::detail::thread_move_t<promise>() - { - return boost::detail::thread_move_t<promise>(*this); - } -#endif void swap(promise& other) { - future.swap(other.future); + future_.swap(other.future_); std::swap(future_obtained,other.future_obtained); } // Result retrieval - unique_future<R> get_future() + BOOST_THREAD_FUTURE<R> get_future() { lazy_init(); - if(future_obtained) + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if (future_obtained) { boost::throw_exception(future_already_retrieved()); } future_obtained=true; - return unique_future<R>(future); + return BOOST_THREAD_FUTURE<R>(future_); } void set_value(typename detail::future_traits<R>::source_reference_type r) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<boost::mutex> lock(future_->mutex); + if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future->mark_finished_with_result_internal(r); + future_->mark_finished_with_result_internal(r); } // void set_value(R && r); void set_value(typename detail::future_traits<R>::rvalue_source_type r) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<boost::mutex> lock(future_->mutex); + if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future->mark_finished_with_result_internal(static_cast<typename detail::future_traits<R>::rvalue_source_type>(r)); + future_->mark_finished_with_result_internal(static_cast<typename detail::future_traits<R>::rvalue_source_type>(r)); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<boost::mutex> lock(future_->mutex); + if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p); } template<typename F> void set_wait_callback(F f) { lazy_init(); - future->set_wait_callback(f,this); + future_->set_wait_callback(f,this); } }; @@ -1070,135 +1233,140 @@ namespace boost { typedef boost::shared_ptr<detail::future_object<void> > future_ptr; - future_ptr future; + future_ptr future_; bool future_obtained; - promise(promise & rhs);// = delete; - promise & operator=(promise & rhs);// = delete; - void lazy_init() { - if(!atomic_load(&future)) +#if defined BOOST_THREAD_PROMISE_LAZY + if(!atomic_load(&future_)) { future_ptr blank; - atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<void>)); + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object<void>)); } +#endif } public: -// template <class Allocator> explicit promise(Allocator a); + BOOST_THREAD_MOVABLE_ONLY(promise) + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template <class Allocator> + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind<detail::future_object<void> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + future_ = future_ptr(::new(a2.allocate(1)) detail::future_object<void>(), D(a2, 1) ); + future_obtained = false; + } +#endif promise(): - future(),future_obtained(false) +#if defined BOOST_THREAD_PROMISE_LAZY + future_(), +#else + future_(new detail::future_object<void>), +#endif + future_obtained(false) {} ~promise() { - if(future) + if(future_) { - boost::lock_guard<boost::mutex> lock(future->mutex); + boost::lock_guard<boost::mutex> lock(future_->mutex); - if(!future->done) + if(!future_->done) { - future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); } } } // Assignment -#ifndef BOOST_NO_RVALUE_REFERENCES - promise(promise && rhs): - future_obtained(rhs.future_obtained) - { - future.swap(rhs.future); - rhs.future_obtained=false; - } - promise & operator=(promise&& rhs) - { - future.swap(rhs.future); - future_obtained=rhs.future_obtained; - rhs.future.reset(); - rhs.future_obtained=false; - return *this; - } -#else - promise(boost::detail::thread_move_t<promise> rhs): - future(rhs->future),future_obtained(rhs->future_obtained) - { - rhs->future.reset(); - rhs->future_obtained=false; - } - promise & operator=(boost::detail::thread_move_t<promise> rhs) + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) { - future=rhs->future; - future_obtained=rhs->future_obtained; - rhs->future.reset(); - rhs->future_obtained=false; - return *this; + // we need to release the future as shared_ptr doesn't implements move semantics + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; } - operator boost::detail::thread_move_t<promise>() + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT { - return boost::detail::thread_move_t<promise>(*this); + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; } -#endif void swap(promise& other) { - future.swap(other.future); + future_.swap(other.future_); std::swap(future_obtained,other.future_obtained); } // Result retrieval - unique_future<void> get_future() + BOOST_THREAD_FUTURE<void> get_future() { lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } if(future_obtained) { boost::throw_exception(future_already_retrieved()); } future_obtained=true; - return unique_future<void>(future); + return BOOST_THREAD_FUTURE<void>(future_); } void set_value() { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<boost::mutex> lock(future_->mutex); + if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future->mark_finished_with_result_internal(); + future_->mark_finished_with_result_internal(); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<boost::mutex> lock(future_->mutex); + if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p); } template<typename F> void set_wait_callback(F f) { lazy_init(); - future->set_wait_callback(f,this); + future_->set_wait_callback(f,this); } }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<promise<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + namespace container + { + template <class R, class Alloc> + struct uses_allocator<promise<R> , Alloc> : true_type + { + }; + } #endif + BOOST_THREAD_DCL_MOVABLE_BEG(T) promise<T> BOOST_THREAD_DCL_MOVABLE_END + namespace detail { template<typename R> @@ -1211,6 +1379,10 @@ namespace boost started(false) {} + void reset() + { + started=false; + } void run() { { @@ -1243,26 +1415,32 @@ namespace boost struct task_object: task_base<R> { + private: + task_object(task_object&); + public: F f; task_object(F const& f_): f(f_) {} #ifndef BOOST_NO_RVALUE_REFERENCES - task_object(F&& f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::forward<F>(f_)) {} #else - task_object(boost::detail::thread_move_t<F> f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) {} #endif - void do_run() { try { this->mark_finished_with_result(f()); } + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } catch(...) { this->mark_exceptional_finish(); @@ -1274,17 +1452,20 @@ namespace boost struct task_object<void,F>: task_base<void> { + private: + task_object(task_object&); + public: F f; task_object(F const& f_): f(f_) {} #ifndef BOOST_NO_RVALUE_REFERENCES - task_object(F&& f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::forward<F>(f_)) {} #else - task_object(boost::detail::thread_move_t<F> f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) {} #endif @@ -1295,6 +1476,10 @@ namespace boost f(); this->mark_finished_with_result(); } + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } catch(...) { this->mark_exceptional_finish(); @@ -1304,47 +1489,91 @@ namespace boost } - template<typename R> class packaged_task { + typedef boost::shared_ptr<detail::task_base<R> > task_ptr; boost::shared_ptr<detail::task_base<R> > task; bool future_obtained; - packaged_task(packaged_task&);// = delete; - packaged_task& operator=(packaged_task&);// = delete; - public: + typedef R result_type; + BOOST_THREAD_MOVABLE_ONLY(packaged_task) + packaged_task(): future_obtained(false) {} // construction and destruction - template <class F> - explicit packaged_task(F const& f): - task(new detail::task_object<R,F>(f)),future_obtained(false) - {} + explicit packaged_task(R(*f)()): task(new detail::task_object<R,R(*)()>(f)),future_obtained(false) {} - #ifndef BOOST_NO_RVALUE_REFERENCES template <class F> - explicit packaged_task(F&& f): - task(new detail::task_object<R,F>(f)),future_obtained(false) + explicit packaged_task(BOOST_THREAD_RV_REF(F) f): + task(new detail::task_object<R, + typename remove_cv<typename remove_reference<F>::type>::type + >(boost::forward<F>(f))),future_obtained(false) {} #else template <class F> - explicit packaged_task(boost::detail::thread_move_t<F> f): + explicit packaged_task(F const& f): task(new detail::task_object<R,F>(f)),future_obtained(false) {} + template <class F> + explicit packaged_task(BOOST_THREAD_RV_REF(F) f): + task(new detail::task_object<R,F>(boost::move(f))),future_obtained(false) + {} #endif -// template <class F, class Allocator> -// explicit packaged_task(F const& f, Allocator a); -// template <class F, class Allocator> -// explicit packaged_task(F&& f, Allocator a); +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template <class Allocator> + packaged_task(boost::allocator_arg_t, Allocator a, R(*f)()) + { + typedef R(*FR)(); + typedef typename Allocator::template rebind<detail::task_object<R,FR> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + + task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,FR>(f), D(a2, 1) ); + future_obtained = false; + } +#ifndef BOOST_NO_RVALUE_REFERENCES + template <class F, class Allocator> + packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) + { + typedef typename remove_cv<typename remove_reference<F>::type>::type FR; + typedef typename Allocator::template rebind<detail::task_object<R,FR> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,FR>(boost::forward<F>(f)), D(a2, 1) ); + future_obtained = false; + } +#else + template <class F, class Allocator> + packaged_task(boost::allocator_arg_t, Allocator a, const F& f) + { + typedef typename Allocator::template rebind<detail::task_object<R,F> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + + task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,F>(f), D(a2, 1) ); + future_obtained = false; + } + template <class F, class Allocator> + packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) + { + typedef typename Allocator::template rebind<detail::task_object<R,F> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + + task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,F>(boost::move(f)), D(a2, 1) ); + future_obtained = false; + } +#endif //BOOST_NO_RVALUE_REFERENCES +#endif // BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS ~packaged_task() { @@ -1355,46 +1584,39 @@ namespace boost } // assignment -#ifndef BOOST_NO_RVALUE_REFERENCES - packaged_task(packaged_task&& other): - future_obtained(other.future_obtained) - { - task.swap(other.task); - other.future_obtained=false; - } - packaged_task& operator=(packaged_task&& other) + packaged_task(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT : + future_obtained(BOOST_THREAD_RV(other).future_obtained) { - packaged_task temp(static_cast<packaged_task&&>(other)); - swap(temp); - return *this; + task.swap(BOOST_THREAD_RV(other).task); + BOOST_THREAD_RV(other).future_obtained=false; } -#else - packaged_task(boost::detail::thread_move_t<packaged_task> other): - future_obtained(other->future_obtained) + packaged_task& operator=(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT { - task.swap(other->task); - other->future_obtained=false; - } - packaged_task& operator=(boost::detail::thread_move_t<packaged_task> other) - { - packaged_task temp(other); + packaged_task temp(static_cast<BOOST_THREAD_RV_REF(packaged_task)>(other)); swap(temp); return *this; } - operator boost::detail::thread_move_t<packaged_task>() + + void reset() { - return boost::detail::thread_move_t<packaged_task>(*this); + if (!valid()) + throw future_error(system::make_error_code(future_errc::no_state)); + task->reset(); + future_obtained=false; } -#endif - void swap(packaged_task& other) + void swap(packaged_task& other) BOOST_NOEXCEPT { task.swap(other.task); std::swap(future_obtained,other.future_obtained); } + bool valid() const BOOST_NOEXCEPT + { + return task.get()!=0; + } // result retrieval - unique_future<R> get_future() + BOOST_THREAD_FUTURE<R> get_future() { if(!task) { @@ -1403,12 +1625,14 @@ namespace boost else if(!future_obtained) { future_obtained=true; - return unique_future<R>(task); + return BOOST_THREAD_FUTURE<R>(task); } else { boost::throw_exception(future_already_retrieved()); } + return BOOST_THREAD_FUTURE<R>(); + } @@ -1430,14 +1654,50 @@ namespace boost }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<packaged_task<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + namespace container + { + template <class R, class Alloc> + struct uses_allocator<packaged_task<R>, Alloc> + : public true_type {}; + } #endif -} + BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task<T> BOOST_THREAD_DCL_MOVABLE_END + +// template <class F> +// BOOST_THREAD_FUTURE<typename boost::result_of<F()>::type> +// async(launch policy, F f) +// { +// typedef typename boost::result_of<F()>::type R; +// typedef BOOST_THREAD_FUTURE<R> future; +// if (int(policy) & int(launch::async)) +// { +// packaged_task<R> pt( f ); +// +// BOOST_THREAD_FUTURE ret = pt.get_future(); +// boost::thread( boost::move(pt) ).detach(); +// return ::boost::move(ret); +// } +// else if (int(policy) & int(launch::deferred)) +// { +// packaged_task<R> pt( f ); +// +// BOOST_THREAD_FUTURE ret = pt.get_future(); +// return ::boost::move(ret); +// } +// } +// +// template <class F> +// BOOST_THREAD_FUTURE<typename boost::result_of<F()>::type> +// async(F f) +// { +// return async(launch::any, f); +// } -#endif + +} + +#endif // BOOST_NO_EXCEPTION +#endif // header |