diff options
Diffstat (limited to 'boost/thread/future.hpp')
-rw-r--r-- | boost/thread/future.hpp | 149 |
1 files changed, 91 insertions, 58 deletions
diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp index 1234cb85a7..e5fd1921b0 100644 --- a/boost/thread/future.hpp +++ b/boost/thread/future.hpp @@ -159,7 +159,7 @@ namespace boost boost::function<void()> callback; // This declaration should be only included conditionally, but is included to maintain the same layout. continuations_type continuations; - executor_ptr_type ex; + executor_ptr_type ex_; // This declaration should be only included conditionally, but is included to maintain the same layout. virtual void launch_continuation() @@ -173,43 +173,49 @@ namespace boost is_constructed(false), policy_(launch::none), continuations(), - ex() + ex_() {} - shared_state_base(exceptional_ptr const& ex_): - exception(ex_.ptr_), + shared_state_base(exceptional_ptr const& ex): + exception(ex.ptr_), done(true), is_valid_(true), is_deferred_(false), is_constructed(false), policy_(launch::none), continuations(), - ex() + ex_() {} virtual ~shared_state_base() { } + + bool is_done() + { + return done; + } + executor_ptr_type get_executor() { - return ex; + return ex_; } void set_executor_policy(executor_ptr_type aex) { set_executor(); - ex = aex; + ex_ = aex; } void set_executor_policy(executor_ptr_type aex, boost::lock_guard<boost::mutex>&) { set_executor(); - ex = aex; + ex_ = aex; } void set_executor_policy(executor_ptr_type aex, boost::unique_lock<boost::mutex>&) { set_executor(); - ex = aex; + ex_ = aex; } bool valid(boost::unique_lock<boost::mutex>&) { return is_valid_; } @@ -262,6 +268,10 @@ namespace boost external_waiters.erase(it); } +#if 0 + // this inline definition results in ODR. See https://github.com/boostorg/thread/issues/193 + // to avoid it, we define the function on the derived templates using the macro BOOST_THREAD_DO_CONTINUATION +#define BOOST_THREAD_DO_CONTINUATION #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION void do_continuation(boost::unique_lock<boost::mutex>& lock) { @@ -279,6 +289,31 @@ namespace boost { } #endif + +#else +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#define BOOST_THREAD_DO_CONTINUATION \ + void do_continuation(boost::unique_lock<boost::mutex>& lock) \ + { \ + if (! this->continuations.empty()) { \ + continuations_type the_continuations = this->continuations; \ + this->continuations.clear(); \ + relocker rlk(lock); \ + for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { \ + (*it)->launch_continuation(); \ + } \ + } \ + } +#else +#define BOOST_THREAD_DO_CONTINUATION \ + void do_continuation(boost::unique_lock<boost::mutex>&) \ + { \ + } +#endif + + virtual void do_continuation(boost::unique_lock<boost::mutex>&) = 0; +#endif + #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock) { @@ -348,10 +383,7 @@ namespace boost is_deferred_=false; execute(lk); } - while(!done) - { - waiters.wait(lk); - } + waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this))); if(rethrow && exception) { boost::rethrow_exception(exception); @@ -370,6 +402,17 @@ namespace boost } #if defined BOOST_THREAD_USES_DATETIME + template<typename Duration> + bool timed_wait(Duration const& rel_time) + { + boost::unique_lock<boost::mutex> lock(this->mutex); + if (is_deferred_) + return false; + + do_callback(lock); + return waiters.timed_wait(lock, rel_time, boost::bind(&shared_state_base::is_done, boost::ref(*this))); + } + bool timed_wait_until(boost::system_time const& target_time) { boost::unique_lock<boost::mutex> lock(this->mutex); @@ -377,15 +420,7 @@ namespace boost return false; do_callback(lock); - while(!done) - { - bool const success=waiters.timed_wait(lock,target_time); - if(!success && !done) - { - return false; - } - } - return true; + return waiters.timed_wait(lock, target_time, boost::bind(&shared_state_base::is_done, boost::ref(*this))); } #endif #ifdef BOOST_THREAD_USES_CHRONO @@ -398,13 +433,9 @@ namespace boost if (is_deferred_) return future_status::deferred; do_callback(lock); - while(!done) + if(!waiters.wait_until(lock, abs_time, boost::bind(&shared_state_base::is_done, boost::ref(*this)))) { - cv_status const st=waiters.wait_until(lock,abs_time); - if(st==cv_status::timeout && !done) - { - return future_status::timeout; - } + return future_status::timeout; } return future_status::ready; } @@ -546,10 +577,8 @@ namespace boost detail::shared_state_base(ex), result() {} - - ~shared_state() - { - } + // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193 + BOOST_THREAD_DO_CONTINUATION void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock) { @@ -732,9 +761,8 @@ namespace boost detail::shared_state_base(ex), result(0) {} - ~shared_state() - { - } + // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193 + BOOST_THREAD_DO_CONTINUATION void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock) { @@ -811,6 +839,9 @@ namespace boost detail::shared_state_base(ex) {} + // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193 + BOOST_THREAD_DO_CONTINUATION + void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock) { mark_finished_internal(lock); @@ -899,10 +930,7 @@ namespace boost join(); #elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS unique_lock<boost::mutex> lk(this->mutex); - while(!this->done) - { - this->waiters.wait(lk); - } + this->waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this))); #endif } @@ -1007,10 +1035,8 @@ namespace boost template<typename Rp, typename Fp> struct future_deferred_shared_state: shared_state<Rp> { - typedef shared_state<Rp> base_type; Fp func_; - public: explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) : func_(boost::move(f)) { @@ -1035,10 +1061,8 @@ namespace boost template<typename Rp, typename Fp> struct future_deferred_shared_state<Rp&,Fp>: shared_state<Rp&> { - typedef shared_state<Rp&> base_type; Fp func_; - public: explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) : func_(boost::move(f)) { @@ -1060,10 +1084,8 @@ namespace boost template<typename Fp> struct future_deferred_shared_state<void,Fp>: shared_state<void> { - typedef shared_state<void> base_type; Fp func_; - public: explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) : func_(boost::move(f)) { @@ -1091,7 +1113,6 @@ namespace boost public: typedef std::vector<int>::size_type count_type; private: - struct registered_waiter; struct registered_waiter { boost::shared_ptr<detail::shared_state_base> future_; @@ -1452,7 +1473,11 @@ namespace boost template<typename Duration> bool timed_wait(Duration const& rel_time) const { - return timed_wait_until(boost::get_system_time()+rel_time); + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->timed_wait(rel_time); } bool timed_wait_until(boost::system_time const& abs_time) const @@ -3155,7 +3180,7 @@ namespace boost } }; -#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) @@ -3497,7 +3522,7 @@ namespace boost {} // construction and destruction -#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) @@ -3587,7 +3612,7 @@ namespace boost #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS -#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) template <class Allocator> packaged_task(boost::allocator_arg_t, Allocator a, R(*f)()) { @@ -3608,7 +3633,7 @@ namespace boost task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) ); future_obtained = false; } -#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES template <class F, class Allocator> @@ -3825,7 +3850,7 @@ namespace detail // future<R> async(launch policy, F&&, ArgTypes&&...); //////////////////////////////// -#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) template <class R, class... ArgTypes> @@ -3884,7 +3909,7 @@ namespace detail } } #endif -#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) +#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) @@ -4113,7 +4138,7 @@ namespace detail { //#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE) -#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR template <class Executor, class R, class... ArgTypes> BOOST_THREAD_FUTURE<R> @@ -4129,7 +4154,7 @@ namespace detail { ) )); } -#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR template <class Executor, class F, class ...ArgTypes> BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type( @@ -4148,7 +4173,7 @@ namespace detail { } #else // ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR template <class Executor, class R> BOOST_THREAD_FUTURE<R> @@ -4178,7 +4203,7 @@ namespace detail { ) )); } -#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR template <class Executor, class F> BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type()>::type> @@ -4234,7 +4259,7 @@ namespace detail { // future<R> async(F&&, ArgTypes&&...); //////////////////////////////// -#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) template <class R, class... ArgTypes> BOOST_THREAD_FUTURE<R> @@ -4956,6 +4981,10 @@ namespace detail { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>( lock, boost::move(*this), boost::forward<F>(func) ))); + } else if (underlying_cast<int>(policy) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>( + lock, boost::move(*this), boost::forward<F>(func) + ))); #ifdef BOOST_THREAD_PROVIDES_EXECUTORS } else if (underlying_cast<int>(policy) & int(launch::executor)) { assert(this->future_->get_executor()); @@ -4976,6 +5005,10 @@ namespace detail { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>( lock, boost::move(*this), boost::forward<F>(func) ))); + } else if (underlying_cast<int>(policy_) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>( + lock, boost::move(*this), boost::forward<F>(func) + ))); #ifdef BOOST_THREAD_PROVIDES_EXECUTORS } else if (underlying_cast<int>(policy_) & int(launch::executor)) { assert(this->future_->get_executor()); |