From a3098b5dfdab7549bfc9c7f7529495a56ab78b88 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 20 Oct 2012 14:05:32 +0000 Subject: [PATCH] Thread: Added BOOST_THREAD_DONT_PROVIDE_THREAD_EQ, BOOST_THREAD_DONT_USE_DATETIME and forbid their use when defined + Added BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION and future<>::then + Go towards don't throwing from the cpp files (refactor start_thread, join + Added #define BOOST_THREAD_VERSION 2 for the tests that runs only with version 2 [SVN r81023] --- doc/changes.qbk | 13 +- doc/future_ref.qbk | 65 ++++- doc/futures.qbk | 59 ++++ example/future_then.cpp | 37 +++ include/boost/thread/detail/config.hpp | 51 +++- include/boost/thread/detail/thread.hpp | 41 ++- include/boost/thread/future.hpp | 266 ++++++++++++++---- include/boost/thread/locks.hpp | 11 +- .../thread/pthread/condition_variable.hpp | 3 +- .../thread/pthread/condition_variable_fwd.hpp | 2 + include/boost/thread/pthread/mutex.hpp | 6 +- .../boost/thread/pthread/recursive_mutex.hpp | 5 +- include/boost/thread/pthread/shared_mutex.hpp | 8 +- include/boost/thread/pthread/thread_data.hpp | 2 + src/pthread/thread.cpp | 4 +- src/win32/thread.cpp | 54 ++-- test/Jamfile.v2 | 1 + test/test_2309.cpp | 2 + test/test_3628.cpp | 2 + test/test_4882.cpp | 2 + test/test_5542_1.cpp | 2 + test/test_5542_3.cpp | 2 + test/test_6130.cpp | 2 + test/test_lock_concept.cpp | 2 + test/test_xtime.cpp | 2 + 25 files changed, 509 insertions(+), 135 deletions(-) create mode 100644 example/future_then.cpp diff --git a/doc/changes.qbk b/doc/changes.qbk index db27edd3..28157cb3 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -73,11 +73,12 @@ Fixed Bugs: * [@http://svn.boost.org/trac/boost/ticket/2797 #2797] Two problems with thread_specific_ptr. * [@http://svn.boost.org/trac/boost/ticket/5274 #5274] failed to compile future.hpp with stlport 5.1.5 under msvc8.1, because of undefined class. * [@http://svn.boost.org/trac/boost/ticket/5431 #5431] compile error in Windows CE 6.0(interlocked). -* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms. -[/* [@http://svn.boost.org/trac/boost/ticket/5696 #5696] win32 detail::set_tss_data does nothing when tss_cleanup_function is NULL]. +[/* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms.] +* [@http://svn.boost.org/trac/boost/ticket/5696 #5696] win32 detail::set_tss_data does nothing when tss_cleanup_function is NULL. +* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel C++ Compiler XE 12.1.5.344 Build 20120612 * [@http://svn.boost.org/trac/boost/ticket/7045 #7045] Thread library does not automatically compile date_time. * [@http://svn.boost.org/trac/boost/ticket/7173 #7173] wrong function name interrupt_point(). -* [@http://svn.boost.org/trac/boost/ticket/7200 #7200] Unable to build boost.thread modularized. +* [@http://svn.boost.org/trac/boost/ticket/7200 #7200] Unable to build boost.thread modularized. * [@http://svn.boost.org/trac/boost/ticket/7220 #7220] gcc 4.6.2 warns about inline+dllimport functions. * [@http://svn.boost.org/trac/boost/ticket/7238 #7238] this_thread::sleep_for() does not respond to interrupt(). * [@http://svn.boost.org/trac/boost/ticket/7245 #7245] Minor typos on documentation related to version 3. @@ -87,6 +88,12 @@ Fixed Bugs: * [@http://svn.boost.org/trac/boost/ticket/7336 #7336] BOOST_THREAD_DONT_USE_SYSTEM doesn't work. * [@http://svn.boost.org/trac/boost/ticket/7329 #7349] packaged_task holds reference to temporary. * [@http://svn.boost.org/trac/boost/ticket/7350 #7350] allocator_destructor does not destroy object +* [@http://svn.boost.org/trac/boost/ticket/7360 #7360] Memory leak in pthread implementation of boost::thread_specific_ptr +* [@http://svn.boost.org/trac/boost/ticket/7370 #7370] Boost.Thread documentation +* [@http://svn.boost.org/trac/boost/ticket/7438 #7438] Segmentation fault in test_once regression test in group.join_all(); +* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0 +* [@http://svn.boost.org/trac/boost/ticket/7499 #7499] call_once doesn't call even once + [heading Version 3.0.1 - boost 1.51] diff --git a/doc/future_ref.qbk b/doc/future_ref.qbk index 2da9f408..5d62f6cc 100644 --- a/doc/future_ref.qbk +++ b/doc/future_ref.qbk @@ -261,7 +261,16 @@ The object's `name` virtual function returns a pointer to the string "future".]] __unique_future__(__unique_future__ && other) noexcept; __unique_future__& operator=(__unique_future__ && other) noexcept; shared_future share(); - + template + __unique_future__::type> + then(F&& func); // EXTENSION + template + __unique_future__::type> + then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED + template + __unique_future__::type> + then(launch policy, F&& func); // EXTENSION NOT_YET_IMPLEMENTED + void swap(__unique_future__& other) noexcept; // EXTENSION // retrieving the value @@ -628,6 +637,60 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] [endsect] +[section:then Member function `then()`] + + template + __unique_future__::type> + then(F&& func); // EXTENSION + template + __unique_future__::type> + then(S& scheduler, F&& func); // EXTENSION + template + __unique_future__::type> + then(launch policy, F&& func); // EXTENSION + +[variablelist + +[[Notes:] [The three functions differ only by input parameters. The first only takes a callable object which accepts a +future object as a parameter. The second function takes a scheduler as the first parameter and a callable object as +the second parameter. The third function takes a launch policy as the first parameter and a callable object as the +second parameter.]] + +[[Effects:] [ + +- The continuation is called when the object's shared state is ready (has a value or exception stored). + +- The continuation launches according to the specified policy or scheduler. + +- When the scheduler or launch policy is not provided the continuation inherits the +parent's launch policy or scheduler. + +- If the parent was created with std::promise or with a packaged_task (has no associated launch policy), the +continuation behaves the same as the third overload with a policy argument of launch::async | launch::deferred and +the same argument for func. + +- If the parent has a policy of launch::deferred and the continuation does not have a specified launch policy or +scheduler, then the parent is filled by immediately calling .wait(), and the policy of the antecedent is +launch::deferred + +]] + +[[Returns:] [An object of type future that refers to the shared state created by the continuation.]] + +[[Postconditions:] [ + +- The future object is moved to the parameter of the continuation function . + +- valid() == false on original future object immediately after it returns. + +]] + +] + +[endsect] + + + [endsect] diff --git a/doc/futures.qbk b/doc/futures.qbk index f3e77e59..5c3b126a 100755 --- a/doc/futures.qbk +++ b/doc/futures.qbk @@ -220,6 +220,65 @@ make_shared_future has the same functionality as make_future, except has a retur [endsect] +[section:then Associating future continuations] + +In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second +operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future. +With .then, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is +invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits +or wasting threads on polling, greatly improving the responsiveness and scalability of an application. + +future.then provides the ability to sequentially compose two futures by declaring one to be the continuation of another. +With .then the antecedent future is ready (has a value or exception stored in the shared state) before the continuation +starts as instructed by the lambda function. + +In the example below the future f2 is registered to be a continuation of future f1 using the .then member +function. This operation takes a lambda function which describes how f2 should proceed after f1 is ready. + + + #include + using namespace boost; + int main() + { + future f1 = async([]() { return 123; }); + future f2 = f1.then([](future f) { return f.get().to_string(); // here .get() won't block }); + } + +One key feature of this function is the ability to chain multiple asynchronous operations. In asynchronous programming, +it's common to define a sequence of operations, in which each continuation executes only when the previous one completes. +In some cases, the antecedent future produces a value that the continuation accepts as input. By using future.then, +creating a chain of continuations becomes straightforward and intuitive: + + myFuture.then(...).then(...).then(...). + +Some points to note are: + +* Each continuation will not begin until the preceding has completed. +* If an exception is thrown, the following continuation can handle it in a try-catch block + + +Input Parameters: + +* Lambda function2: One option which was considered was to follow JavaScript's approach and take two functions, one for +success and one for error handling. However this option is not viable in C++ as there is no single base type for +exceptions as there is in JavaScript. The lambda function takes a future as its input which carries the exception +through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations. +* Scheduler: Providing an overload to .then, to take a scheduler reference places great flexibility over the execution +of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful +asynchronous operations. The lifetime of the scheduler must outlive the continuation. +* Launch policy: if the additional flexibility that the scheduler provides is not required. + + +Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using +.then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning +a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A +shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future +to a shared_future when needed using future::share(). + + +[endsect] + + [include future_ref.qbk] [endsect] \ No newline at end of file diff --git a/example/future_then.cpp b/example/future_then.cpp new file mode 100644 index 00000000..79e35a86 --- /dev/null +++ b/example/future_then.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2012 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_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET + +#include +#include +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + +int p1() +{ + return 123; +} + +int p2(boost::future& f) +{ + return 2 * f.get(); +} + +int main() +{ + boost::future f1 = boost::async(p1); + boost::future f2 = f1.then(p2); + std::cout << f2.get() << std::endl; + return 0; +} +#else + +int main() +{ + return 0; +} +#endif diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index 587f0df7..0a920aff 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -16,12 +16,15 @@ #include #include #include +#include +#if ! defined BOOST_THREAD_NOEXCEPT_OR_THROW #ifdef BOOST_NO_NOEXCEPT # define BOOST_THREAD_NOEXCEPT_OR_THROW throw() #else # define BOOST_THREAD_NOEXCEPT_OR_THROW noexcept #endif +#endif // This compiler doesn't support Boost.Chrono #if defined __IBMCPP__ && (__IBMCPP__ < 1100) && ! defined BOOST_THREAD_DONT_USE_CHRONO @@ -69,12 +72,21 @@ #if BOOST_THREAD_VERSION==2 -#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY && ! defined BOOST_THREAD_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 -#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 + +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_EQ \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ #endif + +#if ! defined BOOST_THREAD_DONT_USE_DATETIME \ + && ! defined BOOST_THREAD_USES_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif + #endif #if BOOST_THREAD_VERSION>=3 @@ -110,10 +122,6 @@ && ! 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 \ - && ! 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 \ && ! defined BOOST_THREAD_USES_MOVE #define BOOST_THREAD_USES_MOVE @@ -136,19 +144,27 @@ ! defined(BOOST_NO_CXX11_DECLTYPE) && \ ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ ! defined(BOOST_NO_CXX11_HDR_TUPLE) - - #define BOOST_THREAD_PROVIDES_VARIADIC_THREAD #endif +#endif + +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION + +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#endif +#endif #if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \ && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET #define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET #endif +#endif // BOOST_THREAD_VERSION>=4 -#endif -#endif + +// CORRELATIONS // 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 \ @@ -158,9 +174,16 @@ // 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 \ -&& ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 -#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 + +#if ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ +#endif + +#if ! defined BOOST_THREAD_USES_DATETIME +#define defined BOOST_THREAD_USES_DATETIME +#endif + #endif #if BOOST_WORKAROUND(__BORLANDC__, < 0x600) diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index d75a6e97..b791bcc7 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -262,10 +262,6 @@ namespace boost detail::thread_data_ptr thread_info; -#ifdef BOOST_THREAD_PLATFORM_WIN32 - void start_thread(); - void start_thread(const attributes& attr); -#else private: bool start_thread_noexcept(); bool start_thread_noexcept(const attributes& attr); @@ -285,7 +281,6 @@ namespace boost } } -#endif explicit thread(detail::thread_data_ptr data); detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; @@ -542,14 +537,10 @@ namespace boost bool joinable() const BOOST_NOEXCEPT; -#if defined(BOOST_THREAD_PLATFORM_WIN32) - void join(); -#else private: bool join_noexcept(); public: inline void join(); -#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -574,10 +565,15 @@ namespace boost } #endif #if defined(BOOST_THREAD_PLATFORM_WIN32) - bool timed_join(const system_time& abs_time); private: - bool do_try_join_until(uintmax_t milli); + bool do_try_join_until_noexcept(uintmax_t milli, bool& res); + inline bool do_try_join_until(uintmax_t milli); public: + bool timed_join(const system_time& abs_time); + //{ + // return do_try_join_until(get_milliseconds_until(wait_until)); + //} + #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { @@ -592,7 +588,7 @@ namespace boost bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res); inline bool do_try_join_until(struct timespec const &timeout); public: -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO +#if defined BOOST_THREAD_USES_DATETIME bool timed_join(const system_time& abs_time) { struct timespec const ts=detail::get_timespec(abs_time); @@ -615,7 +611,7 @@ namespace boost #endif public: -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO +#if defined BOOST_THREAD_USES_DATETIME template inline bool timed_join(TimeDuration const& rel_time) { @@ -630,7 +626,7 @@ namespace boost typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ // Use thread::id when comparisions are needed // backwards compatibility bool operator==(const thread& other) const; @@ -641,7 +637,7 @@ namespace boost this_thread::yield(); } -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO +#if defined BOOST_THREAD_USES_DATETIME static inline void sleep(const system_time& xt) { this_thread::sleep(xt); @@ -679,7 +675,7 @@ namespace boost bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO +#if defined BOOST_THREAD_USES_DATETIME inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); @@ -720,11 +716,7 @@ namespace boost public: id() BOOST_NOEXCEPT: #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID -#if defined(BOOST_THREAD_PLATFORM_WIN32) thread_data(0) -#else - thread_data(0) -#endif #else thread_data() #endif @@ -825,6 +817,7 @@ namespace boost #endif } } +#endif void thread::join() { if (this_thread::get_id() == get_id()) { @@ -838,7 +831,11 @@ namespace boost } } +#ifdef BOOST_THREAD_PLATFORM_PTHREAD bool thread::do_try_join_until(struct timespec const &timeout) +#else + bool thread::do_try_join_until(uintmax_t timeout) +#endif { if (this_thread::get_id() == get_id()) { @@ -858,8 +855,6 @@ namespace boost } } -#endif - #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template BOOST_SYMBOL_VISIBLE @@ -870,7 +865,7 @@ namespace boost } #endif -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ inline bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 919f4320..c2d39e30 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -58,7 +58,6 @@ #define BOOST_THREAD_FUTURE unique_future #endif - namespace boost { @@ -210,6 +209,50 @@ namespace boost namespace detail { +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + struct future_continuation_base + { + future_continuation_base() {} + virtual ~future_continuation_base() {} + + virtual void do_continuation(boost::unique_lock& ) {}; + private: + future_continuation_base(future_continuation_base const&); + future_continuation_base& operator=(future_continuation_base const&); + }; + + template + struct future_continuation; + +#endif + + struct relocker + { + boost::unique_lock& lock_; + bool unlocked_; + + relocker(boost::unique_lock& lk): + lock_(lk) + { + lock_.unlock(); + unlocked_=true; + } + ~relocker() + { + if (unlocked_) { + lock_.lock(); + } + } + void lock() { + if (unlocked_) { + lock_.lock(); + unlocked_=false; + } + } + private: + relocker& operator=(relocker const&); + }; + struct future_object_base { boost::exception_ptr exception; @@ -220,10 +263,16 @@ namespace boost typedef std::list waiter_list; waiter_list external_waiters; boost::function callback; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + shared_ptr continuation_ptr; +#endif future_object_base(): done(false), thread_was_interrupted(false) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + , continuation_ptr() +#endif {} virtual ~future_object_base() {} @@ -241,7 +290,28 @@ namespace boost external_waiters.erase(it); } - void mark_finished_internal() +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void do_continuation(boost::unique_lock& lock) + { + if (continuation_ptr) { + continuation_ptr->do_continuation(lock); + } + } +#else + void do_continuation(boost::unique_lock&) + { + } +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void set_continuation_ptr(future_continuation_base* continuation, boost::unique_lock& lock) + { + continuation_ptr.reset(continuation); + if (done) { + do_continuation(lock); + } + } +#endif + void mark_finished_internal(boost::unique_lock& lock) { done=true; waiters.notify_all(); @@ -250,25 +320,9 @@ namespace boost { (*it)->notify_all(); } + do_continuation(lock); } - struct relocker - { - boost::unique_lock& lock; - - relocker(boost::unique_lock& lock_): - lock(lock_) - { - lock.unlock(); - } - ~relocker() - { - lock.lock(); - } - private: - relocker& operator=(relocker const&); - }; - void do_callback(boost::unique_lock& lock) { if(callback && !done) @@ -280,9 +334,8 @@ namespace boost } - void wait(bool rethrow=true) + void wait_internal(boost::unique_lock &lock, bool rethrow=true) { - boost::unique_lock lock(mutex); do_callback(lock); while(!done) { @@ -296,8 +349,15 @@ namespace boost { boost::rethrow_exception(exception); } + + } + void wait(bool rethrow=true) + { + boost::unique_lock lock(mutex); + wait_internal(lock, rethrow); } +#if defined BOOST_THREAD_USES_DATETIME bool timed_wait_until(boost::system_time const& target_time) { boost::unique_lock lock(mutex); @@ -312,7 +372,7 @@ namespace boost } return true; } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -332,21 +392,21 @@ namespace boost return future_status::ready; } #endif - void mark_exceptional_finish_internal(boost::exception_ptr const& e) + void mark_exceptional_finish_internal(boost::exception_ptr const& e, boost::unique_lock& lock) { exception=e; - mark_finished_internal(); + mark_finished_internal(lock); } void mark_exceptional_finish() { - boost::lock_guard lock(mutex); - mark_exceptional_finish_internal(boost::current_exception()); + boost::unique_lock lock(mutex); + mark_exceptional_finish_internal(boost::current_exception(), lock); } void mark_interrupted_finish() { - boost::lock_guard lock(mutex); + boost::unique_lock lock(mutex); thread_was_interrupted=true; - mark_finished_internal(); + mark_finished_internal(lock); } bool has_value() { @@ -463,30 +523,35 @@ namespace boost result(0) {} - void mark_finished_with_result_internal(source_reference_type result_) + ~future_object() { - future_traits::init(result,result_); - mark_finished_internal(); } - void mark_finished_with_result_internal(rvalue_source_type result_) + void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock& lock) + { + future_traits::init(result,result_); + mark_finished_internal(lock); + } + + void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock& lock) { future_traits::init(result,static_cast(result_)); - mark_finished_internal(); + mark_finished_internal(lock); } void mark_finished_with_result(source_reference_type result_) { - boost::lock_guard lock(mutex); - mark_finished_with_result_internal(result_); + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(result_, lock); } void mark_finished_with_result(rvalue_source_type result_) { - boost::lock_guard lock(mutex); - mark_finished_with_result_internal(static_cast(result_)); + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(static_cast(result_), lock); } + move_dest_type get() { wait(); @@ -527,15 +592,15 @@ namespace boost future_object() {} - void mark_finished_with_result_internal() + void mark_finished_with_result_internal(boost::unique_lock& lock) { - mark_finished_internal(); + mark_finished_internal(lock); } void mark_finished_with_result() { - boost::lock_guard lock(mutex); - mark_finished_with_result_internal(); + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(lock); } void get() @@ -590,7 +655,6 @@ namespace boost count_type index_): future_(a_future),wait_iterator(wait_iterator_),index(index_) {} - }; struct all_futures_lock @@ -812,7 +876,10 @@ namespace boost friend class shared_future; friend class promise; - +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + friend struct detail::future_continuation; +#endif #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK template friend class packaged_task; // todo check if this works in windows #else @@ -918,6 +985,7 @@ namespace boost future_->wait(false); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_wait(Duration const& rel_time) const { @@ -932,6 +1000,7 @@ namespace boost } return future_->timed_wait_until(abs_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template future_status @@ -950,6 +1019,14 @@ namespace boost } return future_->wait_until(abs_time); } +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +// template +// auto then(F&& func) -> BOOST_THREAD_FUTURE; + template + inline BOOST_THREAD_FUTURE::type> then(F&& func); + #endif }; @@ -1072,6 +1149,7 @@ namespace boost future_->wait(false); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_wait(Duration const& rel_time) const { @@ -1086,6 +1164,7 @@ namespace boost } return future_->timed_wait_until(abs_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -1156,11 +1235,11 @@ namespace boost { if(future_) { - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(!future_->done) { - future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); } } } @@ -1206,35 +1285,35 @@ namespace boost void set_value(typename detail::future_traits::source_reference_type r) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(r); + future_->mark_finished_with_result_internal(r, lock); } // void set_value(R && r); void set_value(typename detail::future_traits::rvalue_source_type r) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(static_cast::rvalue_source_type>(r)); + future_->mark_finished_with_result_internal(static_cast::rvalue_source_type>(r), lock); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p, lock); } // setting the result with deferred notification @@ -1297,11 +1376,11 @@ namespace boost { if(future_) { - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(!future_->done) { - future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); } } } @@ -1350,23 +1429,23 @@ namespace boost void set_value() { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(); + future_->mark_finished_with_result_internal(lock); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p,lock); } template @@ -1443,11 +1522,11 @@ namespace boost void owner_destroyed() { - boost::lock_guard lk(this->mutex); + boost::unique_lock lk(this->mutex); if(!started) { started=true; - this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise())); + this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise()), lk); } } @@ -1925,7 +2004,7 @@ namespace boost { boost::throw_exception(future_already_retrieved()); } - return BOOST_THREAD_FUTURE(); + //return BOOST_THREAD_FUTURE(); } @@ -2178,7 +2257,7 @@ namespace boost { typedef typename decay::type future_type; promise p; - p.set_value(value); + p.set_value(boost::forward(value)); return p.get_future().share(); } @@ -2190,6 +2269,71 @@ namespace boost } #endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + namespace detail + { + + template + struct future_continuation : future_continuation_base + { + F& parent; + C continuation; + promise next; + + future_continuation(F& f, C&& c) : parent(f), continuation(boost::forward(c)), next() + {} + ~future_continuation() + {} + + void do_continuation(boost::unique_lock& lk) + { + try + { + lk.unlock(); + R val = continuation(parent); + next.set_value(boost::move(val)); + } + catch (...) + { + next.set_exception(boost::current_exception()); + } + } + private: + + future_continuation(future_continuation const&); + future_continuation& operator=(future_continuation const&); + }; + } + +// template +// auto then(F&& func) -> BOOST_THREAD_FUTURE; + template + template + inline BOOST_THREAD_FUTURE&)>::type> + BOOST_THREAD_FUTURE::then(F&& func) + { + + typedef typename boost::result_of&)>::type future_type; + + if (future_) + { + boost::unique_lock lock(future_->mutex); + detail::future_continuation, future_type, F > *ptr = + new detail::future_continuation, future_type, F>(*this, boost::forward(func)); + if (ptr==0) + { + return BOOST_THREAD_FUTURE(); + } + future_->set_continuation_ptr(ptr, lock); + return ptr->next.get_future(); + } else { + return BOOST_THREAD_FUTURE(); + } + + } +#endif + } #endif // BOOST_NO_EXCEPTION diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index c11c2bd3..f2d3f4dc 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -311,6 +311,7 @@ namespace boost { try_lock(); } +#if defined BOOST_THREAD_USES_DATETIME template unique_lock(Mutex& m_,TimeDuration const& target_time): m(&m_),is_locked(false) @@ -322,7 +323,7 @@ namespace boost { timed_lock(target_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template unique_lock(Mutex& mtx, const chrono::time_point& t) @@ -521,6 +522,7 @@ namespace boost is_locked=m->try_lock(); return is_locked; } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_lock(TimeDuration const& relative_time) { @@ -562,7 +564,7 @@ namespace boost is_locked=m->timed_lock(absolute_time); return is_locked; } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -686,12 +688,13 @@ namespace boost { try_lock(); } +#if defined BOOST_THREAD_USES_DATETIME shared_lock(Mutex& m_,system_time const& target_time): m(&m_),is_locked(false) { timed_lock(target_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template shared_lock(Mutex& mtx, const chrono::time_point& t) @@ -809,6 +812,7 @@ namespace boost is_locked=m->try_lock_shared(); return is_locked; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(boost::system_time const& target_time) { if(m==0) @@ -836,6 +840,7 @@ namespace boost is_locked=m->timed_lock_shared(target_time); return is_locked; } +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index aa710076..9cc61111 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -157,6 +157,7 @@ namespace boost while(!pred()) wait(m); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_wait(lock_type& m,boost::system_time const& wait_until) { @@ -197,7 +198,7 @@ namespace boost { return timed_wait(m,get_system_time()+wait_duration,pred); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template cv_status diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index dbb38926..889b9c96 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -66,6 +66,7 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME inline bool timed_wait( unique_lock& m, boost::system_time const& wait_until) @@ -121,6 +122,7 @@ namespace boost { return timed_wait(m,get_system_time()+wait_duration,pred); } +#endif #ifdef BOOST_THREAD_USES_CHRONO diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 2c5af92b..a3334e8f 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -146,6 +146,7 @@ namespace boost #endif } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_lock(TimeDuration const & relative_time) { @@ -155,7 +156,7 @@ namespace boost { return timed_lock(system_time(absolute_time)); } - +#endif #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK void lock() { @@ -232,12 +233,13 @@ namespace boost public: #endif +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { struct timespec const ts=detail::get_timespec(abs_time); return do_try_lock_until(ts); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index 2a6bc7da..70787f22 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -232,11 +232,13 @@ namespace boost #endif } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_lock(TimeDuration const & relative_time) { return timed_lock(get_system_time()+relative_time); } +#endif #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK void lock() @@ -334,12 +336,13 @@ namespace boost #endif +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { struct timespec const ts=detail::get_timespec(abs_time); return do_try_lock_until(ts); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp index cf451886..f6ef8bb9 100644 --- a/include/boost/thread/pthread/shared_mutex.hpp +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -88,6 +88,7 @@ namespace boost } } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock_shared(system_time const& timeout) { boost::this_thread::disable_interruption do_not_disturb; @@ -109,6 +110,7 @@ namespace boost { return timed_lock_shared(get_system_time()+relative_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_shared_for(const chrono::duration& rel_time) @@ -166,6 +168,7 @@ namespace boost state.exclusive=true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const& timeout) { boost::this_thread::disable_interruption do_not_disturb; @@ -194,7 +197,7 @@ namespace boost { return timed_lock(get_system_time()+relative_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) @@ -262,6 +265,7 @@ namespace boost state.upgrade=true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock_upgrade(system_time const& timeout) { boost::this_thread::disable_interruption do_not_disturb; @@ -287,7 +291,7 @@ namespace boost { return timed_lock_upgrade(get_system_time()+relative_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_upgrade_for(const chrono::duration& rel_time) diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index db4e09f5..c7c7a858 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -233,6 +233,7 @@ namespace boost #endif void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; +#if defined BOOST_THREAD_USES_DATETIME #ifdef __DECXXX /// Workaround of DECCXX issue of incorrect template substitution template @@ -251,6 +252,7 @@ namespace boost { this_thread::sleep(get_system_time()+rel_time); } +#endif #endif } } diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 4e453880..81605bb7 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -6,6 +6,7 @@ // 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 2 #include #include @@ -400,6 +401,7 @@ namespace boost namespace this_thread { +#if ! defined BOOST_THREAD_USES_DATETIME2 #ifdef __DECXXX /// Workaround of DECCXX issue of incorrect template substitution template<> @@ -443,7 +445,7 @@ namespace boost } } } - +#endif void yield() BOOST_NOEXCEPT { # if defined(BOOST_HAS_SCHED_YIELD) diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index b8a7aa73..f60f2fbe 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -11,6 +11,7 @@ #ifndef WINVER #define WINVER 0x400 #endif +#define BOOST_THREAD_VERSION 2 #include #include @@ -87,10 +88,15 @@ namespace boost void set_current_thread_data(detail::thread_data_base* new_data) { boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); - if(current_thread_tls_key!=TLS_OUT_OF_INDEXES) + if (current_thread_tls_key!=TLS_OUT_OF_INDEXES) + { BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data)); + } else - boost::throw_exception(thread_resource_error()); + { + BOOST_VERIFY(false); + //boost::throw_exception(thread_resource_error()); + } } #ifndef BOOST_HAS_THREADEX @@ -212,29 +218,33 @@ namespace boost thread::thread() BOOST_NOEXCEPT {} - void thread::start_thread() + bool thread::start_thread_noexcept() { uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); if(!new_thread) { - boost::throw_exception(thread_resource_error()); + return false; +// boost::throw_exception(thread_resource_error()); } intrusive_ptr_add_ref(thread_info.get()); thread_info->thread_handle=(detail::win32::handle)(new_thread); ResumeThread(thread_info->thread_handle); + return true; } - void thread::start_thread(const attributes& attr) + bool thread::start_thread_noexcept(const attributes& attr) { //uintptr_t const new_thread=_beginthreadex(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); uintptr_t const new_thread=_beginthreadex(0,static_cast(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); if(!new_thread) { - boost::throw_exception(thread_resource_error()); + return false; +// boost::throw_exception(thread_resource_error()); } intrusive_ptr_add_ref(thread_info.get()); thread_info->thread_handle=(detail::win32::handle)(new_thread); ResumeThread(thread_info->thread_handle); + return true; } thread::thread(detail::thread_data_ptr data): @@ -305,23 +315,22 @@ namespace boost { return (get_thread_info)(); } - void thread::join() + bool thread::join_noexcept() { - if (this_thread::get_id() == get_id()) - { - boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself")); - } + detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel()); 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 false; +//#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED +// boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); +//#endif } } @@ -330,27 +339,26 @@ namespace boost return do_try_join_until(get_milliseconds_until(wait_until)); } - bool thread::do_try_join_until(uintmax_t milli) + bool thread::do_try_join_until_noexcept(uintmax_t milli, bool& res) { - if (this_thread::get_id() == get_id()) - { - boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself")); - } detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { if(!this_thread::interruptible_wait(local_thread_info->thread_handle,milli)) { - return false; + res=false; + return true; } release_handle(); + res=true; 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 false; +//#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED +// boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); +//#endif } } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 14f07ed0..dd0270c3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -523,6 +523,7 @@ rule thread-compile-fail ( sources : reqs * : name ) #[ thread-run ../example/vhh_shared_monitor.cpp ] #[ thread-run ../example/vhh_shared_mutex.cpp ] [ thread-run ../example/make_future.cpp ] + [ thread-run ../example/future_then.cpp ] ; diff --git a/test/test_2309.cpp b/test/test_2309.cpp index 1d1c3e55..2cfef8c4 100755 --- a/test/test_2309.cpp +++ b/test/test_2309.cpp @@ -3,6 +3,8 @@ // 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 2 + #include #include diff --git a/test/test_3628.cpp b/test/test_3628.cpp index bef38cdc..b15cb760 100644 --- a/test/test_3628.cpp +++ b/test/test_3628.cpp @@ -3,6 +3,8 @@ // 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 2 + #include #include #include diff --git a/test/test_4882.cpp b/test/test_4882.cpp index bd6e1e61..9a404e46 100644 --- a/test/test_4882.cpp +++ b/test/test_4882.cpp @@ -3,6 +3,8 @@ // 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 2 + #include #include #include diff --git a/test/test_5542_1.cpp b/test/test_5542_1.cpp index 256ba34d..9e86e504 100644 --- a/test/test_5542_1.cpp +++ b/test/test_5542_1.cpp @@ -3,6 +3,8 @@ // 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 2 + #include #include diff --git a/test/test_5542_3.cpp b/test/test_5542_3.cpp index 792bf1d0..b1c8ea28 100644 --- a/test/test_5542_3.cpp +++ b/test/test_5542_3.cpp @@ -3,6 +3,8 @@ // 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 2 + #include #include #include diff --git a/test/test_6130.cpp b/test/test_6130.cpp index d8e84c34..de158f63 100644 --- a/test/test_6130.cpp +++ b/test/test_6130.cpp @@ -3,6 +3,8 @@ // 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 2 + #include #include #include diff --git a/test/test_lock_concept.cpp b/test/test_lock_concept.cpp index cc9d518c..8665f6e5 100644 --- a/test/test_lock_concept.cpp +++ b/test/test_lock_concept.cpp @@ -3,6 +3,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include diff --git a/test/test_xtime.cpp b/test/test_xtime.cpp index 2ba3013c..447cb619 100644 --- a/test/test_xtime.cpp +++ b/test/test_xtime.cpp @@ -5,6 +5,8 @@ // 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 2 + #include #include