From 6f53279b50622de004591037cb6cb70e9ba1d450 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 18 Apr 2015 19:26:07 +0200 Subject: [PATCH 01/23] ref #11174 - boost::condition_variable::timed_wait with predicate unexpectedly wakes up while should wait infinite. --- .../boost/thread/win32/condition_variable.hpp | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 14c23ce0..9a197c99 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -327,12 +327,30 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool timed_wait(unique_lock& m,boost::system_time const& abs_time) { - return do_wait(m,abs_time); + 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 do_wait(m,abs_time); } bool timed_wait(unique_lock& m,boost::xtime const& abs_time) { - return do_wait(m,system_time(abs_time)); + 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 do_wait(m,system_time(abs_time)); } template bool timed_wait(unique_lock& m,duration_type const& wait_duration) @@ -352,17 +370,44 @@ namespace boost template bool timed_wait(unique_lock& m,boost::system_time const& abs_time,predicate_type pred) { - return do_wait(m,abs_time,pred); + if (wait_duration.is_pos_infinity()) + { + wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + return do_wait(m,abs_time,pred); } template bool timed_wait(unique_lock& m,boost::xtime const& abs_time,predicate_type pred) { - return do_wait(m,system_time(abs_time),pred); + if (wait_duration.is_pos_infinity()) + { + wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + return do_wait(m,system_time(abs_time),pred); } template bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) { - return do_wait(m,wait_duration.total_milliseconds(),pred); + if (wait_duration.is_pos_infinity()) + { + wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + return do_wait(m,wait_duration.total_milliseconds(),pred); } #endif #ifdef BOOST_THREAD_USES_CHRONO From 8853a4cbdf34d2699d7997ea99adf62fe9d6d568 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Wed, 22 Apr 2015 07:23:38 +0200 Subject: [PATCH 02/23] ref #11174 - boost::condition_variable::timed_wait with predicate unexpectedly wakes up while should wait infinite. --- include/boost/thread/win32/condition_variable.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 9a197c99..7ec96ae4 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -327,12 +327,12 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool timed_wait(unique_lock& m,boost::system_time const& abs_time) { - if (wait_duration.is_pos_infinity()) + if (abs_time.is_pos_infinity()) { wait(m); // or do_wait(m,detail::timeout::sentinel()); return true; } - if (wait_duration.is_special()) + if (abs_time.is_special()) { return true; } @@ -341,12 +341,12 @@ namespace boost bool timed_wait(unique_lock& m,boost::xtime const& abs_time) { - if (wait_duration.is_pos_infinity()) + if (abs_time.is_pos_infinity()) { wait(m); // or do_wait(m,detail::timeout::sentinel()); return true; } - if (wait_duration.is_special()) + if (abs_time.is_special()) { return true; } @@ -370,7 +370,7 @@ namespace boost template bool timed_wait(unique_lock& m,boost::system_time const& abs_time,predicate_type pred) { - if (wait_duration.is_pos_infinity()) + if (abs_time.is_pos_infinity()) { wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); return true; @@ -384,7 +384,7 @@ namespace boost template bool timed_wait(unique_lock& m,boost::xtime const& abs_time,predicate_type pred) { - if (wait_duration.is_pos_infinity()) + if (abs_time.is_pos_infinity()) { wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); return true; From c9433c2a5b4e6b489c6502eff9924fe15a5b5e91 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Wed, 22 Apr 2015 22:49:26 +0200 Subject: [PATCH 03/23] rollback ref #11174 - boost::condition_variable::timed_wait with predicate unexpectedly wakes up while should wait infinite. --- .../boost/thread/win32/condition_variable.hpp | 55 ++----------------- 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 7ec96ae4..14c23ce0 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -327,30 +327,12 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool timed_wait(unique_lock& m,boost::system_time const& abs_time) { - if (abs_time.is_pos_infinity()) - { - wait(m); // or do_wait(m,detail::timeout::sentinel()); - return true; - } - if (abs_time.is_special()) - { - return true; - } - return do_wait(m,abs_time); + return do_wait(m,abs_time); } bool timed_wait(unique_lock& m,boost::xtime const& abs_time) { - if (abs_time.is_pos_infinity()) - { - wait(m); // or do_wait(m,detail::timeout::sentinel()); - return true; - } - if (abs_time.is_special()) - { - return true; - } - return do_wait(m,system_time(abs_time)); + return do_wait(m,system_time(abs_time)); } template bool timed_wait(unique_lock& m,duration_type const& wait_duration) @@ -370,44 +352,17 @@ namespace boost template bool timed_wait(unique_lock& m,boost::system_time const& abs_time,predicate_type pred) { - if (abs_time.is_pos_infinity()) - { - wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); - return true; - } - if (wait_duration.is_special()) - { - return true; - } - return do_wait(m,abs_time,pred); + return do_wait(m,abs_time,pred); } template bool timed_wait(unique_lock& m,boost::xtime const& abs_time,predicate_type pred) { - if (abs_time.is_pos_infinity()) - { - wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); - return true; - } - if (wait_duration.is_special()) - { - return true; - } - return do_wait(m,system_time(abs_time),pred); + return do_wait(m,system_time(abs_time),pred); } template bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) { - if (wait_duration.is_pos_infinity()) - { - wait(m, pred); // or do_wait(m,detail::timeout::sentinel()); - return true; - } - if (wait_duration.is_special()) - { - return true; - } - return do_wait(m,wait_duration.total_milliseconds(),pred); + return do_wait(m,wait_duration.total_milliseconds(),pred); } #endif #ifdef BOOST_THREAD_USES_CHRONO From 2ddf7aad0b7e037c379fc193ddc3be6ff90581d0 Mon Sep 17 00:00:00 2001 From: Zoey Greer Date: Wed, 22 Apr 2015 19:37:36 -0400 Subject: [PATCH 04/23] Remove unused parameter lk is unused in get_state, naming it causes build warnings --- include/boost/thread/future.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 28239c4a..a1a0d97f 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -407,7 +407,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) { From 385eefd3b3d29a52df89fd95bdc27101010dab69 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 25 Apr 2015 00:20:05 +0200 Subject: [PATCH 05/23] ref #11174 - boost::condition_variable::timed_wait with predicate unexpectedly wakes up while should wait infinite. --- .../boost/thread/win32/condition_variable.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 From e850218c49da259d349a8dad315ecae10c56f1a1 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 25 Apr 2015 00:20:53 +0200 Subject: [PATCH 06/23] ref #11174 - boost::condition_variable::timed_wait with predicate unexpectedly wakes up while should wait infinite. --- .../thread/pthread/condition_variable_fwd.hpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 From 348da6b7e471110209d88dead93ddfcce8a2064a Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 25 Apr 2015 10:11:01 +0200 Subject: [PATCH 07/23] fix memory leack in test. --- example/thread_group.cpp | 1 + 1 file changed, 1 insertion(+) 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; } { { From 1bd78bbeeae966c633d8b3db213bb795b0e7a322 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 25 Apr 2015 11:16:03 +0200 Subject: [PATCH 08/23] cleanup commented code. --- include/boost/thread/detail/thread.hpp | 1 - src/pthread/thread.cpp | 3 --- 2 files changed, 4 deletions(-) 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/src/pthread/thread.cpp b/src/pthread/thread.cpp index bbd25493..45d10e88 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -252,7 +252,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 +265,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 +272,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) { From 461bf803fcd99b7c082ff59d4808d61ed72c5e9c Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 25 Apr 2015 11:17:20 +0200 Subject: [PATCH 09/23] Avoid data race in std::cout. --- example/producer_consumer.cpp | 28 ++++++++++++++-------------- example/producer_consumer2.cpp | 28 ++++++++++++++-------------- example/recursive_mutex.cpp | 2 +- example/serial_executor.cpp | 14 ++++---------- 4 files changed, 33 insertions(+), 39 deletions(-) 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 ad25e822..e3c2c340 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) 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,13 +73,11 @@ 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); @@ -89,7 +85,6 @@ int test_executor_adaptor() boost::this_thread::sleep_for(boost::chrono::seconds(10)); } #endif - // std::cout << BOOST_CONTEXTOF << std::endl; } catch (std::exception& ex) { @@ -102,7 +97,6 @@ int test_executor_adaptor() return 2; } } - // std::cout << BOOST_CONTEXTOF << std::endl; return 0; } From 0218136ed7df26b66ec64cec1f7195b83e3f90db Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 25 Apr 2015 15:41:49 +0200 Subject: [PATCH 10/23] Try to see if share_from_this helps on the thread sanitize data race. --- src/pthread/thread.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 45d10e88..730a43a6 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) @@ -158,8 +160,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 From bce7eabba29a96c762e3a5e5c28cb6928fe706c6 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Thu, 30 Apr 2015 01:11:39 +0200 Subject: [PATCH 11/23] fix make_exceptional issue. --- example/make_future.cpp | 15 +++++++---- include/boost/thread/future.hpp | 46 ++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 17 deletions(-) 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/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 28239c4a..d972b644 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -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); @@ -483,6 +496,10 @@ namespace boost shared_state(): result() {} + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex), result() + {} + ~shared_state() {} @@ -624,6 +641,10 @@ namespace boost result(0) {} + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex), result(0) + {} + ~shared_state() { } @@ -687,6 +708,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 +1175,15 @@ 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_; + return future_ptr(new detail::shared_state(ex)); } void set_exceptional_if_invalid() { if (valid()) return; - promise p; - p.set_exception(future_uninitialized()); - future_ = p.get_future().future_; +// promise p; +// p.set_exception(future_uninitialized()); +// future_ = p.get_future().future_; + future_ = make_exceptional_future_ptr(exceptional_ptr(future_uninitialized())); } future_ptr future_; @@ -4092,12 +4116,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,6 +4137,10 @@ namespace detail { p.set_exception(boost::current_exception()); return BOOST_THREAD_MAKE_RV_REF(p.get_future()); } + template + BOOST_THREAD_FUTURE make_ready_future(exception_ptr ex) { + return make_exceptional_future(ex); + } template BOOST_THREAD_FUTURE make_exceptional_future_if_invalid(BOOST_THREAD_FWD_REF(BOOST_THREAD_FUTURE) fut) { From e598796eafc517031e478ae0178ef67615deea79 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 2 May 2015 16:29:06 +0200 Subject: [PATCH 12/23] Add assertion on future continuation parameter is ready. As noted in #11256, there some serious issues with the parameter passed and with lock on locked mutextes :(. --- example/executor.cpp | 9 +- test/Jamfile.v2 | 12 ++- .../futures/future/then_deferred_pass.cpp | 4 + .../futures/future/then_executor_pass.cpp | 3 + test/test_10963.cpp | 17 ++++ test/test_10964.cpp | 85 ++++++++++++++++++- 6 files changed, 123 insertions(+), 7 deletions(-) diff --git a/example/executor.cpp b/example/executor.cpp index 10c77a00..69de41f0 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(); } @@ -156,10 +158,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/test/Jamfile.v2 b/test/Jamfile.v2 index 22f52650..0c8fd430 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -947,11 +947,19 @@ 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-compile test_10963.cpp : : test_10963_c ] + #[ thread-run test_10964.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/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..0dbf4bb1 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(); } }; @@ -51,13 +64,23 @@ int main() f2.wait(); } std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + { + 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; + } +#if 0 + // @fixme this doesn't works. + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; { 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; @@ -71,6 +94,62 @@ int main() f.then( TestCallback()).unwrap().then(TestCallback()).get(); } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + { + auto f1 = boost::make_ready_future().then(TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + auto f3 = f1.then(TestCallback()); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + BOOST_STATIC_ASSERT(std::is_same > >::value); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + f3.wait(); + } + + + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + { + boost::basic_thread_pool executor; + + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + auto f1 = boost::make_ready_future().then(executor, TestCallback()); + //BOOST_STATIC_ASSERT(std::is_same > >::value); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + auto f3 = f1.then(executor, TestCallback()); + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + BOOST_STATIC_ASSERT(std::is_same > >::value); + f3.wait(); + } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + { + boost::basic_thread_pool executor; + + auto f1 = boost::make_ready_future().then(executor, TestCallback()); + 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); + auto f3 = f2.then(executor, TestCallback()); + BOOST_STATIC_ASSERT(std::is_same > >::value); + f3.wait(); + } + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + { + 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(); + } +#endif + std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + #endif return 0; } From ba2988a8f7920865e4c9c88925eb8a72a227a396 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 3 May 2015 10:42:42 +0200 Subject: [PATCH 13/23] Fixed issue with basic_thread_pool scoped threads. --- include/boost/thread/executors/basic_thread_pool.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/thread/executors/basic_thread_pool.hpp b/include/boost/thread/executors/basic_thread_pool.hpp index 64ba1e90..001a628f 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 @@ -30,15 +30,14 @@ namespace executors /// type-erasure to store the works to do typedef executors::work work; private: - /// the kind of stored threads are scoped threads to ensure that the threads are joined. + typedef thread thread_t; /// A move aware vector type - typedef scoped_thread<> thread_t; typedef csbl::vector thread_vector; - /// the thread safe work queue - concurrent::sync_queue work_queue; /// A move aware vector thread_vector threads; + /// the thread safe work queue + concurrent::sync_queue work_queue; public: /** @@ -222,7 +221,8 @@ namespace executors { // signal to all the worker threads that there will be no more submissions. close(); - // joins all the threads as the threads were scoped_threads + // joins all the threads before destroying the thread pool resources (e.g. the queue). + join(); } /** From 5205fa71bfc06a8eac22fc2a49357d1db1ef505f Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 3 May 2015 14:30:52 +0200 Subject: [PATCH 14/23] Fixed some missing lock.unlock(). --- include/boost/thread/future.hpp | 7 ++++++ test/Jamfile.v2 | 1 + test/test_10964.cpp | 12 ++++------ test/test_11256.cpp | 42 +++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 test/test_11256.cpp diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index d972b644..077e8fe8 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -4848,14 +4848,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) ))); @@ -4871,6 +4874,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) ))); @@ -4886,15 +4890,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) ); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0c8fd430..f5cbd4cc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -959,6 +959,7 @@ rule thread-compile ( sources : reqs * : name ) : #[ thread-compile test_10963.cpp : : test_10963_c ] #[ thread-run test_10964.cpp ] + [ thread-run test_11256.cpp ] ; diff --git a/test/test_10964.cpp b/test/test_10964.cpp index 0dbf4bb1..20658d69 100644 --- a/test/test_10964.cpp +++ b/test/test_10964.cpp @@ -94,15 +94,13 @@ int main() f.then( TestCallback()).unwrap().then(TestCallback()).get(); } +#endif std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; { auto f1 = boost::make_ready_future().then(TestCallback()); BOOST_STATIC_ASSERT(std::is_same > >::value); - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; auto f3 = f1.then(TestCallback()); - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; BOOST_STATIC_ASSERT(std::is_same > >::value); - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; f3.wait(); } @@ -110,16 +108,14 @@ int main() std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; { boost::basic_thread_pool executor; - - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; auto f1 = boost::make_ready_future().then(executor, TestCallback()); - //BOOST_STATIC_ASSERT(std::is_same > >::value); - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + BOOST_STATIC_ASSERT(std::is_same > >::value); auto f3 = f1.then(executor, TestCallback()); - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; BOOST_STATIC_ASSERT(std::is_same > >::value); f3.wait(); } +#if 0 + // @fixme this doesn't works. std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; { boost::basic_thread_pool executor; 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(); +} From b7b2a463cfebdaeb697fbb667858c5fd35998f14 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 3 May 2015 22:32:17 +0200 Subject: [PATCH 15/23] fix issue with unwrap shared state. --- include/boost/thread/future.hpp | 71 +++++++++++++++++++++++---------- test/Jamfile.v2 | 4 +- test/test_10964.cpp | 28 ++++++++----- 3 files changed, 70 insertions(+), 33 deletions(-) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 077e8fe8..ad23c1a0 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -5042,41 +5042,70 @@ 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, shared_ptr that) { - boost::unique_lock lk(parent.future_->mutex); - parent.future_->set_continuation_ptr(continuation, lk); + if (! unwrapped.valid() ) + { + 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 { + 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, shared_ptr that) + { + if (! unwrapped.valid() ) + { + 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 { + unwrapped.wait(); + 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/test/Jamfile.v2 b/test/Jamfile.v2 index f5cbd4cc..6f2f2c64 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -957,9 +957,7 @@ rule thread-compile ( sources : reqs * : name ) explicit ts_ ; test-suite ts_ : - #[ thread-compile test_10963.cpp : : test_10963_c ] - #[ thread-run test_10964.cpp ] - [ thread-run test_11256.cpp ] + #[ thread-run test_11256.cpp ] ; diff --git a/test/test_10964.cpp b/test/test_10964.cpp index 20658d69..6cd26759 100644 --- a/test/test_10964.cpp +++ b/test/test_10964.cpp @@ -48,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; { @@ -56,14 +58,21 @@ 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()); @@ -71,9 +80,8 @@ int main() boost::future f2 = f1.get(); std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; } -#if 0 - // @fixme this doesn't works. 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); @@ -84,18 +92,20 @@ int main() 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(); } -#endif 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); @@ -106,6 +116,7 @@ int main() 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()); @@ -114,17 +125,16 @@ int main() BOOST_STATIC_ASSERT(std::is_same > >::value); f3.wait(); } -#if 0 - // @fixme this doesn't works. std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) { - boost::basic_thread_pool executor; + 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__ << "]" << std::endl; + std::cout << __FILE__ << "[" << __LINE__ << "] " << int(f1.valid()) << std::endl; auto f2 = f1.unwrap(); - std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + std::cout << __FILE__ << "[" << __LINE__ << "] " << int(f2.valid()) << std::endl; BOOST_STATIC_ASSERT(std::is_same >::value); auto f3 = f2.then(executor, TestCallback()); @@ -132,6 +142,7 @@ int main() f3.wait(); } std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; + for (int i=0; i< number_of_tests; i++) { boost::basic_thread_pool executor; @@ -143,7 +154,6 @@ int main() BOOST_STATIC_ASSERT(std::is_same > >::value); f3.wait(); } -#endif std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl; #endif From 71d9a0a12010583a59548dc32bb1cb84f16a5d56 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 3 May 2015 22:52:52 +0200 Subject: [PATCH 16/23] fix issue with unwrap shared state. Take care of exceptions on the unwrapped future. --- include/boost/thread/future.hpp | 50 ++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index ad23c1a0..0919c7c8 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -5053,17 +5053,25 @@ namespace detail { if (! unwrapped.valid() ) { - 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); + if (wrapped.has_exception()) { + this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); } else { - this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); + 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 { - this->mark_finished_with_result_internal(unwrapped.get(), lk); + if (unwrapped.has_exception()) { + this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); + } else { + this->mark_finished_with_result_internal(unwrapped.get(), lk); + } } } }; @@ -5082,18 +5090,26 @@ namespace detail { if (! unwrapped.valid() ) { - 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); + if (wrapped.has_exception()) { + this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); } else { - this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); + 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 { - unwrapped.wait(); - this->mark_finished_with_result_internal(lk); + if (unwrapped.has_exception()) { + this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); + } else { + unwrapped.wait(); + this->mark_finished_with_result_internal(lk); + } } } }; From 5488482a444c9ce45a74c3bd0c0a259426abc981 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Mon, 4 May 2015 23:06:39 +0200 Subject: [PATCH 17/23] simplify launch_continuation interface. --- include/boost/thread/future.hpp | 64 +++++++++++++++++---------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 0919c7c8..613d5d74 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() { } @@ -234,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(); } } } @@ -4209,8 +4208,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_) { @@ -4240,8 +4240,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_) { @@ -4291,9 +4292,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); } @@ -4330,9 +4330,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); } @@ -4373,8 +4372,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_) { @@ -4403,8 +4403,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_) { @@ -4441,9 +4442,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); } @@ -4479,9 +4479,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); } @@ -4521,7 +4520,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); @@ -4559,7 +4559,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); @@ -4598,7 +4599,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); @@ -4634,7 +4636,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); @@ -5049,8 +5052,9 @@ namespace detail : wrapped(boost::move(f)) { } - void launch_continuation(boost::unique_lock& lk, shared_ptr that) + void launch_continuation() { + boost::unique_lock lk(this->mutex); if (! unwrapped.valid() ) { if (wrapped.has_exception()) { @@ -5086,8 +5090,9 @@ namespace detail : wrapped(boost::move(f)) { } - void launch_continuation(boost::unique_lock& lk, shared_ptr that) + void launch_continuation() { + boost::unique_lock lk(this->mutex); if (! unwrapped.valid() ) { if (wrapped.has_exception()) { @@ -5107,7 +5112,6 @@ namespace detail if (unwrapped.has_exception()) { this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); } else { - unwrapped.wait(); this->mark_finished_with_result_internal(lk); } } From c0afe2d8730c4615963a5bf949ac97cb0137ca87 Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Wed, 6 May 2015 02:11:59 +1200 Subject: [PATCH 18/23] Tests: correct #error message in recursive_mutex/native_handle_pass --- .../mutual_exclusion/recursive_mutex/native_handle_pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); From 87615d54dd031f9cb83926805745d503d2d46c30 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Wed, 6 May 2015 09:48:54 +0200 Subject: [PATCH 19/23] cleanup unused function set_exceptional_if_invalid. --- include/boost/thread/future.hpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 613d5d74..7174303c 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -1177,14 +1177,6 @@ namespace boost return future_ptr(new detail::shared_state(ex)); } - void set_exceptional_if_invalid() { - if (valid()) return; -// promise p; -// p.set_exception(future_uninitialized()); -// future_ = p.get_future().future_; - future_ = make_exceptional_future_ptr(exceptional_ptr(future_uninitialized())); - } - future_ptr future_; basic_future(future_ptr a_future): @@ -4141,17 +4133,6 @@ namespace detail { return make_exceptional_future(ex); } - 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; - } - #if 0 template make_future(CLOSURE closure) -> BOOST_THREAD_FUTURE { From 58e8addad681fa0a4ba0eee843d4eda7a843d5f7 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Wed, 6 May 2015 13:51:21 +0200 Subject: [PATCH 20/23] Try to get rid of bad link issue while defining global new. --- test/threads/thread/constr/FArgs_pass.cpp | 8 ++++---- test/threads/thread/constr/lambda_pass.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) 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); From 3dcd875944fa4b3b2a588cac6edc81ac5ecfdf92 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 12 May 2015 18:51:03 +0100 Subject: [PATCH 21/23] Link to archived copy of article. The original is no longer available. Fixes: https://svn.boost.org/trac/boost/ticket/11185 --- doc/sync_tutorial.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From aafd5ca7265e9edea1f100df88eb90c7653a70fc Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Fri, 15 May 2015 15:05:09 +0200 Subject: [PATCH 22/23] applie patch for #11266. --- include/boost/thread/future.hpp | 6 +++--- test/Jamfile.v2 | 1 + test/test_11266.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 test/test_11266.cpp diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 7174303c..6825c76f 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -2882,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 @@ -3113,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 @@ -3436,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()); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6f2f2c64..88ab9cb7 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 ] ; 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 +} From 4d45da6c06970b54387ee040e20a8a88c84c50c0 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Mon, 18 May 2015 21:26:46 +0200 Subject: [PATCH 23/23] Apply patch #11302. --- src/pthread/once.cpp | 4 +++- src/pthread/thread.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) 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 730a43a6..aa29615d 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -126,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); }