diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 4c250598..a05a735c 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -47,6 +47,7 @@ project boost/thread -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag @$(__name__).tag gcc:-Wno-long-long + BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED BOOST_SYSTEM_NO_DEPRECATED /boost/system//boost_system #-pedantic -ansi -std=gnu++0x -Wextra -fpermissive @@ -98,6 +99,7 @@ project boost/thread #shared:BOOST_THREAD_DYN_LINK=1 static:BOOST_THREAD_BUILD_LIB=1 shared:BOOST_THREAD_BUILD_DLL=1 + BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED BOOST_SYSTEM_NO_DEPRECATED /boost/system//boost_system ; diff --git a/doc/thread_ref.qbk b/doc/thread_ref.qbk index a19ed858..91d49535 100644 --- a/doc/thread_ref.qbk +++ b/doc/thread_ref.qbk @@ -391,7 +391,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o void swap(thread& x) noexcept; class id; - class attributes; + class attributes; // EXTENSION id get_id() const noexcept; @@ -471,7 +471,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o [[Effects:] [Transfers ownership of the thread managed by `other` (if any) to `*this`. Version 2: If there was a thread previously associated with -`*this` then that thread is detached, version 3: If the thread is joinable calls to std::terminate.]] +`*this` then that thread is detached, Version 3: If the thread is joinable calls to std::terminate.]] [[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]] @@ -628,7 +628,7 @@ are copied into internal storage for access by the new thread.]]] [variablelist -[[Effects:] [Version 1: If `*this` has an associated thread of execution, calls __detach__, Version 2: If the thread is joinable calls to std::terminate. Destroys `*this`.]] +[[Effects:] [Version 2: If `*this` has an associated thread of execution, calls __detach__, Version 3: If the thread is joinable calls to std::terminate. Destroys `*this`.]] [[Throws:] [Nothing.]] @@ -688,10 +688,12 @@ are copied into internal storage for access by the new thread.]]] [*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id(). +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. + + [/ [*no_such_process]: if the thread is not valid. -[*invalid_argument]: if the thread is not joinable. ] ]] @@ -711,7 +713,7 @@ are copied into internal storage for access by the new thread.]]] [variablelist -[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]] +[[Preconditions:] [the thread is joinable.]] [[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `wait_until` has been reach or the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]] @@ -729,10 +731,11 @@ unchanged.]] [*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id(). +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. + + [/ [*no_such_process]: if the thread is not valid. - -[*invalid_argument]: if the thread is not joinable. ] ]] @@ -750,7 +753,7 @@ unchanged.]] [variablelist -[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]] +[[Preconditions:] [the thread is joinable.]] [[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]] @@ -768,10 +771,11 @@ unchanged.]] [*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id(). +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. + + [/ [*no_such_process]: if the thread is not valid. - -[*invalid_argument]: if the thread is not joinable. ] ]] @@ -789,7 +793,7 @@ unchanged.]] [variablelist -[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]] +[[Preconditions:] [the thread is joinable.]] [[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `abs_time` has been reach. If `*this` doesn't refer to a thread of execution, returns immediately.]] @@ -807,10 +811,12 @@ unchanged.]] [*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id(). +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. + + [/ [*no_such_process]: if the thread is not valid. -[*invalid_argument]: if the thread is not joinable. ] ]] @@ -825,7 +831,7 @@ unchanged.]] [section:detach Member function `detach()`] - void detach() noexcept; + void detach(); [variablelist @@ -835,7 +841,15 @@ unchanged.]] [[Postconditions:] [`*this` no longer refers to any thread of execution.]] -[[Throws:] [Nothing]] +[[Throws:] [`system_error`]] + +[[Error Conditions:] [ + +[*no_such_process]: if the thread is not valid. + +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. + +]] ] diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index 7200e20e..5ec3e7c1 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -12,27 +12,25 @@ #include // This compiler doesn't support Boost.Chrono -#if defined __IBMCPP__ && (__IBMCPP__ < 1100) -#if ! defined BOOST_THREAD_DONT_USE_CHRONO +#if defined __IBMCPP__ && (__IBMCPP__ < 1100) && ! defined BOOST_THREAD_DONT_USE_CHRONO #define BOOST_THREAD_DONT_USE_CHRONO #endif -#endif // This compiler doesn't support Boost.Move -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) && ! defined BOOST_THREAD_DONT_USE_MOVE #define BOOST_THREAD_DONT_USE_MOVE #endif // This compiler doesn't support Boost.Container Allocators files -#if defined __SUNPRO_CC +#if defined __SUNPRO_CC && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #endif -#if defined _WIN32_WCE && _WIN32_WCE==0x501 +#if defined _WIN32_WCE && _WIN32_WCE==0x501 && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID +#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID && ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #endif @@ -46,12 +44,12 @@ #endif // Uses Boost.System by default if not stated the opposite defining BOOST_THREAD_DONT_USE_SYSTEM -#if ! defined BOOST_THREAD_DONT_USE_SYSTEM +#if ! defined BOOST_THREAD_DONT_USE_SYSTEM && ! defined BOOST_THREAD_USES_SYSTEM #define BOOST_THREAD_USES_SYSTEM #endif // Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO or BOOST_THREAD_DONT_USE_SYSTEM -#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_DONT_USE_SYSTEM +#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_DONT_USE_SYSTEM && ! defined BOOST_THREAD_USES_CHRONO #define BOOST_THREAD_USES_CHRONO #endif @@ -63,15 +61,8 @@ #endif -// Uses Boost.Move by default if not stated the opposite defining BOOST_THREAD_DONT_USE_MOVE -#if ! defined BOOST_THREAD_DONT_USE_MOVE -#if ! defined BOOST_THREAD_USES_MOVE -//#define BOOST_THREAD_USES_MOVE -#endif -#endif - #if BOOST_THREAD_VERSION==2 -#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY +#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY && ! defined BOOST_THREAD_PROMISE_LAZY #define BOOST_THREAD_PROMISE_LAZY #endif #if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 @@ -80,49 +71,59 @@ #endif #if BOOST_THREAD_VERSION==3 -#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 +#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 \ + && ! defined BOOST_THREAD_PROVIDES_ONCE_CXX11 #define BOOST_THREAD_PROVIDES_ONCE_CXX11 #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE \ + && ! defined BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_PROVIDES_FUTURE #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS \ + && ! defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS +#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS \ + && ! defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION +#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION \ + && ! defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN +#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN \ + && ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #endif -#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 \ + && ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_ #define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 #endif -#if ! defined BOOST_THREAD_DONT_USE_MOVE -#if ! defined BOOST_THREAD_USES_MOVE +#if ! defined BOOST_THREAD_DONT_USE_MOVE \ + && ! defined BOOST_THREAD_USES_MOVE #define BOOST_THREAD_USES_MOVE #endif -#endif #endif // BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS -#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS +#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \ +&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #endif // BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52 // BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55 -#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 \ +&& ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 #define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 #endif @@ -137,7 +138,7 @@ // provided for backwards compatibility, since this // macro was used for several releases by mistake. -#if defined(BOOST_THREAD_DYN_DLL) +#if defined(BOOST_THREAD_DYN_DLL) && ! defined BOOST_THREAD_DYN_LINK # define BOOST_THREAD_DYN_LINK #endif diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 712951b0..2590f45c 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -23,6 +23,8 @@ #include #include #include +//#include +//#include #include #include #include @@ -69,10 +71,13 @@ namespace boost f(f_) {} #endif + //thread_data() {} + void run() { f(); } + private: F f; }; @@ -406,7 +411,7 @@ namespace boost return timed_join(get_system_time()+rel_time); } - void detach() BOOST_NOEXCEPT; + void detach(); static unsigned hardware_concurrency() BOOST_NOEXCEPT; diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index 4f4bd881..dbb38926 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -229,8 +229,11 @@ namespace boost unique_lock& lock, struct timespec const &timeout); }; + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); } + #include #endif diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index aa84c568..db4e09f5 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -8,18 +8,25 @@ #include #include +#include +#include +#include + #include #include -#include #include -#include #include -#include -#include -#include #ifdef BOOST_THREAD_USES_CHRONO #include #endif + +#include +#include +#include + +#include +#include + #include namespace boost @@ -104,19 +111,28 @@ namespace boost bool interrupt_requested; pthread_mutex_t* cond_mutex; pthread_cond_t* current_cond; + typedef std::vector + //, hidden_allocator > + > notify_list_t; + notify_list_t notify; thread_data_base(): done(false),join_started(false),joined(false), thread_exit_callbacks(0), interrupt_enabled(true), interrupt_requested(false), - current_cond(0) + current_cond(0), + notify() {} virtual ~thread_data_base(); typedef pthread_t native_handle_type; virtual void run()=0; + void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + { + notify.push_back(std::pair(cv, m)); + } }; BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 63f830b1..f438dba9 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -6,23 +6,27 @@ // (C) Copyright 2007-8 Anthony Williams // (C) Copyright 2011-2012 Vicente J. Botet Escriba -#include #include -#include -#include -#include -#include #include -#include +#include #include +#include #include -#include +#include +#include + +#include #include + #ifdef BOOST_THREAD_USES_CHRONO #include #include #endif +#include +#include +#include + #include namespace boost @@ -510,6 +514,7 @@ namespace boost #endif }; + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); } #include diff --git a/include/boost/thread/win32/thread_data.hpp b/include/boost/thread/win32/thread_data.hpp index 397ec143..18fd7cbb 100644 --- a/include/boost/thread/win32/thread_data.hpp +++ b/include/boost/thread/win32/thread_data.hpp @@ -7,18 +7,26 @@ // (C) Copyright 2011-2012 Vicente J. Botet Escriba #include -#include #include #include #include -#include + +#include #ifdef BOOST_THREAD_USES_CHRONO #include #endif + +#include +#include +#include + #include namespace boost { + class condition_variable; + class mutex; + class thread_attributes { public: thread_attributes() BOOST_NOEXCEPT { @@ -76,7 +84,7 @@ namespace boost void intrusive_ptr_add_ref(thread_data_base * p); void intrusive_ptr_release(thread_data_base * p); - struct BOOST_SYMBOL_VISIBLE thread_data_base + struct BOOST_THREAD_DECL thread_data_base { long count; detail::win32::handle_manager thread_handle; @@ -85,16 +93,21 @@ namespace boost std::map tss_data; bool interruption_enabled; unsigned id; + typedef std::vector + //, hidden_allocator > + > notify_list_t; + notify_list_t notify; + thread_data_base(): count(0),thread_handle(detail::win32::invalid_handle_value), interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), thread_exit_callbacks(0),tss_data(), interruption_enabled(true), - id(0) - {} - virtual ~thread_data_base() + id(0), + notify() {} + virtual ~thread_data_base(); friend void intrusive_ptr_add_ref(thread_data_base * p) { @@ -117,6 +130,12 @@ namespace boost typedef detail::win32::handle native_handle_type; virtual void run()=0; + + void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + { + notify.push_back(std::pair(cv, m)); + } + }; typedef boost::intrusive_ptr thread_data_ptr; diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index e76cdf19..d5140957 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -10,11 +10,12 @@ #include #include -#include +#include #include #include #include #include + #ifdef __GLIBC__ #include #elif defined(__APPLE__) || defined(__FreeBSD__) @@ -31,7 +32,16 @@ namespace boost namespace detail { thread_data_base::~thread_data_base() - {} + { + { + for (notify_list_t::iterator i = notify.begin(), e = notify.end(); + i != e; ++i) + { + i->second->unlock(); + i->first->notify_all(); + } + } + } struct thread_exit_callback_node { @@ -175,6 +185,8 @@ namespace boost void run() {} + void notify_all_at_thread_exit(condition_variable*, mutex*) + {} private: externally_launched_thread(externally_launched_thread&); @@ -304,6 +316,12 @@ namespace boost thread_info.reset(); } } + else + { +#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); +#endif + } } bool thread::do_try_join_until(struct timespec const &timeout) @@ -353,8 +371,14 @@ namespace boost { thread_info.reset(); } + return true; + } + else + { +#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); +#endif } - return true; } bool thread::joinable() const BOOST_NOEXCEPT @@ -363,7 +387,7 @@ namespace boost } - void thread::detach() BOOST_NOEXCEPT + void thread::detach() { detail::thread_data_ptr local_thread_info; thread_info.swap(local_thread_info); @@ -677,6 +701,15 @@ namespace boost } } } + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) + { + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); + } + } + } diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index 9177786f..1c16b060 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -13,22 +13,39 @@ #endif #include +#include +#include +#include +#include + +#include +#include +#include + +#include #include #ifndef UNDER_CE #include #endif #include -#include -#include -#include -#include -#include -#include #include -#include namespace boost { + namespace detail + { + thread_data_base::~thread_data_base() + { + { + for (notify_list_t::iterator i = notify.begin(), e = notify.end(); + i != e; ++i) + { + i->second->unlock(); + i->first->notify_all(); + } + } + } + } namespace { #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 @@ -240,6 +257,9 @@ namespace boost void run() {} + void notify_all_at_thread_exit(condition_variable*, mutex*) + {} + private: externally_launched_thread(externally_launched_thread&); void operator=(externally_launched_thread&); @@ -303,6 +323,12 @@ namespace boost this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel()); release_handle(); } + else + { +#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); +#endif + } } bool thread::timed_join(boost::system_time const& wait_until) @@ -324,11 +350,17 @@ namespace boost return false; } release_handle(); + return true; + } + else + { +#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); +#endif } - return true; } - void thread::detach() BOOST_NOEXCEPT + void thread::detach() { release_handle(); } @@ -682,6 +714,14 @@ namespace boost boost::run_thread_exit_callbacks(); } + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); + } + } } diff --git a/src/win32/tss_dll.cpp b/src/win32/tss_dll.cpp index 9699a12b..2dc019f4 100644 --- a/src/win32/tss_dll.cpp +++ b/src/win32/tss_dll.cpp @@ -5,6 +5,7 @@ #include + #if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL) #include diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 352c9065..490eb5f9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -225,6 +225,7 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/conditions/condition_variable_any/wait_until_pass.cpp : condition_variable_any__wait_until_p ] [ thread-run2 ./sync/conditions/condition_variable_any/wait_until_pred_pass.cpp : condition_variable_any__wait_until_pred_p ] [ thread-run2 ./sync/conditions/cv_status/cv_status_pass.cpp : cv_status__cv_status_p ] + [ thread-run2 ./sync/conditions/notify_all_at_thread_exit_pass.cpp : notify_all_at_thread_exit_p ] ; explicit ts_async ; @@ -469,6 +470,8 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./threads/thread/members/detach_pass.cpp : thread__detach_p ] [ thread-run2 ./threads/thread/members/get_id_pass.cpp : thread__get_id_p ] [ thread-run2 ./threads/thread/members/join_pass.cpp : thread__join_p ] + [ thread-run2 ./threads/thread/members/try_join_until_pass.cpp : thread__join_until_p ] + [ thread-run2 ./threads/thread/members/try_join_for_pass.cpp : thread__join_for_p ] [ thread-run2 ./threads/thread/members/joinable_pass.cpp : thread__joinable_p ] [ thread-run2 ./threads/thread/members/native_handle_pass.cpp : thread__native_handle_p ] [ thread-run2 ./threads/thread/members/swap_pass.cpp : thread__swap_p ] diff --git a/test/sync/conditions/notify_all_at_thread_exit_pass.cpp b/test/sync/conditions/notify_all_at_thread_exit_pass.cpp new file mode 100644 index 00000000..d6eecbd9 --- /dev/null +++ b/test/sync/conditions/notify_all_at_thread_exit_pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// 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) + +// + +// void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); + +#define BOOST_THREAD_USES_MOVE +#define BOOST_THREAD_VESRION 3 + +#include +#include +#include +#include +#include +#include + +boost::condition_variable cv; +boost::mutex mut; + +typedef boost::chrono::milliseconds ms; +typedef boost::chrono::high_resolution_clock Clock; + +void func() +{ + boost::unique_lock < boost::mutex > lk(mut); + boost::notify_all_at_thread_exit(cv, boost::move(lk)); + boost::this_thread::sleep_for(ms(300)); +} + +int main() +{ + boost::unique_lock < boost::mutex > lk(mut); + boost::thread(func).detach(); + Clock::time_point t0 = Clock::now(); + cv.wait(lk); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 > ms(250)); + return boost::report_errors(); +} + diff --git a/test/threads/thread/assign/move_pass.cpp b/test/threads/thread/assign/move_pass.cpp index 2163c543..7d2dfd8a 100644 --- a/test/threads/thread/assign/move_pass.cpp +++ b/test/threads/thread/assign/move_pass.cpp @@ -89,14 +89,14 @@ int main() t1.join(); BOOST_TEST(G::op_run); } -// BOOST_TEST(G::n_alive == 0); -// { -// boost::thread t0(G(), 5, 5.5); -// boost::thread::id id = t0.get_id(); -// boost::thread t1; -// t0 = boost::move(t1); -// BOOST_TEST(false); -// } + BOOST_TEST(G::n_alive == 0); + { + boost::thread t0(G(), 5, 5.5); + boost::thread::id id = t0.get_id(); + boost::thread t1; + t0 = boost::move(t1); + BOOST_TEST(false); + } return boost::report_errors(); } diff --git a/test/threads/thread/members/join_pass.cpp b/test/threads/thread/members/join_pass.cpp index 35248d9e..d5a4fa1b 100644 --- a/test/threads/thread/members/join_pass.cpp +++ b/test/threads/thread/members/join_pass.cpp @@ -16,7 +16,6 @@ // class thread // void join(); - #define BOOST_THREAD_VESRION 3 #include #include @@ -53,7 +52,7 @@ public: void operator()() { BOOST_TEST(alive_ == 1); - BOOST_TEST(n_alive == 1); + //BOOST_TEST(n_alive == 1); op_run = true; } }; @@ -68,8 +67,6 @@ void resource_deadlock_would_occur_tester() try { boost::unique_lock lk(resource_deadlock_would_occur_mtx); - - resource_deadlock_would_occur_th->join(); BOOST_TEST(false); } @@ -83,28 +80,6 @@ void resource_deadlock_would_occur_tester() } } -void throws_thread_resource_error_tester() -{ - { - try { - boost::throw_exception( - boost::thread_resource_error( - boost::system::errc::resource_deadlock_would_occur, - "boost thread: trying joining itself" - )); - BOOST_TEST(false); - } - catch (boost::system::system_error& e) - { - BOOST_TEST(e.code().value() == boost::system::errc::resource_deadlock_would_occur); - } - catch (...) - { - BOOST_TEST(false&&"exception thrown"); - } - } -} - int main() { { @@ -114,10 +89,6 @@ int main() BOOST_TEST(!t0.joinable()); } - { - boost::thread t0( throws_thread_resource_error_tester ); - t0.join(); - } { boost::unique_lock lk(resource_deadlock_would_occur_mtx); boost::thread t0( resource_deadlock_would_occur_tester ); @@ -130,35 +101,34 @@ int main() BOOST_TEST(!t0.joinable()); } -// { -// boost::thread t0( (G())); -// t0.detach(); -// try -// { -// t0.join(); -// BOOST_TEST(false); -// } -// catch (boost::system::system_error& e) -// { -// BOOST_TEST(e.code().value() == boost::system::errc::no_such_process); -// } -// } -// { -// boost::thread t0( (G())); -// BOOST_TEST(t0.joinable()); -// t0.join(); -// BOOST_TEST(!t0.joinable()); -// try -// { -// t0.join(); -// BOOST_TEST(false); -// } -// catch (boost::system::system_error& e) -// { -// BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); -// } -// -// } + { + boost::thread t0( (G())); + t0.detach(); + try + { + t0.join(); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + } + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + t0.join(); + try + { + t0.join(); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + + } return boost::report_errors(); } diff --git a/test/threads/thread/members/try_join_for_pass.cpp b/test/threads/thread/members/try_join_for_pass.cpp new file mode 100644 index 00000000..772b5b28 --- /dev/null +++ b/test/threads/thread/members/try_join_for_pass.cpp @@ -0,0 +1,161 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// 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) + +// + +// class thread + +// template +// bool try_join_for(const chrono::duration& rel_time); + +#define BOOST_THREAD_VESRION 3 +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined BOOST_THREAD_USES_CHRONO + +class G +{ + int alive_; +public: + static bool op_run; + + G() : + alive_(1) + { + } + G(const G& g) : + alive_(g.alive_) + { + } + ~G() + { + alive_ = 0; + } + + void operator()() + { + BOOST_TEST(alive_ == 1); + op_run = true; + } +}; + +bool G::op_run = false; + +boost::thread* resource_deadlock_would_occur_th=0; +boost::mutex resource_deadlock_would_occur_mtx; +void resource_deadlock_would_occur_tester() +{ + try + { + boost::unique_lock lk(resource_deadlock_would_occur_mtx); + resource_deadlock_would_occur_th->try_join_for(boost::chrono::milliseconds(50)); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::resource_deadlock_would_occur); + } + catch (...) + { + BOOST_TEST(false&&"exception thrown"); + } +} + +void th_100_ms() +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); +} + +int main() +{ + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + BOOST_TEST(t0.try_join_for(boost::chrono::milliseconds(50))); + BOOST_TEST(!t0.joinable()); + } + { + boost::thread t0( (th_100_ms)); + BOOST_TEST(!t0.try_join_for(boost::chrono::milliseconds(50))); + t0.join(); + } + + { + boost::unique_lock lk(resource_deadlock_would_occur_mtx); + boost::thread t0( resource_deadlock_would_occur_tester ); + resource_deadlock_would_occur_th = &t0; + BOOST_TEST(t0.joinable()); + lk.unlock(); + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); + boost::unique_lock lk2(resource_deadlock_would_occur_mtx); + t0.join(); + BOOST_TEST(!t0.joinable()); + } + + { + boost::thread t0( (G())); + t0.detach(); + try + { + t0.try_join_for(boost::chrono::milliseconds(50)); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + } + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + t0.join(); + try + { + t0.try_join_for(boost::chrono::milliseconds(50)); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + + } + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + t0.try_join_for(boost::chrono::milliseconds(50)); + try + { + t0.join(); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + + } + + return boost::report_errors(); +} + +#else +#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif diff --git a/test/threads/thread/members/try_join_until_pass.cpp b/test/threads/thread/members/try_join_until_pass.cpp new file mode 100644 index 00000000..c1324ac3 --- /dev/null +++ b/test/threads/thread/members/try_join_until_pass.cpp @@ -0,0 +1,162 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// 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) + +// + +// class thread + +// template +// bool try_join_until(const chrono::time_point& t); + +#define BOOST_THREAD_VESRION 3 +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined BOOST_THREAD_USES_CHRONO + +class G +{ + int alive_; +public: + static bool op_run; + + G() : + alive_(1) + { + } + G(const G& g) : + alive_(g.alive_) + { + } + ~G() + { + alive_ = 0; + } + + void operator()() + { + BOOST_TEST(alive_ == 1); + op_run = true; + } +}; + +bool G::op_run = false; + +boost::thread* resource_deadlock_would_occur_th=0; +boost::mutex resource_deadlock_would_occur_mtx; +void resource_deadlock_would_occur_tester() +{ + try + { + boost::unique_lock lk(resource_deadlock_would_occur_mtx); + resource_deadlock_would_occur_th->try_join_until(boost::chrono::steady_clock::now()+boost::chrono::milliseconds(50)); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::resource_deadlock_would_occur); + } + catch (...) + { + BOOST_TEST(false&&"exception thrown"); + } +} + +void th_100_ms() +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); +} + + +int main() +{ + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + t0.try_join_until(boost::chrono::steady_clock::now()+boost::chrono::milliseconds(50)); + BOOST_TEST(!t0.joinable()); + } + { + boost::thread t0( (th_100_ms)); + BOOST_TEST(!t0.try_join_until(boost::chrono::steady_clock::now()+boost::chrono::milliseconds(50))); + t0.join(); + } + + { + boost::unique_lock lk(resource_deadlock_would_occur_mtx); + boost::thread t0( resource_deadlock_would_occur_tester ); + resource_deadlock_would_occur_th = &t0; + BOOST_TEST(t0.joinable()); + lk.unlock(); + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); + boost::unique_lock lk2(resource_deadlock_would_occur_mtx); + t0.join(); + BOOST_TEST(!t0.joinable()); + } + + { + boost::thread t0( (G())); + t0.detach(); + try + { + t0.try_join_until(boost::chrono::steady_clock::now()+boost::chrono::milliseconds(50)); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + } + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + t0.join(); + try + { + t0.try_join_until(boost::chrono::steady_clock::now()+boost::chrono::milliseconds(50)); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + + } + { + boost::thread t0( (G())); + BOOST_TEST(t0.joinable()); + t0.try_join_until(boost::chrono::steady_clock::now()+boost::chrono::milliseconds(50)); + try + { + t0.join(); + BOOST_TEST(false); + } + catch (boost::system::system_error& e) + { + BOOST_TEST(e.code().value() == boost::system::errc::invalid_argument); + } + + } + + return boost::report_errors(); +} + +#else +#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif