diff --git a/example/future_unwrap.cpp b/example/future_unwrap.cpp index 017ffaf0..4f252805 100644 --- a/example/future_unwrap.cpp +++ b/example/future_unwrap.cpp @@ -41,10 +41,28 @@ int main() for (int i=0; i< number_of_tests; i++) try { - boost::future > outer_future = boost::async(boost::launch::async, &p2); - boost::future inner_future = outer_future.unwrap(); - int ii = inner_future.get(); - BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + { + boost::future inner_future = boost::async(boost::launch::async, &p2); + inner_future.wait(); + int ii = inner_future.get(); + BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG; + } +#endif + { + boost::future > outer_future = boost::async(boost::launch::async, &p2); + boost::future inner_future = outer_future.unwrap(); + inner_future.wait(); + int ii = inner_future.get(); + BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG; + } + { + boost::future > outer_future = boost::async(boost::launch::async, &p2); + boost::future inner_future = outer_future.unwrap(); + int ii = inner_future.get(); + BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG; + } } catch (std::exception& ex) { diff --git a/include/boost/thread/detail/invoker.hpp b/include/boost/thread/detail/invoker.hpp index 60dc2c6c..9f38e979 100644 --- a/include/boost/thread/detail/invoker.hpp +++ b/include/boost/thread/detail/invoker.hpp @@ -99,7 +99,7 @@ namespace boost result_type execute(tuple_indices) { - return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get(f_))...); + return detail::invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get(f_))...); } }; @@ -136,7 +136,7 @@ namespace boost result_type execute(tuple_indices) { - return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get(f_))...); + return detail::invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get(f_))...); } }; //BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker BOOST_THREAD_DCL_MOVABLE_END @@ -190,7 +190,7 @@ namespace boost {} \ \ result_type operator()() { \ - return invoke(boost::move(fp_) \ + return detail::invoke(boost::move(fp_) \ BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \ ); \ } \ @@ -315,7 +315,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -381,7 +381,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -442,7 +442,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -498,7 +498,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -549,7 +549,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -595,7 +595,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -636,7 +636,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) , boost::move(v2_) @@ -672,7 +672,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) , boost::move(v1_) ); @@ -703,7 +703,7 @@ namespace boost result_type operator()() { - return invoke(boost::move(fp_) + return detail::invoke(boost::move(fp_) , boost::move(v0_) ); } diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 2e97e5cb..3c702db0 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -72,7 +72,7 @@ namespace boost void run2(tuple_indices) { - invoke(std::move(std::get<0>(fp)), std::move(std::get(fp))...); + detail::invoke(std::move(std::get<0>(fp)), std::move(std::get(fp))...); } void run() { diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 6f6243ff..c31c5011 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -3693,9 +3693,6 @@ namespace detail typename decay::type... )>::type> async(launch policy, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { - typedef typename boost::result_of::type( - typename decay::type... - )>::type R; typedef detail::invoker::type, typename decay::type...> BF; typedef typename BF::result_type Rp; @@ -4252,13 +4249,11 @@ namespace detail { F parent; Fp continuation; - shared_ptr centinel; public: continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : parent(boost::move(f)), - continuation(boost::move(c)), - centinel(parent.future_) + continuation(boost::move(c)) { } @@ -4273,6 +4268,31 @@ namespace detail } catch(...) { this->mark_exceptional_finish(); } + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + } + + void call(boost::unique_lock& lck) { + try { + relocker relock(lck); + + // neither continuation nor parent are protected by the lock - call() must only + // be called once, and no one else must modify it. + Rp res = this->continuation(boost::move(this->parent)); + + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + + relock.lock(); + + this->mark_finished_with_result_internal(boost::move(res), lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + + // make sure parent is really cleared to prevent memory "leaks" + relocker relock(lck); + this->parent = F(); + } } static void run(shared_ptr that_) @@ -4289,13 +4309,11 @@ namespace detail { F parent; Fp continuation; - shared_ptr centinel; public: continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) : parent(boost::move(f)), - continuation(boost::move(c)), - centinel(parent.future_) + continuation(boost::move(c)) { } @@ -4312,6 +4330,29 @@ namespace detail } catch(...) { this->mark_exceptional_finish(); } + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + } + + void call(boost::unique_lock& lck) { + try { + { + relocker relock(lck); + // neither continuation nor parent are protected by the lock - call() must only + // be called once, and no one else must modify it. + this->continuation(boost::move(this->parent)); + + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + } + this->mark_finished_with_result_internal(lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + + // make sure parent is really cleared to prevent memory "leaks" + relocker relock(lck); + this->parent = F(); + } } static void run(shared_ptr that_) @@ -4536,56 +4577,7 @@ namespace detail { boost::unique_lock lk(this->mutex); if (this->is_deferred_) { this->is_deferred_=false; - this->execute(lk); - } - } - - virtual void execute(boost::unique_lock& lck) { - try { - Fp local_fuct=boost::move(this->continuation); - F ftmp = boost::move(this->parent); - relocker relock(lck); - Rp res = local_fuct(boost::move(ftmp)); - relock.lock(); - this->mark_finished_with_result_internal(boost::move(res), lck); - } catch (...) { - this->mark_exceptional_finish_internal(current_exception(), lck); - } - } - }; - - template - struct future_deferred_continuation_shared_state: continuation_shared_state - { - typedef continuation_shared_state base_type; - - public: - future_deferred_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) - : base_type(boost::move(f), boost::forward(c)) - { - this->set_deferred(); - } - - ~future_deferred_continuation_shared_state() { - } - virtual void launch_continuation() { - boost::unique_lock lk(this->mutex); - if (this->is_deferred_) { - this->is_deferred_=false; - this->execute(lk); - } - } - - virtual void execute(boost::unique_lock& lck) { - try { - Fp local_fuct=boost::move(this->continuation); - F ftmp = boost::move(this->parent); - relocker relock(lck); - local_fuct(boost::move(ftmp)); - relock.lock(); - this->mark_finished_with_result_internal(lck); - } catch (...) { - this->mark_exceptional_finish_internal(current_exception(), lck); + this->call(lk); } } }; @@ -4609,53 +4601,7 @@ namespace detail { boost::unique_lock lk(this->mutex); if (this->is_deferred_) { this->is_deferred_=false; - this->execute(lk); - } - } - - virtual void execute(boost::unique_lock& lck) { - try { - Fp local_fuct=boost::move(this->continuation); - F ftmp = this->parent; - relocker relock(lck); - Rp res = local_fuct(ftmp); - relock.lock(); - this->mark_finished_with_result_internal(boost::move(res), lck); - } catch (...) { - this->mark_exceptional_finish_internal(current_exception(), lck); - } - } - }; - - template - struct shared_future_deferred_continuation_shared_state: continuation_shared_state - { - typedef continuation_shared_state base_type; - public: - shared_future_deferred_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) - : base_type(boost::move(f), boost::forward(c)) - { - this->set_deferred(); - } - - virtual void launch_continuation() { - boost::unique_lock lk(this->mutex); - if (this->is_deferred_) { - this->is_deferred_=false; - this->execute(lk); - } - } - - virtual void execute(boost::unique_lock& lck) { - try { - Fp local_fuct=boost::move(this->continuation); - F ftmp = this->parent; - relocker relock(lck); - local_fuct(ftmp); - relock.lock(); - this->mark_finished_with_result_internal(lck); - } catch (...) { - this->mark_exceptional_finish_internal(current_exception(), lck); + this->call(lk); } } }; @@ -4800,7 +4746,10 @@ namespace detail { typedef typename boost::result_of)>::type future_type; BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + if (underlying_cast(policy) & int(launch::async)) { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( lock, boost::move(*this), boost::forward(func) @@ -4863,7 +4812,10 @@ namespace detail { typedef typename boost::result_of)>::type future_type; BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, lock, boost::move(*this), boost::forward(func) ))); @@ -4884,7 +4836,10 @@ namespace detail { typedef typename boost::result_of)>::type future_type; BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + launch policy = this->launch_policy(lock); if (underlying_cast(policy) & int(launch::deferred)) { this->future_->wait_internal(lock); @@ -4912,7 +4867,10 @@ namespace detail { typedef typename boost::result_of)>::type future_type; BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + if (underlying_cast(policy) & int(launch::async)) { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( lock, boost::move(*this), boost::forward(func) @@ -4983,7 +4941,10 @@ namespace detail { typedef typename boost::result_of)>::type future_type; BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, lock, boost::move(*this), boost::forward(func) ))); @@ -5006,7 +4967,10 @@ namespace detail { typedef typename boost::result_of)>::type future_type; BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + launch policy = this->launch_policy(lock); if (underlying_cast(policy) & int(launch::deferred)) { @@ -5297,7 +5261,11 @@ namespace detail BOOST_THREAD_FUTURE >::unwrap() { BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); - boost::unique_lock lock(this->future_->mutex); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + return boost::detail::make_future_unwrap_shared_state >, R2>(lock, boost::move(*this)); } #endif diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index 2aa6cd6b..a6033515 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -68,17 +68,14 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS thread_cv_detail::lock_on_exit > guard; detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + pthread_mutex_t* the_mutex = &internal_mutex; guard.activate(m); - do { - res = pthread_cond_wait(&cond,&internal_mutex); - } while (res == EINTR); #else - //boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); pthread_mutex_t* the_mutex = m.mutex()->native_handle(); +#endif do { res = pthread_cond_wait(&cond,the_mutex); } while (res == EINTR); -#endif } #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); @@ -99,18 +96,17 @@ namespace boost boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned")); } #endif - thread_cv_detail::lock_on_exit > guard; int cond_res; { #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + thread_cv_detail::lock_on_exit > guard; detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + pthread_mutex_t* the_mutex = &internal_mutex; guard.activate(m); - cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); #else - //boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); pthread_mutex_t* the_mutex = m.mutex()->native_handle(); - cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout); #endif + cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout); } #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); @@ -178,7 +174,7 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); #else - boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); + boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); #endif guard.activate(m); res=pthread_cond_wait(&cond,&internal_mutex); @@ -405,7 +401,7 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); #else - boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); + boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); #endif guard.activate(m); res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); @@ -423,8 +419,6 @@ namespace boost } return true; } - - }; } diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 4743d2db..969e58cc 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -80,8 +80,8 @@ namespace boost { static void tls_destructor(void* data) { - boost::detail::thread_data_base* thread_info=static_cast(data); - //boost::detail::thread_data_ptr thread_info = static_cast(data)->shared_from_this(); + //boost::detail::thread_data_base* thread_info=static_cast(data); + boost::detail::thread_data_ptr thread_info = static_cast(data)->shared_from_this(); if(thread_info) { @@ -110,10 +110,7 @@ namespace boost thread_info->tss_data.erase(current); } } - if (thread_info) // fixme: should we test this? - { - thread_info->self.reset(); - } + thread_info->self.reset(); } } }