diff --git a/doc/sync_tutorial.qbk b/doc/sync_tutorial.qbk index 1ea6dbf0..dd4002c7 100644 --- a/doc/sync_tutorial.qbk +++ b/doc/sync_tutorial.qbk @@ -7,7 +7,7 @@ [section:tutorial Tutorial] -[@http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost. +[@http://web.archive.org/web/20140531071228/http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html Mutex, Lock, Condition Variable Rationale] adds rationale for the design decisions made for mutexes, locks and condition variables. diff --git a/example/executor.cpp b/example/executor.cpp index 6cd29eda..e0683c48 100644 --- a/example/executor.cpp +++ b/example/executor.cpp @@ -27,8 +27,10 @@ #include #include #include +#include -boost::future p(boost::future) { +boost::future p(boost::future f) { + assert(f.is_ready()); return boost::make_ready_future(); } @@ -200,10 +202,13 @@ int main() && defined BOOST_THREAD_PROVIDES_EXECUTORS \ && ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + boost::basic_thread_pool executor; // compiles boost::make_ready_future().then(&p); - boost::basic_thread_pool executor; + // ?? + boost::make_ready_future().then(executor, &p); + // doesn't compile boost::make_ready_future().then(executor, &p); #endif diff --git a/example/make_future.cpp b/example/make_future.cpp index 3b427e39..76207d7a 100644 --- a/example/make_future.cpp +++ b/example/make_future.cpp @@ -94,6 +94,11 @@ int main() f.get(); } #endif + { + std::cout << __FILE__ << " "<< __LINE__ << std::endl; + boost::future f = compute(-1); + f.wait(); + } { std::cout << __FILE__ << " "<< __LINE__ << std::endl; boost::future f = compute(0); @@ -124,11 +129,11 @@ int main() boost::future f = boost::make_ready_future(boost::cref(i)); std::cout << f.get() << std::endl; } -// { -// std::cout << __FILE__ << " "<< __LINE__ << std::endl; -// boost::future f = compute(2); -// std::cout << f.get() << std::endl; -// } + { + std::cout << __FILE__ << " "<< __LINE__ << std::endl; + boost::future f = compute(2); + std::cout << f.get() << std::endl; + } { std::cout << __FILE__ << " "<< __LINE__ << std::endl; boost::shared_future f = shared_compute(0); diff --git a/example/producer_consumer.cpp b/example/producer_consumer.cpp index 51979b6c..73ad04fb 100644 --- a/example/producer_consumer.cpp +++ b/example/producer_consumer.cpp @@ -24,7 +24,7 @@ #endif #include -void producer(the_ostream &mos, boost::sync_queue & sbq) +void producer(the_ostream & /*mos*/, boost::sync_queue & sbq) { using namespace boost; try { @@ -32,22 +32,22 @@ void producer(the_ostream &mos, boost::sync_queue & sbq) { sbq.push(i); //sbq << i; - mos << "push(" << i << ") "<< sbq.size()<<"\n"; + //mos << "push(" << i << ") "<< sbq.size()<<"\n"; this_thread::sleep_for(chrono::milliseconds(200)); } } catch(sync_queue_is_closed&) { - mos << "closed !!!\n"; + //mos << "closed !!!\n"; } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } void consumer( - the_ostream &mos, + the_ostream & /*mos*/, boost::sync_queue & sbq) { using namespace boost; @@ -57,21 +57,21 @@ void consumer( int r; sbq.pull(r); //sbq >> r; - mos << i << " pull(" << r << ") "<< sbq.size()<<"\n"; + //mos << i << " pull(" << r << ") "<< sbq.size()<<"\n"; this_thread::sleep_for(chrono::milliseconds(250)); } } catch(sync_queue_is_closed&) { - mos << "closed !!!\n"; + //mos << "closed !!!\n"; } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } -void consumer2(the_ostream &mos, boost::sync_queue & sbq) +void consumer2(the_ostream &/*mos*/, boost::sync_queue & sbq) { using namespace boost; try { @@ -81,17 +81,17 @@ void consumer2(the_ostream &mos, boost::sync_queue & sbq) queue_op_status st = sbq.try_pull(r); if (queue_op_status::closed == st) break; if (queue_op_status::success == st) { - mos << i << " pull(" << r << ")\n"; + //mos << i << " pull(" << r << ")\n"; } this_thread::sleep_for(chrono::milliseconds(250)); } } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } -void consumer3(the_ostream &mos, boost::sync_queue & sbq) +void consumer3(the_ostream &/*mos*/, boost::sync_queue & sbq) { using namespace boost; try { @@ -100,13 +100,13 @@ void consumer3(the_ostream &mos, boost::sync_queue & sbq) int r; queue_op_status res = sbq.wait_pull(r); if (res==queue_op_status::closed) break; - mos << i << " wait_pull(" << r << ")\n"; + //mos << i << " wait_pull(" << r << ")\n"; this_thread::sleep_for(chrono::milliseconds(250)); } } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } diff --git a/example/producer_consumer2.cpp b/example/producer_consumer2.cpp index 9e3ad976..a8264a9b 100644 --- a/example/producer_consumer2.cpp +++ b/example/producer_consumer2.cpp @@ -27,7 +27,7 @@ #include #include -void producer(the_ostream &mos, boost::queue_back sbq) +void producer(the_ostream &/*mos*/, boost::queue_back sbq) { using namespace boost; try { @@ -35,22 +35,22 @@ void producer(the_ostream &mos, boost::queue_back sbq) { sbq.push(i); //sbq << i; - mos << "push(" << i << ") " << sbq.size() <<"\n"; + //mos << "push(" << i << ") " << sbq.size() <<"\n"; this_thread::sleep_for(chrono::milliseconds(200)); } } catch(sync_queue_is_closed&) { - mos << "closed !!!\n"; + //mos << "closed !!!\n"; } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } void consumer( - the_ostream &mos, + the_ostream &/*mos*/, boost::queue_front sbq) { using namespace boost; @@ -60,21 +60,21 @@ void consumer( int r; sbq.pull(r); //sbq >> r; - mos << i << " pull(" << r << ") " << sbq.size() <<"\n"; + //mos << i << " pull(" << r << ") " << sbq.size() <<"\n"; this_thread::sleep_for(chrono::milliseconds(250)); } } catch(sync_queue_is_closed&) { - mos << "closed !!!\n"; + //mos << "closed !!!\n"; } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } -void consumer2(the_ostream &mos, boost::queue_front sbq) +void consumer2(the_ostream &/*mos*/, boost::queue_front sbq) { using namespace boost; try { @@ -84,17 +84,17 @@ void consumer2(the_ostream &mos, boost::queue_front sbq) queue_op_status st = sbq.try_pull(r); if (queue_op_status::closed == st) break; if (queue_op_status::success == st) { - mos << i << " try_pull(" << r << ")\n"; + //mos << i << " try_pull(" << r << ")\n"; } this_thread::sleep_for(chrono::milliseconds(250)); } } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } -void consumer3(the_ostream &mos, boost::queue_front sbq) +void consumer3(the_ostream &/*mos*/, boost::queue_front sbq) { using namespace boost; try { @@ -103,13 +103,13 @@ void consumer3(the_ostream &mos, boost::queue_front sbq) int r; queue_op_status res = sbq.wait_pull(r); if (res==queue_op_status::closed) break; - mos << i << " wait_pull(" << r << ")\n"; + //mos << i << " wait_pull(" << r << ")\n"; this_thread::sleep_for(chrono::milliseconds(250)); } } catch(...) { - mos << "exception !!!\n"; + //mos << "exception !!!\n"; } } diff --git a/example/recursive_mutex.cpp b/example/recursive_mutex.cpp index a5894832..8cb99d30 100644 --- a/example/recursive_mutex.cpp +++ b/example/recursive_mutex.cpp @@ -32,7 +32,7 @@ counter c; void change_count() { - std::cout << "count == " << c.increment() << std::endl; + //std::cout << "count == " << c.increment() << std::endl; } int main(int, char*[]) diff --git a/example/serial_executor.cpp b/example/serial_executor.cpp index f64ac4b9..36208369 100644 --- a/example/serial_executor.cpp +++ b/example/serial_executor.cpp @@ -27,16 +27,16 @@ void p1() { - std::cout << BOOST_CONTEXTOF << std::endl; + //std::cout << BOOST_CONTEXTOF << std::endl; boost::this_thread::sleep_for(boost::chrono::milliseconds(30)); - std::cout << BOOST_CONTEXTOF << std::endl; + //std::cout << BOOST_CONTEXTOF << std::endl; } void p2() { - std::cout << BOOST_CONTEXTOF << std::endl; + //std::cout << BOOST_CONTEXTOF << std::endl; boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); - std::cout << BOOST_CONTEXTOF << std::endl; + //std::cout << BOOST_CONTEXTOF << std::endl; } int f1() @@ -54,7 +54,6 @@ int f2(int i) template void submit_some(boost::serial_executor& tp) { - std::cout << BOOST_CONTEXTOF << std::endl; for (int i = 0; i < 3; ++i) { std::cout << BOOST_CONTEXTOF << std::endl; tp.submit(&p2); @@ -63,7 +62,6 @@ void submit_some(boost::serial_executor& tp) std::cout << BOOST_CONTEXTOF << std::endl; tp.submit(&p1); } - std::cout << BOOST_CONTEXTOF << std::endl; } @@ -75,20 +73,17 @@ void at_th_entry(boost::basic_thread_pool& ) int test_executor_adaptor() { - // std::cout << BOOST_CONTEXTOF << std::endl; { try { #if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - // std::cout << BOOST_CONTEXTOF << std::endl; { boost::basic_thread_pool ea1(4); boost::serial_executor ea2(ea1); submit_some(ea2); } #endif - // std::cout << BOOST_CONTEXTOF << std::endl; } catch (std::exception& ex) { @@ -101,7 +96,6 @@ int test_executor_adaptor() return 2; } } - // std::cout << BOOST_CONTEXTOF << std::endl; return 0; } diff --git a/example/thread_group.cpp b/example/thread_group.cpp index 5f501100..1256a104 100644 --- a/example/thread_group.cpp +++ b/example/thread_group.cpp @@ -59,6 +59,7 @@ int main() threads.remove_thread(th); BOOST_TEST(! threads.is_thread_in(th)); th->join(); + delete th; } { { diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index b80eacfa..7d7a9da5 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -173,7 +173,6 @@ namespace boost private: bool start_thread_noexcept(); bool start_thread_noexcept(const attributes& attr); - //public: void start_thread() { if (!start_thread_noexcept()) diff --git a/include/boost/thread/executors/basic_thread_pool.hpp b/include/boost/thread/executors/basic_thread_pool.hpp index afab0795..0c8e282c 100644 --- a/include/boost/thread/executors/basic_thread_pool.hpp +++ b/include/boost/thread/executors/basic_thread_pool.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 28239c4a..e2dcb434 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -137,7 +137,7 @@ namespace boost continuations_type continuations; // This declaration should be only included conditionally, but is included to maintain the same layout. - virtual void launch_continuation(boost::unique_lock&, shared_ptr) + virtual void launch_continuation() { } @@ -150,6 +150,19 @@ namespace boost policy_(launch::none), continuations() {} + + shared_state_base(exceptional_ptr const& ex): + exception(ex.ptr_), + done(true), + is_valid_(true), + is_deferred_(false), + is_constructed(false), + cnt_(0), + policy_(launch::none), + continuations() + {} + + virtual ~shared_state_base() { BOOST_ASSERT(cnt_==0); @@ -221,8 +234,7 @@ namespace boost continuations.clear(); relocker rlk(lock); for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { - boost::unique_lock cont_lock((*it)->mutex); - (*it)->launch_continuation(cont_lock, *it); + (*it)->launch_continuation(); } } } @@ -407,7 +419,7 @@ namespace boost return policy_; } - future_state::state get_state(boost::unique_lock& lk) const + future_state::state get_state(boost::unique_lock&) const { if(!done) { @@ -483,6 +495,10 @@ namespace boost shared_state(): result() {} + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex), result() + {} + ~shared_state() {} @@ -624,6 +640,10 @@ namespace boost result(0) {} + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex), result(0) + {} + ~shared_state() { } @@ -687,6 +707,10 @@ namespace boost shared_state() {} + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex) + {} + void mark_finished_with_result_internal(boost::unique_lock& lock) { mark_finished_internal(lock); @@ -1150,16 +1174,7 @@ namespace boost static //BOOST_CONSTEXPR future_ptr make_exceptional_future_ptr(exceptional_ptr const& ex) { - promise p; - p.set_exception(ex.ptr_); - return p.get_future().future_; - } - - void set_exceptional_if_invalid() { - if (valid()) return; - promise p; - p.set_exception(future_uninitialized()); - future_ = p.get_future().future_; + return future_ptr(new detail::shared_state(ex)); } future_ptr future_; @@ -2867,7 +2882,7 @@ namespace boost private: task_shared_state(task_shared_state&); #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) - typedef R (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes) ... ); + typedef R (*CallableType)(ArgTypes ... ); #else typedef R (*CallableType)(); #endif @@ -3098,7 +3113,7 @@ namespace boost private: task_shared_state(task_shared_state&); #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) - typedef void (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes)...); + typedef void (*CallableType)(ArgTypes...); #else typedef void (*CallableType)(); #endif @@ -3421,7 +3436,7 @@ namespace boost // execution #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) - void operator()(BOOST_THREAD_RV_REF(ArgTypes)... args) { + void operator()(ArgTypes... args) { if(!task) { boost::throw_exception(task_moved()); } @@ -4092,12 +4107,6 @@ namespace detail { } #endif - template - BOOST_THREAD_FUTURE make_ready_future(exception_ptr ex) { - promise p; - p.set_exception(ex); - return BOOST_THREAD_MAKE_RV_REF(p.get_future()); - } template BOOST_THREAD_FUTURE make_exceptional_future(exception_ptr ex) { @@ -4119,16 +4128,9 @@ namespace detail { p.set_exception(boost::current_exception()); return BOOST_THREAD_MAKE_RV_REF(p.get_future()); } - template - BOOST_THREAD_FUTURE make_exceptional_future_if_invalid(BOOST_THREAD_FWD_REF(BOOST_THREAD_FUTURE) fut) { - fut.set_exceptional_if_invalid(); - return boost::move(fut); - } - template - shared_future make_exceptional_future_if_invalid(shared_future fut) { - fut.set_exceptional_if_invalid(); - return fut; + BOOST_THREAD_FUTURE make_ready_future(exception_ptr ex) { + return make_exceptional_future(ex); } #if 0 @@ -4187,8 +4189,9 @@ namespace detail } - void launch_continuation(boost::unique_lock&, shared_ptr that) { - this->thr_ = thread(&future_async_continuation_shared_state::run, that); + void launch_continuation() { + boost::lock_guard lk(this->mutex); + this->thr_ = thread(&future_async_continuation_shared_state::run, this->shared_from_this()); } static void run(shared_ptr that_) { @@ -4218,8 +4221,9 @@ namespace detail centinel(parent.future_) { } - void launch_continuation(boost::unique_lock&, shared_ptr that) { - this->thr_ = thread(&future_async_continuation_shared_state::run, that); + void launch_continuation() { + boost::lock_guard lk(this->mutex); + this->thr_ = thread(&future_async_continuation_shared_state::run, this->shared_from_this()); } static void run(shared_ptr that_) { @@ -4269,9 +4273,8 @@ namespace detail this->set_executor(); } - void launch_continuation(boost::unique_lock& lck, shared_ptr that ) { - relocker relock(lck); - run_it fct(that); + void launch_continuation() { + run_it fct(this->shared_from_this()); ex->submit(fct); } @@ -4308,9 +4311,8 @@ namespace detail this->set_executor(); } - void launch_continuation(boost::unique_lock& lck, shared_ptr that ) { - relocker relock(lck); - run_it fct(that); + void launch_continuation() { + run_it fct(this->shared_from_this()); ex->submit(fct); } @@ -4351,8 +4353,9 @@ namespace detail centinel(parent.future_) { } - void launch_continuation(boost::unique_lock&, shared_ptr that) { - this->thr_ = thread(&shared_future_async_continuation_shared_state::run, that); + void launch_continuation() { + boost::lock_guard lk(this->mutex); + this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this->shared_from_this()); } static void run(shared_ptr that_) { @@ -4381,8 +4384,9 @@ namespace detail centinel(parent.future_) { } - void launch_continuation(boost::unique_lock&, shared_ptr that) { - this->thr_ = thread(&shared_future_async_continuation_shared_state::run, that); + void launch_continuation() { + boost::lock_guard lk(this->mutex); + this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this->shared_from_this()); } static void run(shared_ptr that_) { @@ -4419,9 +4423,8 @@ namespace detail this->set_executor(); } - void launch_continuation(boost::unique_lock& lck, shared_ptr that) { - relocker relock(lck); - run_it fct(that); + void launch_continuation() { + run_it fct(this->shared_from_this()); ex->submit(fct); } @@ -4457,9 +4460,8 @@ namespace detail centinel(parent.future_) { } - void launch_continuation(boost::unique_lock& lck, shared_ptr that) { - relocker relock(lck); - run_it fct(that); + void launch_continuation() { + run_it fct(this->shared_from_this()); ex->submit(fct); } @@ -4499,7 +4501,8 @@ namespace detail this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock&lk, shared_ptr ) { + virtual void launch_continuation() { + boost::unique_lock lk(this->mutex); if (this->is_deferred_) { this->is_deferred_=false; this->execute(lk); @@ -4537,7 +4540,8 @@ namespace detail ~future_deferred_continuation_shared_state() { } - virtual void launch_continuation(boost::unique_lock& lk, shared_ptr ) { + virtual void launch_continuation() { + boost::unique_lock lk(this->mutex); if (this->is_deferred_) { this->is_deferred_=false; this->execute(lk); @@ -4576,7 +4580,8 @@ namespace detail this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock& lk, shared_ptr ) { + virtual void launch_continuation() { + boost::unique_lock lk(this->mutex); if (this->is_deferred_) { this->is_deferred_=false; this->execute(lk); @@ -4612,7 +4617,8 @@ namespace detail this->set_deferred(); } - virtual void launch_continuation(boost::unique_lock& lk, shared_ptr ) { + virtual void launch_continuation() { + boost::unique_lock lk(this->mutex); if (this->is_deferred_) { this->is_deferred_=false; this->execute(lk); @@ -4826,14 +4832,17 @@ namespace detail boost::unique_lock lock(this->future_->mutex); if (underlying_cast(policy) & int(launch::async)) { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ))); } else if (underlying_cast(policy) & int(launch::deferred)) { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ))); } else { + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ))); @@ -4849,6 +4858,7 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); + lock.unlock(); return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type, F>(ex, lock, boost::move(*this), boost::forward(func) ))); @@ -4864,15 +4874,18 @@ namespace detail boost::unique_lock lock(this->future_->mutex); if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { + lock.unlock(); return boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ); } else if (underlying_cast(this->launch_policy(lock)) & int(launch::deferred)) { this->future_->wait_internal(lock); + lock.unlock(); return boost::detail::make_future_deferred_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ); } else { + lock.unlock(); return boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ); @@ -5013,41 +5026,87 @@ namespace detail template struct future_unwrap_shared_state: shared_state { - F parent; + F wrapped; + typename F::value_type unwrapped; public: explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) - : parent(boost::move(f)) {} - - typename F::value_type parent_value(boost::unique_lock& ) { - typename F::value_type r = parent.get(); - r.set_exceptional_if_invalid(); - return boost::move(r); + : wrapped(boost::move(f)) { } - virtual void wait(boost::unique_lock& lk, bool ) { // todo see if rethrow must be used - parent_value(lk).wait(); - } - virtual Rp get(boost::unique_lock& lk) { - return parent_value(lk).get(); - } -#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION - typedef shared_ptr continuation_ptr_type; - - virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock& lock) + void launch_continuation() { - boost::unique_lock lk(parent.future_->mutex); - parent.future_->set_continuation_ptr(continuation, lk); + boost::unique_lock lk(this->mutex); + if (! unwrapped.valid() ) + { + if (wrapped.has_exception()) { + this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); + } else { + unwrapped = wrapped.get(); + if (unwrapped.valid()) + { + lk.unlock(); + boost::unique_lock lk2(unwrapped.future_->mutex); + unwrapped.future_->set_continuation_ptr(this->shared_from_this(), lk2); + } else { + this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); + } + } + } else { + if (unwrapped.has_exception()) { + this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); + } else { + this->mark_finished_with_result_internal(unwrapped.get(), lk); + } + } } -#endif }; + template + struct future_unwrap_shared_state: shared_state + { + F wrapped; + typename F::value_type unwrapped; + public: + explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) + : wrapped(boost::move(f)) { + } + + void launch_continuation() + { + boost::unique_lock lk(this->mutex); + if (! unwrapped.valid() ) + { + if (wrapped.has_exception()) { + this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); + } else { + unwrapped = wrapped.get(); + if (unwrapped.valid()) + { + lk.unlock(); + boost::unique_lock lk2(unwrapped.future_->mutex); + unwrapped.future_->set_continuation_ptr(this->shared_from_this(), lk2); + } else { + this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); + } + } + } else { + if (unwrapped.has_exception()) { + this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); + } else { + this->mark_finished_with_result_internal(lk); + } + } + } + }; + + template BOOST_THREAD_FUTURE make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f) { shared_ptr > h(new future_unwrap_shared_state(boost::move(f))); lock.lock(); - h->parent.future_->set_continuation_ptr(h, lock); + h->wrapped.future_->set_continuation_ptr(h, lock); lock.unlock(); return BOOST_THREAD_FUTURE(h); } diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index e18030fd..29efa876 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -120,6 +120,15 @@ namespace boost unique_lock& m, duration_type const& wait_duration) { + if (wait_duration.is_pos_infinity()) + { + wait(m); // or do_wait(m,detail::timeout::sentinel()); + return true; + } + if (wait_duration.is_special()) + { + return true; + } return timed_wait(m,get_system_time()+wait_duration); } @@ -149,6 +158,18 @@ namespace boost unique_lock& m, duration_type const& wait_duration,predicate_type pred) { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); // or do_wait(m,detail::timeout::sentinel()); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } return timed_wait(m,get_system_time()+wait_duration,pred); } #endif diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 14c23ce0..23e9e444 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -339,8 +339,8 @@ namespace boost { if (wait_duration.is_pos_infinity()) { - wait(m); // or do_wait(m,detail::timeout::sentinel()); - return true; + wait(m); // or do_wait(m,detail::timeout::sentinel()); + return true; } if (wait_duration.is_special()) { @@ -362,6 +362,18 @@ namespace boost template bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); // or do_wait(m,detail::timeout::sentinel()); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } return do_wait(m,wait_duration.total_milliseconds(),pred); } #endif diff --git a/src/pthread/once.cpp b/src/pthread/once.cpp index 2cfe7cd1..f61d74c8 100644 --- a/src/pthread/once.cpp +++ b/src/pthread/once.cpp @@ -15,7 +15,9 @@ #include #include #include - +#if defined BOOST_THREAD_PATCH +#include // memcmp. +#endif namespace boost { namespace thread_detail diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index bbd25493..aa29615d 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -80,6 +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(); + if(thread_info) { while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks) @@ -124,7 +126,8 @@ namespace boost } ~delete_current_thread_tls_key_on_dlclose_t() { - if (current_thread_tls_init_flag.epoch!=BOOST_ONCE_INITIAL_FLAG_VALUE) + const boost::once_flag uninitialized = BOOST_ONCE_INIT; + if (memcmp(¤t_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag))) { pthread_key_delete(current_thread_tls_key); } @@ -158,8 +161,9 @@ namespace boost { static void* thread_proxy(void* param) { - boost::detail::thread_data_ptr thread_info = static_cast(param)->self; - //thread_info->self.reset(); + //boost::detail::thread_data_ptr thread_info = static_cast(param)->self; + boost::detail::thread_data_ptr thread_info = static_cast(param)->shared_from_this(); + thread_info->self.reset(); detail::set_current_thread_data(thread_info.get()); #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS BOOST_TRY @@ -252,7 +256,6 @@ namespace boost { thread_info->self.reset(); return false; -// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create")); } return true; } @@ -266,7 +269,6 @@ namespace boost { thread_info->self.reset(); return false; -// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create")); } int detached_state; res = pthread_attr_getdetachstate(h, &detached_state); @@ -274,7 +276,6 @@ namespace boost { thread_info->self.reset(); return false; -// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_attr_getdetachstate")); } if (PTHREAD_CREATE_DETACHED==detached_state) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7d3c9bfe..c75bdac1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -298,6 +298,7 @@ rule thread-compile ( sources : reqs * : name ) [ thread-compile test_10963.cpp : : test_10963_c ] [ thread-run test_10964.cpp ] [ thread-test test_11053.cpp ] + [ thread-run test_11266.cpp ] ; @@ -950,11 +951,18 @@ rule thread-compile ( sources : reqs * : name ) [ thread-run2-noit ./experimental/parallel/v2/task_region_pass.cpp : task_region_p ] ; - explicit ts_ ; - test-suite ts_ + explicit ts_other ; + test-suite ts_other : [ thread-run2 ../example/this_executor.cpp : ex_this_executor ] [ thread-run2 ../example/default_executor.cpp : ex_default_executor ] ; + explicit ts_ ; + test-suite ts_ + : + #[ thread-run test_11256.cpp ] + ; + + } diff --git a/test/sync/futures/future/then_deferred_pass.cpp b/test/sync/futures/future/then_deferred_pass.cpp index 455610f4..0a7848de 100644 --- a/test/sync/futures/future/then_deferred_pass.cpp +++ b/test/sync/futures/future/then_deferred_pass.cpp @@ -17,6 +17,7 @@ #include #include +#include #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION @@ -31,6 +32,8 @@ int p1() int p2(boost::future f) { + assert(f.is_ready()); + BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG; BOOST_TEST(f.valid()); int i = f.get(); @@ -41,6 +44,7 @@ int p2(boost::future f) void p3(boost::future f) { + assert(f.is_ready()); BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG; BOOST_TEST(f.valid()); int i = f.get(); diff --git a/test/sync/futures/future/then_executor_pass.cpp b/test/sync/futures/future/then_executor_pass.cpp index c3c2354b..8703fe51 100644 --- a/test/sync/futures/future/then_executor_pass.cpp +++ b/test/sync/futures/future/then_executor_pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION @@ -34,6 +35,7 @@ int p1() int p2(boost::future f) { + assert(f.is_ready()); BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG; BOOST_TEST(f.valid()); int i = f.get(); @@ -44,6 +46,7 @@ int p2(boost::future f) void p3(boost::future f) { + assert(f.is_ready()); BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG; BOOST_TEST(f.valid()); int i = f.get(); diff --git a/test/sync/mutual_exclusion/recursive_mutex/native_handle_pass.cpp b/test/sync/mutual_exclusion/recursive_mutex/native_handle_pass.cpp index b46619cd..b784f24e 100644 --- a/test/sync/mutual_exclusion/recursive_mutex/native_handle_pass.cpp +++ b/test/sync/mutual_exclusion/recursive_mutex/native_handle_pass.cpp @@ -29,7 +29,7 @@ int main() boost::recursive_mutex::native_handle_type h = m.native_handle(); BOOST_TEST(h); #else -#error "Test not applicable: BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE not defined for this platform as not supported" +#error "Test not applicable: BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE not defined for this platform as not supported" #endif return boost::report_errors(); diff --git a/test/test_10963.cpp b/test/test_10963.cpp index b918b55d..1ec8d6cf 100644 --- a/test/test_10963.cpp +++ b/test/test_10963.cpp @@ -8,9 +8,12 @@ #if ! defined BOOST_NO_CXX11_DECLTYPE #define BOOST_RESULT_OF_USE_DECLTYPE #endif +#define BOOST_THREAD_PROVIDES_EXECUTORS #include #include +#include +#include struct TestCallback @@ -19,12 +22,14 @@ struct TestCallback result_type operator()(boost::future future) const { + assert(future.is_ready()); future.get(); return boost::make_ready_future(); } result_type operator()(boost::future > future) const { + assert(future.is_ready()); future.get(); return boost::make_ready_future(); } @@ -33,12 +38,24 @@ struct TestCallback int main() { #if ! defined BOOST_NO_CXX11_DECLTYPE && ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS + { boost::promise test_promise; boost::future test_future(test_promise.get_future()); auto f1 = test_future.then(TestCallback()); BOOST_STATIC_ASSERT(std::is_same > >::value); auto f2 = f1.then(TestCallback()); BOOST_STATIC_ASSERT(std::is_same > >::value); + } + { + boost::basic_thread_pool executor; + boost::promise test_promise; + boost::future test_future(test_promise.get_future()); + auto f1 = test_future.then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + auto f2 = f1.then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + + } #endif return 0; } diff --git a/test/test_10964.cpp b/test/test_10964.cpp index b8cc7b5c..6cd26759 100644 --- a/test/test_10964.cpp +++ b/test/test_10964.cpp @@ -8,9 +8,12 @@ #if ! defined BOOST_NO_CXX11_DECLTYPE #define BOOST_RESULT_OF_USE_DECLTYPE #endif +#define BOOST_THREAD_PROVIDES_EXECUTORS #include #include +#include +#include struct TestCallback { @@ -18,13 +21,23 @@ struct TestCallback result_type operator()(boost::future future) const { - future.get(); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + assert(future.is_ready()); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + future.wait(); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; return boost::make_ready_future(); } result_type operator()(boost::future > future) const { - future.get(); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + assert(future.is_ready()); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + assert(future.get().is_ready()); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + //boost::future ff = future.get(); + return boost::make_ready_future(); } }; @@ -35,6 +48,8 @@ void p1() int main() { + const int number_of_tests = 2; + #if ! defined BOOST_NO_CXX11_DECLTYPE && ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; { @@ -43,34 +58,104 @@ int main() f1.wait(); } std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) { auto f1 = boost::make_ready_future().then(TestCallback()); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; BOOST_STATIC_ASSERT(std::is_same > >::value); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; auto f2 = f1.unwrap(); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; BOOST_STATIC_ASSERT(std::is_same >::value); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; f2.wait(); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; } std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) + { + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + auto f1 = boost::make_ready_future().then(TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + boost::future f2 = f1.get(); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) { auto f1 = boost::make_ready_future().then(TestCallback()); BOOST_STATIC_ASSERT(std::is_same > >::value); auto f2 = f1.unwrap(); BOOST_STATIC_ASSERT(std::is_same >::value); auto f3 = f2.then(TestCallback()); - BOOST_STATIC_ASSERT(std::is_same > >::value); + BOOST_STATIC_ASSERT(std::is_same > >::value); f3.wait(); } std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) { boost::make_ready_future().then( TestCallback()).unwrap().then(TestCallback()).get(); } std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) { boost::future f = boost::async(p1); f.then( TestCallback()).unwrap().then(TestCallback()).get(); } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) + { + auto f1 = boost::make_ready_future().then(TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + auto f3 = f1.then(TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + f3.wait(); + } + + + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) + { + boost::basic_thread_pool executor; + auto f1 = boost::make_ready_future().then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + auto f3 = f1.then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + f3.wait(); + } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) + { + boost::basic_thread_pool executor(1); + + auto f1 = boost::make_ready_future().then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + std::cout << __FILE__ << "[" << __LINE__ << "] " << int(f1.valid()) << std::endl; + auto f2 = f1.unwrap(); + std::cout << __FILE__ << "[" << __LINE__ << "] " << int(f2.valid()) << std::endl; + + BOOST_STATIC_ASSERT(std::is_same >::value); + auto f3 = f2.then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + f3.wait(); + } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) + { + boost::basic_thread_pool executor; + + auto f1 = boost::make_ready_future().then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + auto f2 = f1.unwrap(); + BOOST_STATIC_ASSERT(std::is_same >::value); + auto f3 = f2.then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + f3.wait(); + } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + #endif return 0; } diff --git a/test/test_11256.cpp b/test/test_11256.cpp new file mode 100644 index 00000000..13002f86 --- /dev/null +++ b/test/test_11256.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2015 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 +#define BOOST_THREAD_PROVIDES_EXECUTORS + +#include +#include +#include + +auto createFuture() +{ + boost::promise promise; + promise.set_value(); + return promise.get_future(); +} + +auto stepOne(boost::basic_thread_pool &executor) +{ + auto sendFuture = createFuture(); + auto wrappedFuture = sendFuture.then(executor, [](auto f) mutable { + return createFuture(); + }); + + return wrappedFuture.unwrap(); +} + +auto stepTwo(boost::basic_thread_pool &executor) +{ + auto future = stepOne(executor); + return future.then(executor, [](auto f) { + assert(f.is_ready()); + }); +} + +int main() +{ + boost::basic_thread_pool executor{1}; + stepTwo(executor).get(); +} diff --git a/test/test_11266.cpp b/test/test_11266.cpp new file mode 100644 index 00000000..0f736783 --- /dev/null +++ b/test/test_11266.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2015 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 + +void func(int) { } + +int main() +{ +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + { + boost::packaged_task task{func}; + } + { + boost::packaged_task task{func}; + + task(0); + } + { + boost::packaged_task task{func}; + int x = 0; + task(x); + } +#endif +} diff --git a/test/threads/thread/constr/FArgs_pass.cpp b/test/threads/thread/constr/FArgs_pass.cpp index c6630760..7b05786b 100644 --- a/test/threads/thread/constr/FArgs_pass.cpp +++ b/test/threads/thread/constr/FArgs_pass.cpp @@ -26,9 +26,9 @@ unsigned throw_one = 0xFFFF; #if defined _GLIBCXX_THROW -void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc) +inline void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc) #elif defined BOOST_MSVC -void* operator new(std::size_t s) +inline void* operator new(std::size_t s) #else void* operator new(std::size_t s) throw (std::bad_alloc) #endif @@ -40,9 +40,9 @@ void* operator new(std::size_t s) throw (std::bad_alloc) } #if defined BOOST_MSVC -void operator delete(void* p) +inline void operator delete(void* p) #else -void operator delete(void* p) throw () +inline void operator delete(void* p) throw () #endif { std::cout << __FILE__ << ":" << __LINE__ << std::endl; diff --git a/test/threads/thread/constr/lambda_pass.cpp b/test/threads/thread/constr/lambda_pass.cpp index 1d585a23..0ce72534 100644 --- a/test/threads/thread/constr/lambda_pass.cpp +++ b/test/threads/thread/constr/lambda_pass.cpp @@ -28,9 +28,9 @@ unsigned throw_one = 0xFFFF; #if defined _GLIBCXX_THROW -void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc) +inline void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc) #elif defined BOOST_MSVC -void* operator new(std::size_t s) +inline void* operator new(std::size_t s) #else void* operator new(std::size_t s) throw (std::bad_alloc) #endif @@ -41,9 +41,9 @@ void* operator new(std::size_t s) throw (std::bad_alloc) } #if defined BOOST_MSVC -void operator delete(void* p) +inline void operator delete(void* p) #else -void operator delete(void* p) throw () +inline void operator delete(void* p) throw () #endif { std::free(p);