From 89e944914b6ea57dd705ae8e21178a7e60afed17 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 9 Sep 2012 19:39:44 +0000 Subject: [PATCH] Thread: Merged from trunk : 1.52 [SVN r80476] --- build/Jamfile.v2 | 2 + doc/changes.qbk | 6 +- doc/condition_variables.qbk | 48 ++- doc/future_ref.qbk | 407 ++++++++++++------ doc/futures.qbk | 9 +- doc/mutex_concepts.qbk | 38 +- doc/mutexes.qbk | 4 +- doc/thread_ref.qbk | 42 +- doc/tss.qbk | 5 +- include/boost/thread/detail/config.hpp | 65 +-- include/boost/thread/detail/thread.hpp | 7 +- include/boost/thread/future.hpp | 174 +++++++- .../thread/pthread/condition_variable_fwd.hpp | 3 + .../boost/thread/pthread/recursive_mutex.hpp | 4 +- include/boost/thread/pthread/thread_data.hpp | 28 +- .../thread/win32/basic_recursive_mutex.hpp | 6 +- .../boost/thread/win32/condition_variable.hpp | 19 +- .../boost/thread/win32/interlocked_read.hpp | 19 +- include/boost/thread/win32/thread_data.hpp | 31 +- src/pthread/thread.cpp | 41 +- src/win32/thread.cpp | 58 ++- src/win32/tss_dll.cpp | 1 + test/Jamfile.v2 | 3 + .../notify_all_at_thread_exit_pass.cpp | 51 +++ test/sync/futures/async/async_pass.cpp | 64 ++- test/threads/thread/assign/move_pass.cpp | 16 +- test/threads/thread/members/join_pass.cpp | 88 ++-- .../thread/members/try_join_for_pass.cpp | 161 +++++++ .../thread/members/try_join_until_pass.cpp | 162 +++++++ 29 files changed, 1227 insertions(+), 335 deletions(-) create mode 100644 test/sync/conditions/notify_all_at_thread_exit_pass.cpp create mode 100644 test/threads/thread/members/try_join_for_pass.cpp create mode 100644 test/threads/thread/members/try_join_until_pass.cpp 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/changes.qbk b/doc/changes.qbk index 9e2cb4a2..65240e5b 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -14,6 +14,8 @@ New Features: * [@http://svn.boost.org/trac/boost/ticket/2361 #2361] thread_specific_ptr: document nature of the key, complexity and rationale * [@http://svn.boost.org/trac/boost/ticket/4710 #4710] C++11 compliance: : Missing async() +* [@http://svn.boost.org/trac/boost/ticket/7283 #7283] C++11 compliance: Add notify_all_at_thread_exit +* [@http://svn.boost.org/trac/boost/ticket/7345 #7345] C++11 compliance: Add noexcept to recursive mutex try_lock Fixed Bugs: @@ -29,6 +31,8 @@ Fixed Bugs: * [@http://svn.boost.org/trac/boost/ticket/7238 #5274] 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 * [@http://svn.boost.org/trac/boost/ticket/7272 #7272] win32/thread_primitives.hpp: (Unneccessary) Warning +* [@http://svn.boost.org/trac/boost/ticket/7284 #7284] Clarify that there is no access priority between lock and shared_lock on shared mutex +* [@http://svn.boost.org/trac/boost/ticket/7329 #7329] boost/thread/future.hpp does not compile on HPUX [heading Version 3.0.1 - boost 1.51] @@ -248,7 +252,7 @@ The following features will be included in next releases. # Complete the C++11 missing features, in particular - * [@http://svn.boost.org/trac/boost/ticket/4710 #4710] Missing async(). + * async with deferred and variadic rvalue reference args. * [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Use of variadic templates on Generic Locking Algorithms on compilers providing them. * [@http://svn.boost.org/trac/boost/ticket/6270 #6270] Add thread constructor from movable callable and movable arguments following C++11. diff --git a/doc/condition_variables.qbk b/doc/condition_variables.qbk index 77d0b26a..88deee1c 100644 --- a/doc/condition_variables.qbk +++ b/doc/condition_variables.qbk @@ -19,6 +19,7 @@ }; class condition_variable; class condition_variable_any; + void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); } The classes `condition_variable` and `condition_variable_any` provide a @@ -86,7 +87,7 @@ optimizations in some cases, based on the knowledge of the mutex type; [section:condition_variable Class `condition_variable`] - #include + //#include namespace boost { @@ -439,7 +440,7 @@ return true; [section:condition_variable_any Class `condition_variable_any`] - #include + //#include namespace boost { @@ -751,14 +752,53 @@ return true; [endsect] -[section:condition Typedef `condition`] +[section:condition Typedef `condition` DEPRECATED V3] - #include + // #include + namespace boost + { typedef condition_variable_any condition; + } + The typedef `condition` is provided for backwards compatibility with previous boost releases. [endsect] + +[section:notify_all_at_thread_exit Non-member Function `notify_all_at_thread_exit`()] + + // #include + + namespace boost + { + void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); + } + +[variablelist + +[[Requires:] [`lk` is locked by the calling thread and either no other thread is waiting on `cond`, or `lk.mutex()` returns the same value for each of the lock arguments supplied by all concurrently waiting (via `wait`, `wait_for`, or `wait_until`) threads.]] +[[Effects:] [transfers ownership of the lock associated with `lk` into internal storage and schedules `cond` to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification shall be as if + +`` + lk.unlock(); + cond.notify_all(); +`` + +]] + +] + +[/ +[[Synchronization:] [The call to notify_all_at_thread_exit and the completion of the destructors for all the current threadŐs variables of thread storage duration synchronize with (1.10) calls to functions waiting on cond. +]] +[[Note:] [The supplied lock will be held until the thread exits, and care must be taken to ensure that this does not cause deadlock due to lock ordering issues. After calling notify_all_at_thread_exit it is recommended that the thread should be exited as soon as possible, and that no blocking or time-consuming tasks are run on that thread. +]] +[[Note:] [It is the userŐs responsibility to ensure that waiting threads do not erroneously assume that the thread has finished if they experience spurious wakeups. This typically requires that the condition being waited for is satisfied while holding the lock on lk, and that this lock is not released and reacquired prior to calling notify_all_at_thread_exit. +]] +] + +[endsect] + [endsect] diff --git a/doc/future_ref.qbk b/doc/future_ref.qbk index 6adef76a..b4644b82 100644 --- a/doc/future_ref.qbk +++ b/doc/future_ref.qbk @@ -5,16 +5,17 @@ http://www.boost.org/LICENSE_1_0.txt). ] + [section:reference Futures Reference] //#include - namespace boost + namespace boost { #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 namespace future_state { - enum state {uninitialized, waiting, ready, moved}; + enum state {uninitialized, waiting, ready, moved}; } #endif @@ -47,7 +48,7 @@ void swap(promise& x, promise& y) noexcept; namespace container { - template + template struct uses_allocator, Alloc>:: true_type; } @@ -61,14 +62,21 @@ class packaged_task; template void swap(packaged_task&, packaged_task&) noexcept; - template + template struct uses_allocator, Alloc>; - // template - // future::type(typename decay::type...)>::type> + template + future::type()>::type> + async(F f); + template + future::type()>::type> + async(launch policy, F f); + + // template + // future::type(typename decay::type...)>::type> // async(F&& f, Args&&... args); // NOT YET IMPLEMENTED - // template - // future::type(typename decay::type...)>::type> + // template + // future::type(typename decay::type...)>::type> // async(launch policy, F&& f, Args&&... args); // NOT YET IMPLEMENTED @@ -89,7 +97,7 @@ namespace future_state { - enum state {uninitialized, waiting, ready, moved}; + enum state {uninitialized, waiting, ready, moved}; } @@ -153,66 +161,66 @@ [section:future_status Enumeration `future_status`] - enum class future_status { + enum class future_status { ready, timeout, deferred }; [endsect] -[section:unique_future `unique_future` class template] +[section:unique_future __unique_future class template] template - class unique_future + class __unique_future__ { public: - unique_future(unique_future & rhs);// = delete; - unique_future& operator=(unique_future& rhs);// = delete; + __unique_future__(__unique_future__ & rhs);// = delete; + __unique_future__& operator=(__unique_future__& rhs);// = delete; - unique_future() noexcept; - ~unique_future(); + __unique_future__() noexcept; + ~__unique_future__(); - // move support - unique_future(unique_future && other) noexcept; - unique_future& operator=(unique_future && other) noexcept; - shared_future share(); + // move support + __unique_future__(__unique_future__ && other) noexcept; + __unique_future__& operator=(__unique_future__ && other) noexcept; + shared_future share(); - void swap(unique_future& other) noexcept; // EXTENSION + void swap(__unique_future__& other) noexcept; // EXTENSION - // retrieving the value - R&& get(); + // retrieving the value + R&& get(); - // functions to check state - bool valid() const; - bool is_ready() const; // EXTENSION - bool has_exception() const; // EXTENSION - bool has_value() const; // EXTENSION + // functions to check state + bool valid() const; + bool is_ready() const; // EXTENSION + bool has_exception() const; // EXTENSION + bool has_value() const; // EXTENSION - // waiting for the result to be ready - void wait() const; - template - future_status wait_for(const chrono::duration& rel_time) const; - template - future_status wait_until(const chrono::time_point& abs_time) const; + // waiting for the result to be ready + void wait() const; + template + future_status wait_for(const chrono::duration& rel_time) const; + template + future_status wait_until(const chrono::time_point& abs_time) const; #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO - template - bool timed_wait(Duration const& rel_time) const; - bool timed_wait_until(boost::system_time const& abs_time) const; + template + bool timed_wait(Duration const& rel_time) const; + bool timed_wait_until(boost::system_time const& abs_time) const; #endif #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - typedef future_state::state state; - state get_state() const; + typedef future_state::state state; + state get_state() const; #endif }; [section:default_constructor Default Constructor] - unique_future(); + __unique_future__(); [variablelist -[[Effects:] [Constructs an uninitialized future.]] +[[Effects:] [Constructs an uninitialized __unique_future__.]] [[Postconditions:] [[unique_future_is_ready_link `this->is_ready`] returns `false`. [unique_future_get_state_link `this->get_state()`] returns __uninitialized__.]] @@ -225,7 +233,7 @@ [section:destructor Destructor] - ~unique_future(); + ~__unique_future__(); [variablelist @@ -239,11 +247,11 @@ [section:move_constructor Move Constructor] - unique_future(unique_future && other); + __unique_future__(__unique_future__ && other); [variablelist -[[Effects:] [Constructs a new future, and transfers ownership of the asynchronous result associated with `other` to `*this`.]] +[[Effects:] [Constructs a new __unique_future__, and transfers ownership of the asynchronous result associated with `other` to `*this`.]] [[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the call. `other->get_state()` returns __uninitialized__. If `other` was associated with an asynchronous result, that result is now @@ -259,7 +267,7 @@ associated with `*this`. `other` is not associated with any asynchronous result. [section:move_assignment Move Assignment Operator] - unique_future& operator=(unique_future && other); + __unique_future__& operator=(__unique_future__ && other); [variablelist @@ -280,7 +288,7 @@ result prior to the call, that result no longer has an associated __unique_futur [section:swap Member function `swap()`] - void swap(unique_future & other) no_except; + void swap(__unique_future__ & other) no_except; [variablelist @@ -301,8 +309,8 @@ associated with an asynchronous result, that result is now associated with `othe [section:get Member function `get()`] R&& get(); - R& unique_future::get(); - void unique_future::get(); + R& __unique_future__::get(); + void __unique_future__::get(); [variablelist @@ -478,46 +486,46 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] class shared_future { public: - typedef future_state::state state; // EXTENSION + typedef future_state::state state; // EXTENSION - shared_future() noexcept; - ~shared_future(); + shared_future() noexcept; + ~shared_future(); - // copy support - shared_future(shared_future const& other); - shared_future& operator=(shared_future const& other); + // copy support + shared_future(shared_future const& other); + shared_future& operator=(shared_future const& other); - // move support - shared_future(shared_future && other) noexcept; - shared_future(unique_future && other) noexcept; - shared_future& operator=(shared_future && other) noexcept; - shared_future& operator=(unique_future && other) noexcept; + // move support + shared_future(shared_future && other) noexcept; + shared_future(__unique_future__ && other) noexcept; + shared_future& operator=(shared_future && other) noexcept; + shared_future& operator=(__unique_future__ && other) noexcept; - void swap(shared_future& other); + void swap(shared_future& other); - // retrieving the value - R get(); - - // functions to check state, and wait for ready - bool valid() const noexcept; - bool is_ready() const noexcept; // EXTENSION - bool has_exception() const noexcept; // EXTENSION - bool has_value() const noexcept; // EXTENSION + // retrieving the value + R get(); - // waiting for the result to be ready - void wait() const; - template - future_status wait_for(const chrono::duration& rel_time) const; - template - future_status wait_until(const chrono::time_point& abs_time) const; + // functions to check state, and wait for ready + bool valid() const noexcept; + bool is_ready() const noexcept; // EXTENSION + bool has_exception() const noexcept; // EXTENSION + bool has_value() const noexcept; // EXTENSION + + // waiting for the result to be ready + void wait() const; + template + future_status wait_for(const chrono::duration& rel_time) const; + template + future_status wait_until(const chrono::time_point& abs_time) const; #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO - template - bool timed_wait(Duration const& rel_time) const; - bool timed_wait_until(boost::system_time const& abs_time) const; + template + bool timed_wait(Duration const& rel_time) const; + bool timed_wait_until(boost::system_time const& abs_time) const; #endif #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - state get_state() const noexcept; + state get_state() const noexcept; #endif }; @@ -527,7 +535,7 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] [variablelist -[[Effects:] [Constructs an uninitialized future.]] +[[Effects:] [Constructs an uninitialized shared_future.]] [[Postconditions:] [[shared_future_is_ready_link `this->is_ready`] returns `false`. [shared_future_get_state_link `this->get_state()`] returns __uninitialized__.]] @@ -712,33 +720,33 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] { public: - promise(); - template - promise(allocator_arg_t, Allocator a); - promise & operator=(const promise & rhs);// = delete; - promise(const promise & rhs);// = delete; - ~promise(); + promise(); + template + promise(allocator_arg_t, Allocator a); + promise & operator=(const promise & rhs);// = delete; + promise(const promise & rhs);// = delete; + ~promise(); - // Move support - promise(promise && rhs) noexcept;; - promise & operator=(promise&& rhs) noexcept;; - - void swap(promise& other) noexcept; - // Result retrieval - unique_future get_future(); + // Move support + promise(promise && rhs) noexcept;; + promise & operator=(promise&& rhs) noexcept;; - // Set the value - void set_value(R& r); - void set_value(R&& r); - void set_exception(boost::exception_ptr e); + void swap(promise& other) noexcept; + // Result retrieval + __unique_future__ get_future(); - // setting the result with deferred notification - // void set_value_at_thread_exit(const R& r); // NOT YET IMPLEMENTED - // void set_value_at_thread_exit(see below); // NOT YET IMPLEMENTED - // void set_exception_at_thread_exit(exception_ptr p); // NOT YET IMPLEMENTED + // Set the value + void set_value(R& r); + void set_value(R&& r); + void set_exception(boost::exception_ptr e); - template - void set_wait_callback(F f); // EXTENSION + // setting the result with deferred notification + // void set_value_at_thread_exit(const R& r); // NOT YET IMPLEMENTED + // void set_value_at_thread_exit(see below); // NOT YET IMPLEMENTED + // void set_exception_at_thread_exit(exception_ptr p); // NOT YET IMPLEMENTED + + template + void set_wait_callback(F f); // EXTENSION }; [section:default_constructor Default Constructor] @@ -757,8 +765,8 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] [section:alloc_constructor Allocator Constructor] - template - promise(allocator_arg_t, Allocator a); + template + promise(allocator_arg_t, Allocator a); [variablelist @@ -826,7 +834,7 @@ associated with that task to ['ready] with a __broken_promise__ exception as the [section:get_future Member Function `get_future()`] - unique_future get_future(); + __unique_future__ get_future(); [variablelist @@ -913,43 +921,43 @@ or __shared_future__ associated with this result, and the result is not ['ready] class packaged_task { public: - typedef R result_type; + typedef R result_type; - packaged_task(packaged_task&);// = delete; - packaged_task& operator=(packaged_task&);// = delete; + packaged_task(packaged_task&);// = delete; + packaged_task& operator=(packaged_task&);// = delete; - // construction and destruction - packaged_task() noexcept; + // construction and destruction + packaged_task() noexcept; - explicit packaged_task(R(*f)()); - - template - explicit packaged_task(F&& f); + explicit packaged_task(R(*f)()); - template - packaged_task(allocator_arg_t, Allocator a, F&& f); + template + explicit packaged_task(F&& f); - ~packaged_task() - {} + template + packaged_task(allocator_arg_t, Allocator a, F&& f); - // move support - packaged_task(packaged_task&& other) noexcept; - packaged_task& operator=(packaged_task&& other) noexcept; + ~packaged_task() + {} - void swap(packaged_task& other) noexcept; + // move support + packaged_task(packaged_task&& other) noexcept; + packaged_task& operator=(packaged_task&& other) noexcept; - bool valid() const noexcept; - // result retrieval - unique_future get_future(); + void swap(packaged_task& other) noexcept; - // execution - void operator()(); - // void operator()(ArgTypes... ); // NOT YET IMPLEMENTED - // void make_ready_at_thread_exit(ArgTypes...); // NOT YET IMPLEMENTED + bool valid() const noexcept; + // result retrieval + __unique_future__ get_future(); - void reset(); - template - void set_wait_callback(F f); // EXTENSION + // execution + void operator()(); + // void operator()(ArgTypes... ); // NOT YET IMPLEMENTED + // void make_ready_at_thread_exit(ArgTypes...); // NOT YET IMPLEMENTED + + void reset(); + template + void set_wait_callback(F f); // EXTENSION }; [section:task_constructor Task Constructor] @@ -977,10 +985,10 @@ structures could not be allocated.]] [section:alloc_constructor Allocator Constructor] - template - packaged_task(allocator_arg_t, Allocator a, R(*f)()); - template - packaged_task(allocator_arg_t, Allocator a, F&& f); + template + packaged_task(allocator_arg_t, Allocator a, R(*f)()); + template + packaged_task(allocator_arg_t, Allocator a, F&& f); [variablelist @@ -1052,7 +1060,7 @@ associated with that task to ['ready] with a __broken_promise__ exception as the [section:get_future Member Function `get_future()`] - unique_future get_future(); + __unique_future__ get_future(); [variablelist @@ -1086,7 +1094,7 @@ __packaged_task__. __task_already_started__ if the task has already been invoked [section:reset Member Function `reset()`] - void reset(); + void reset(); [variablelist @@ -1123,6 +1131,129 @@ __packaged_task__.]] [endsect] + +[section:decay_copy Non-member function `decay_copy()`] + template + typename decay::type decay_copy(T&& v) + { + return std::forward(v); + } + +[endsect] + +[section:async Non-member function `async()`] + + template + __unique_future__::type()>::type> + async(F f); + template + __unique_future__::type()>::type> + async(launch policy, F f); + + +The function template async provides a mechanism to launch a function potentially in a new thread and +provides the result of the function in a future object with which it shares a shared state. + +[warning `async(launch::deferred, F)` is NOT YET IMPLEMENTED!] + +[variablelist + +[[Requires:] [ + +`` +decay_copy(std::forward(f))() +`` + +shall be a valid expression. +]] + +[[Effects] [The first function behaves the same as a call to the second function with a policy argument of + `launch::async | launch::deferred` and the same arguments for `F`. The second function creates a shared state that is associated with the returned future object. + +The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies): + +- if `policy & launch::async` is non-zero - calls `decay_copy(std::forward(f))()` as if in a new thread of execution represented by a thread object with the calls to `decay_copy()` being evaluated in the thread that called `async`. Any return value is stored as the result in the shared state. Any exception propagated from the execution of `decay_copy(std::forward(f))()` is stored as the exceptional result in the shared state. The thread object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state. + +- if `policy & launch::deferred` is non-zero - Stores `decay_copy(std::forward(f))` in the shared state. This copy of `f` constitute a deferred function. Invocation of the deferred function evaluates `boost::move(g)()` where `g` is the stored value of `decay_copy(std::forward(f))`. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of `boost::move(g)()` begins, the function is no longer considered deferred. (Note: If this policy is specified together with other policies, such as when using a policy value of `launch::async | launch::deferred`, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.) + +]] + +[[Returns:] [An object of type `__unique_future__::type()>::type>` that refers to the shared state created by this call to `async`.]] + +[[Synchronization:] [Regardless of the provided policy argument, + +- the invocation of `async` synchronizes with the invocation of `f`. (Note: This statement applies even when the corresponding future object is moved to another thread.); and + +- the completion of the function `f` is sequenced before the shared state is made ready. (Note: `f` might not be called at all, so its completion might never happen.) + +If the implementation chooses the `launch::async` policy, + +- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined; + +- the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first. +]] + +[[Throws:][`system_error` if policy is `launch::async` and the implementation is unable to start a new thread. +]] + +[[Error conditions:] [ + +- `resource_unavailable_try_again` - if policy is `launch::async` and the system is unable to start a new thread. + +]] + +[[Remarks:] [The first signature shall not participate in overload resolution if decay::type is std::launch. +]] + +] + +[/ + +[variablelist + +[[Requires:] [F and each Ti in Args shall satisfy the MoveConstructible requirements. INVOKE (DECAY_- COPY (std::forward(f)), decay_copy (std::forward(args))...) shall be a valid expression. + +]] +[[Effects:] [The first function behaves the same as a call to the second function with a policy argument of launch::async | launch::deferred and the same arguments for F and Args. The second function creates a shared state that is associated with the returned future object. The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies): +- if policy & launch::async is non-zero - calls INVOKE (decay_copy (std::forward(f)), decay_copy (std::forward(args))...) (20.8.2, 30.3.1.2) as if in a new thread of exe- cution represented by a thread object with the calls to decay_copy() being evaluated in the thread that called async. Any return value is stored as the result in the shared state. Any excep- tion propagated from the execution of INVOKE(decay_copy(std::forward(f)), DECAY_- COPY (std::forward(args))...) is stored as the exceptional result in the shared state. The thread object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state. +- if policy & launch::deferred is non-zero - Stores decay_copy (std::forward(f)) and decay_copy (std::forward(args))... in the shared state. These copies of f and args constitute a deferred function. Invocation of the deferred function evaluates INVOKE (std::move(g), std::move(xyz)) where g is the stored value of decay_copy (std::forward(f)) and xyz is the stored copy of decay_copy (std::forward(args)).... The shared state is not made ready until the function has completed. The first call to a non-timed waiting function (30.6.4) on an asynchronous return object referring to this shared state shall invoke the deferred func- tion in the thread that called the waiting function. Once evaluation of INVOKE (std::move(g), std::move(xyz)) begins, the function is no longer considered deferred. + +]] + +[[Note:] [If this policy is specified together with other policies, such as when using a policy value of launch::async | launch::deferred, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.]] +[[Returns:] [An object of type __unique_future__::type(typename de- cay::type...)>::type> that refers to the shared state created by this call to async.]] + +[[Synchronization:] [Regardless of the provided policy argument, + +- the invocation of async synchronizes with (1.10) the invocation of f. (Note: This statement applies even when the corresponding future object is moved to another thread.); and +- the completion of the function f is sequenced before (1.10) the shared state is made ready. (Note: f might not be called at all, so its completion might never happen.) +If the implementation chooses the launch::async policy, +- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined; +- the associated thread completion synchronizes with (1.10) the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first. + +]] + +[[Throws:] [system_error if policy is launch::async and the implementation is unable to start a new thread. +]] + +[[Error conditions:][ + +- resource_unavailable_try_again - if policy is launch::async and the system is unable to start a new thread. +]] + +[[Remarks:] [The first signature shall not participate in overload resolution if decay::type is std:: launch. +]] + +] + +] + + + + +[endsect] + + [section:wait_for_any Non-member function `wait_for_any()`] template diff --git a/doc/futures.qbk b/doc/futures.qbk index fbc66960..5bfefb18 100755 --- a/doc/futures.qbk +++ b/doc/futures.qbk @@ -23,7 +23,8 @@ [template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]] -[def __unique_future__ [unique_future_link `boost::unique_future`]] +[def __unique_future__ [unique_future_link `future`]] +[def __unique_future `future`] [template unique_future_get_link[link_text] [link thread.synchronization.futures.reference.unique_future.get [link_text]]] [def __unique_future_get__ [unique_future_get_link `boost::unique_future::get()`]] @@ -114,7 +115,7 @@ place of the return value. } boost::packaged_task pt(calculate_the_answer_to_life_the_universe_and_everything); - boost::unique_future fi=pt.get_future(); + boost::__unique_future__ fi=pt.get_future(); boost::thread task(boost::move(pt)); // launch task on a thread @@ -132,7 +133,7 @@ future. A promise can therefore be used where the value may come from more than produce multiple values. boost::promise pi; - boost::unique_future fi; + boost::__unique_future__ fi; fi=pi.get_future(); pi.set_value(42); @@ -174,7 +175,7 @@ call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task t { boost::packaged_task task(calculate_the_answer_to_life_the_universe_and_everything); task.set_wait_callback(invoke_lazy_task); - boost::unique_future f(task.get_future()); + boost::__unique_future__ f(task.get_future()); assert(f.get()==42); } diff --git a/doc/mutex_concepts.qbk b/doc/mutex_concepts.qbk index aa33179b..57153e22 100644 --- a/doc/mutex_concepts.qbk +++ b/doc/mutex_concepts.qbk @@ -790,8 +790,10 @@ blocking.]] [section:locks Lock Types] - #include + //#include + namespace boost + { struct defer_lock_t {}; struct try_to_lock_t {}; struct adopt_lock_t {}; @@ -815,6 +817,7 @@ blocking.]] void swap(upgrade_lock & lhs, upgrade_lock & rhs); template class upgrade_to_unique_lock; + } [section:lock_tags Lock option tags] @@ -837,7 +840,7 @@ These tags are used in scoped locks constructors to specify a specific behavior. [section:lock_guard Class template `lock_guard`] - #include + //#include template class lock_guard @@ -903,7 +906,7 @@ object passed to the constructor.]] [section:unique_lock Class template `unique_lock`] - #include + //#include template class unique_lock @@ -1267,7 +1270,7 @@ __owns_lock_ref__ returns `false`.]] [section:shared_lock Class template `shared_lock`] - #include + //#include template class shared_lock @@ -1508,7 +1511,7 @@ __owns_lock_shared_ref__ returns `false`.]] [section:upgrade_lock Class template `upgrade_lock`] - #include + //#include template class upgrade_lock @@ -1663,8 +1666,10 @@ call [try_lock_ref_link `m.try_lock()`] rather than `m.lock()`. [section: reverse_mutex Class template `reverse_mutex`] - #include + //#include + namespace boost + { template class reverse_mutex { @@ -1679,6 +1684,7 @@ call [try_lock_ref_link `m.try_lock()`] rather than `m.lock()`. void lock(); void unlock(); }; + } __reverse_mutex reverse the operations of a __BasicLockable, that unlocks the lockable when `lock()` is called and locks it when `unlock()` is called. @@ -1692,17 +1698,22 @@ __reverse_mutex reverse the operations of a __BasicLockable, that unlocks the lo [section:shared_lock_guard Class template `shared_lock_guard`] - #include - + // #include + namespace boost + { template class shared_lock_guard { public: + shared_lock_guard(shared_lock_guard const&) = delete; + shared_lock_guard& operator=(shared_lock_guard const&) = delete; + explicit shared_lock_guard(SharedLockable& m_); shared_lock_guard(SharedLockable& m_,boost::adopt_lock_t); ~shared_lock_guard(); }; + } __shared_lock_guard is very simple: on construction it acquires shared ownership of the implementation of the __shared_lockable_concept__ supplied as @@ -1756,7 +1767,9 @@ obtained by a call to `m.__lock_shared()`.]] [section:reverse_lock Class template `reverse_lock`] - #include + // #include + namespace boost + { template class reverse_lock @@ -1768,6 +1781,7 @@ obtained by a call to `m.__lock_shared()`.]] explicit reverse_lock(Lock& m_); ~reverse_lock(); }; + } __reverse_lock reverse the operations of a lock: it provide for RAII-style, that unlocks the lock at construction time and lock it at destruction time. In addition, it transfer ownership temporarily, so that the mutex can not be locked using the Lock. @@ -1810,6 +1824,10 @@ An instance of __reverse_lock doesn't ['own] the lock never. [section:lock_multiple Non-member function `lock(Lockable1,Lockable2,...)`] + // #include + namespace boost + { + template void lock(Lockable1& l1,Lockable2& l2); @@ -1822,6 +1840,8 @@ An instance of __reverse_lock doesn't ['own] the lock never. template void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5); + } + [variablelist [[Effects:] [Locks the __lockable_concept_type__ objects supplied as diff --git a/doc/mutexes.qbk b/doc/mutexes.qbk index 72c22d98..d42892c9 100644 --- a/doc/mutexes.qbk +++ b/doc/mutexes.qbk @@ -131,7 +131,7 @@ implementation. If no such instance exists, `native_handle()` and `native_handle ~recursive_mutex(); void lock(); - bool try_lock(); + bool try_lock() noexcept; void unlock(); typedef platform-specific-type native_handle_type; @@ -187,7 +187,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back ~recursive_timed_mutex(); void lock(); - bool try_lock(); + bool try_lock() noexcept; void unlock(); 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/doc/tss.qbk b/doc/tss.qbk index 646c5a11..c35f05ae 100644 --- a/doc/tss.qbk +++ b/doc/tss.qbk @@ -53,8 +53,10 @@ Boost.Thread uses the address of the `thread_specific_ptr` instance as key of th [section:thread_specific_ptr Class `thread_specific_ptr`] - #include + // #include + namespace boost + { template class thread_specific_ptr { @@ -70,6 +72,7 @@ Boost.Thread uses the address of the `thread_specific_ptr` instance as key of th T* release(); void reset(T* new_value=0); }; + } [section:default_constructor `thread_specific_ptr();`] 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/future.hpp b/include/boost/thread/future.hpp index ab3ae76c..5349a015 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -598,7 +598,7 @@ namespace boost { for(count_type i=0;i(futures[i].future_->mutex).move(); #else locks[i]=boost::unique_lock(futures[i].future_->mutex); @@ -1412,6 +1412,8 @@ namespace boost }; + + template struct task_object: task_base @@ -1449,6 +1451,34 @@ namespace boost } }; + template + struct task_object: + task_base + { + private: + task_object(task_object&); + public: + R (*f)(); + task_object(R (*f_)()): + f(f_) + {} + void do_run() + { + try + { + this->mark_finished_with_result(f()); + } + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + template struct task_object: task_base @@ -1488,6 +1518,35 @@ namespace boost } }; + template<> + struct task_object: + task_base + { + private: + task_object(task_object&); + public: + void (*f)(); + task_object(void (*f_)()): + f(f_) + {} + void do_run() + { + try + { + f(); + this->mark_finished_with_result(); + } + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + } template @@ -1666,15 +1725,46 @@ namespace boost BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task BOOST_THREAD_DCL_MOVABLE_END + + template + BOOST_THREAD_FUTURE + async(launch policy, R(*f)()) + { + if (int(policy) & int(launch::async)) + { + packaged_task pt( f ); + + BOOST_THREAD_FUTURE ret = pt.get_future(); + boost::thread( boost::move(pt) ).detach(); + return ::boost::move(ret); + } + else if (int(policy) & int(launch::deferred)) + { + packaged_task pt( f ); + + BOOST_THREAD_FUTURE ret = pt.get_future(); + return ::boost::move(ret); + } else { + BOOST_THREAD_FUTURE ret; + return ::boost::move(ret); + } + } + + template + BOOST_THREAD_FUTURE + async(R(*f)()) + { + return async(launch::any, f); + } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template - BOOST_THREAD_FUTURE::type> - async(launch policy, F f) + BOOST_THREAD_FUTURE::type()>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f) { - typedef typename boost::result_of::type R; - //typedef BOOST_THREAD_FUTURE future; + typedef typename boost::result_of::type()>::type R; if (int(policy) & int(launch::async)) { - packaged_task pt( f ); + packaged_task pt( boost::forward(f) ); BOOST_THREAD_FUTURE ret = pt.get_future(); boost::thread( boost::move(pt) ).detach(); @@ -1682,7 +1772,7 @@ namespace boost } else if (int(policy) & int(launch::deferred)) { - packaged_task pt( f ); + packaged_task pt( boost::forward(f) ); BOOST_THREAD_FUTURE ret = pt.get_future(); return ::boost::move(ret); @@ -1691,15 +1781,77 @@ namespace boost return ::boost::move(ret); } } - template BOOST_THREAD_FUTURE::type> - async(F f) + async(BOOST_THREAD_RV_REF(F) f) { - return async(launch::any, f); + return async(launch::any, boost::forward(f)); + } +#else + +// template +// BOOST_THREAD_FUTURE::type()>::type> +// async(launch policy, F const& f) +// { +// typedef typename boost::result_of::type()>::type R; +// if (int(policy) & int(launch::async)) +// { +// packaged_task pt( f ); +// +// BOOST_THREAD_FUTURE ret = pt.get_future(); +// boost::thread( boost::move(pt) ).detach(); +// return ::boost::move(ret); +// } +// else if (int(policy) & int(launch::deferred)) +// { +// packaged_task pt( f ); +// +// BOOST_THREAD_FUTURE ret = pt.get_future(); +// return ::boost::move(ret); +// } else { +// BOOST_THREAD_FUTURE ret; +// return ::boost::move(ret); +// } +// } +// template +// BOOST_THREAD_FUTURE::type> +// async(F const& f) +// { +// return async(launch::any, f); +// } + + template + BOOST_THREAD_FUTURE::type()>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f) + { + typedef typename boost::result_of::type()>::type R; + if (int(policy) & int(launch::async)) + { + packaged_task pt( boost::forward(f) ); + + BOOST_THREAD_FUTURE ret = pt.get_future(); + boost::thread( boost::move(pt) ).detach(); + return ::boost::move(ret); + } + else if (int(policy) & int(launch::deferred)) + { + packaged_task pt( boost::forward(f) ); + + BOOST_THREAD_FUTURE ret = pt.get_future(); + return ::boost::move(ret); + } else { + BOOST_THREAD_FUTURE ret; + return ::boost::move(ret); + } + } + template + BOOST_THREAD_FUTURE::type> + async(BOOST_THREAD_FWD_REF(F) f) + { + return async(launch::any, boost::forward(f)); } - +#endif } 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/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index 22acf41f..2a6bc7da 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -110,7 +110,7 @@ namespace boost BOOST_VERIFY(!pthread_mutex_unlock(&m)); } - bool try_lock() + bool try_lock() BOOST_NOEXCEPT { int const res=pthread_mutex_trylock(&m); BOOST_ASSERT(!res || res==EBUSY); @@ -294,7 +294,7 @@ namespace boost BOOST_VERIFY(!pthread_cond_signal(&cond)); } - bool try_lock() + bool try_lock() BOOST_NOEXCEPT { boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); if(is_locked && !pthread_equal(owner,pthread_self())) 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/basic_recursive_mutex.hpp b/include/boost/thread/win32/basic_recursive_mutex.hpp index eb5ec848..890931b6 100644 --- a/include/boost/thread/win32/basic_recursive_mutex.hpp +++ b/include/boost/thread/win32/basic_recursive_mutex.hpp @@ -42,7 +42,7 @@ namespace boost mutex.destroy(); } - bool try_lock() + bool try_lock() // BOOST_NOEXCEPT { long const current_thread_id=win32::GetCurrentThreadId(); return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id); @@ -93,7 +93,7 @@ namespace boost } private: - bool try_recursive_lock(long current_thread_id) + bool try_recursive_lock(long current_thread_id) // BOOST_NOEXCEPT { if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id) { @@ -103,7 +103,7 @@ namespace boost return false; } - bool try_basic_lock(long current_thread_id) + bool try_basic_lock(long current_thread_id) // BOOST_NOEXCEPT { if(mutex.try_lock()) { 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/interlocked_read.hpp b/include/boost/thread/win32/interlocked_read.hpp index 133fb6f9..96a47dcb 100644 --- a/include/boost/thread/win32/interlocked_read.hpp +++ b/include/boost/thread/win32/interlocked_read.hpp @@ -3,13 +3,14 @@ // interlocked_read_win32.hpp // -// (C) Copyright 2005-8 Anthony Williams +// (C) Copyright 2005-8 Anthony Williams // // 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) #include +//#include #include @@ -22,25 +23,25 @@ namespace boost { namespace detail { - inline long interlocked_read_acquire(long volatile* x) + inline long interlocked_read_acquire(long volatile* x) //BOOST_NOEXCEPT { long const res=*x; _ReadWriteBarrier(); return res; } - inline void* interlocked_read_acquire(void* volatile* x) + inline void* interlocked_read_acquire(void* volatile* x) //BOOST_NOEXCEPT { void* const res=*x; _ReadWriteBarrier(); return res; } - inline void interlocked_write_release(long volatile* x,long value) + inline void interlocked_write_release(long volatile* x,long value) //BOOST_NOEXCEPT { _ReadWriteBarrier(); *x=value; } - inline void interlocked_write_release(void* volatile* x,void* value) + inline void interlocked_write_release(void* volatile* x,void* value) //BOOST_NOEXCEPT { _ReadWriteBarrier(); *x=value; @@ -54,19 +55,19 @@ namespace boost { namespace detail { - inline long interlocked_read_acquire(long volatile* x) + inline long interlocked_read_acquire(long volatile* x) //BOOST_NOEXCEPT { return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0); } - inline void* interlocked_read_acquire(void* volatile* x) + inline void* interlocked_read_acquire(void* volatile* x) //BOOST_NOEXCEPT { return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0); } - inline void interlocked_write_release(long volatile* x,long value) + inline void interlocked_write_release(long volatile* x,long value) //BOOST_NOEXCEPT { BOOST_INTERLOCKED_EXCHANGE(x,value); } - inline void interlocked_write_release(void* volatile* x,void* value) + inline void interlocked_write_release(void* volatile* x,void* value) //BOOST_NOEXCEPT { BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value); } 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/sync/futures/async/async_pass.cpp b/test/sync/futures/async/async_pass.cpp index dee44a6a..f38799b6 100644 --- a/test/sync/futures/async/async_pass.cpp +++ b/test/sync/futures/async/async_pass.cpp @@ -33,6 +33,41 @@ typedef boost::chrono::high_resolution_clock Clock; typedef boost::chrono::milliseconds ms; +class A +{ + long data_; + +public: + typedef int result_type; + + explicit A(long i) : data_(i) {} + + long operator()() const + { + boost::this_thread::sleep_for(ms(200)); + return data_; + } +}; + +class MoveOnly +{ +public: + typedef int result_type; + + BOOST_THREAD_MOVABLE_ONLY(MoveOnly) + MoveOnly() + { + } + MoveOnly(BOOST_THREAD_RV_REF(MoveOnly)) + {} + + int operator()() + { + boost::this_thread::sleep_for(ms(200)); + return 3; + } +}; + int f0() { boost::this_thread::sleep_for(ms(200)); @@ -58,11 +93,14 @@ boost::interprocess::unique_ptr > f3(int i) return boost::interprocess::unique_ptr >(new int(i)); } -//boost::interprocess::unique_ptr > f4(boost::interprocess::unique_ptr >&& p) -//{ -// boost::this_thread::sleep_for(ms(200)); -// return boost::move(p); -//} +typedef boost::interprocess::unique_ptr > XXT; +boost::interprocess::unique_ptr > f4( + BOOST_THREAD_RV_REF(boost::interprocess::unique_ptr > ) p) +{ + boost::this_thread::sleep_for(ms(200)); + return boost::move(p); +} + int main() { @@ -82,6 +120,22 @@ int main() Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); } + { + boost::future f = boost::async(boost::launch::async, A(3)); + boost::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + BOOST_TEST(f.get() == 3); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 < ms(100)); + } + { + boost::future f = boost::async(boost::launch::async, BOOST_THREAD_MAKE_RV_REF(MoveOnly())); + boost::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + BOOST_TEST(f.get() == 3); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 < ms(100)); + } { boost::future f = boost::async(boost::launch::any, f0); boost::this_thread::sleep_for(ms(300)); 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