From 566199e49bfefc067b8472dca4e4c212a7ca4b40 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 1 Mar 2015 18:37:16 +0100 Subject: [PATCH 01/23] Added this_executor and default_executor examples. --- example/default_executor.cpp | 61 +++++++++++++++++++++++++ example/this_executor.cpp | 86 ++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 example/default_executor.cpp create mode 100644 example/this_executor.cpp diff --git a/example/default_executor.cpp b/example/default_executor.cpp new file mode 100644 index 00000000..ccdb3876 --- /dev/null +++ b/example/default_executor.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2014 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) + +#include +#if ! defined BOOST_NO_CXX11_DECLTYPE +#define BOOST_RESULT_OF_USE_DECLTYPE +#endif + +#define BOOST_THREAD_VERSION 4 +#define BOOST_THREAD_PROVIDES_EXECUTORS +//#define BOOST_THREAD_USES_LOG +#define BOOST_THREAD_USES_LOG_THREAD_ID +#define BOOST_THREAD_QUEUE_DEPRECATE_OLD + +#include +#include +#include +#include +#include + +#include + + +boost::generic_executor_ref default_executor() +{ + static boost::basic_thread_pool tp(4); + return boost::generic_executor_ref(tp); +} + +void p2() +{ + std::cout << BOOST_CONTEXTOF << std::endl; + boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); + std::cout << BOOST_CONTEXTOF << std::endl; +} + + +void p1() +{ + std::cout << BOOST_CONTEXTOF << std::endl; + boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); + default_executor().submit(&p2); + boost::this_thread::sleep_for(boost::chrono::milliseconds(400)); + std::cout << BOOST_CONTEXTOF << std::endl; +} + +int main() +{ + std::cout << BOOST_CONTEXTOF << std::endl; + + default_executor().submit(&p1); + + boost::this_thread::sleep_for(boost::chrono::seconds(5)); + + std::cout << BOOST_CONTEXTOF << std::endl; + + return 1; + +} diff --git a/example/this_executor.cpp b/example/this_executor.cpp new file mode 100644 index 00000000..feeebf85 --- /dev/null +++ b/example/this_executor.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2014 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) + +#include +#if ! defined BOOST_NO_CXX11_DECLTYPE +#define BOOST_RESULT_OF_USE_DECLTYPE +#endif + +#define BOOST_THREAD_VERSION 4 +#define BOOST_THREAD_PROVIDES_EXECUTORS +#define BOOST_THREAD_USES_LOG_THREAD_ID + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct current_executor_state_type { + boost::shared_ptr current_executor_ptr; + + template + void set_current_executor(Executor& ex) + { + current_executor_ptr = boost::make_shared(ex); + } + boost::generic_executor_ref current_executor() + { + if (current_executor_ptr) + return *current_executor_ptr; + else + throw ""; + } +}; + +thread_local current_executor_state_type current_executor_state; + +boost::generic_executor_ref current_executor() +{ + return current_executor_state.current_executor(); +} + +void p2() +{ + std::cout << BOOST_CONTEXTOF << std::endl; + boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); + std::cout << BOOST_CONTEXTOF << std::endl; +} + + +void p1() +{ + std::cout << BOOST_CONTEXTOF << std::endl; + boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); + current_executor().submit(&p2); + boost::this_thread::sleep_for(boost::chrono::milliseconds(400)); + std::cout << BOOST_CONTEXTOF << std::endl; +} + +int main() +{ + std::cout << BOOST_CONTEXTOF << std::endl; + + boost::basic_thread_pool tp(4, + // at_thread_entry + [](boost::basic_thread_pool& pool) + { + current_executor_state.set_current_executor(pool); + } + ); + + tp.submit(&p1); + + boost::this_thread::sleep_for(boost::chrono::seconds(5)); + + std::cout << BOOST_CONTEXTOF << std::endl; + + return 1; + +} From 0653efff3d83494d78a615f6239b2fbc26ab6663 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 1 Mar 2015 18:53:11 +0100 Subject: [PATCH 02/23] Added this_executor and default_executor examples. --- doc/async_executors.qbk | 26 ++++++++------------------ test/Jamfile.v2 | 2 ++ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/doc/async_executors.qbk b/doc/async_executors.qbk index ea6ef7bc..c9311bdd 100644 --- a/doc/async_executors.qbk +++ b/doc/async_executors.qbk @@ -319,33 +319,23 @@ The reason is that the user can always use a thread_local variable and reset it } ); +[ [heading Default executor] The library authors share some of the concerns of the C++ standard committee (introduction of a new single shared resource, a singleton, could make it difficult to make it portable to all the environments) and that this library doesn't need to provide a default executor for the time been. -The user can always define his default executor himself and use the `at_thread_entry ` member function to set the default constructor. +The user can always define his default executor himself. - thread_local default_executor_state_type default_executor_state; - executor* default_executor() { return default_executor_state.default_executor(); } - - // in main - MyDefaultExecutor myDefaultExecutor( - // at_thread_entry - [](MyDefaultExecutor& ex) { - default_executor_state.set_default_executor(ex); - } - ); - - basic_thread_pool pool( - // at_thread_entry - [&myDefaultExecutor](basic_thread_pool& pool) { - default_executor_state.set_default_executor(myDefaultExecutor); - } - ); + boost::generic_executor_ref default_executor() + { + static boost::basic_thread_pool tp(4); + return generic_executor_ref(tp); + } [endsect] + [/////////////////////] [section:ref Reference] diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index cb28bf7f..22f52650 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -950,6 +950,8 @@ rule thread-compile ( sources : reqs * : name ) explicit ts_ ; test-suite ts_ : + [ thread-run2 ../example/this_executor.cpp : ex_this_executor ] + [ thread-run2 ../example/default_executor.cpp : ex_default_executor ] ; } From af1c7d0c261164fa147807ecdb997a0fd49c5e9e Mon Sep 17 00:00:00 2001 From: Wojciech Mamrak Date: Tue, 3 Mar 2015 19:03:18 +0100 Subject: [PATCH 03/23] Fixed documentation bugs. --- doc/external_locking.qbk | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/external_locking.qbk b/doc/external_locking.qbk index a485f363..9c7b1ee4 100644 --- a/doc/external_locking.qbk +++ b/doc/external_locking.qbk @@ -98,7 +98,7 @@ or inheriting from a class which add these lockable functions. The `basic_lockable_adapter` class helps to define the `BankAccount` class as class BankAccount - : public basic_lockable_adapter + : public basic_lockable_adapter { int balance_; public: @@ -138,7 +138,7 @@ Notice that now acct is being locked by Withdraw after it has already been locke As `boost::mutex` is not recursive, we need to use its recursive version `boost::recursive_mutex`. class BankAccount - : public basic_lockable_adapter + : public basic_lockable_adapter { // ... @@ -147,7 +147,7 @@ As `boost::mutex` is not recursive, we need to use its recursive version `boost: The caller-ensured locking approach is more flexible and the most efficient, but very dangerous. In an implementation using caller-ensured locking, BankAccount still holds a mutex, but its member functions don't manipulate it at all. Deposit and Withdraw are not thread-safe anymore. Instead, the client code is responsible for locking BankAccount properly. class BankAccount - : public basic_lockable_adapter { + : public basic_lockable_adapter { int balance_; public: void Deposit(int amount) { @@ -271,7 +271,7 @@ Now that we have such a strict `strict_lock`, how do we harness its power in def A little code is worth 1,000 words, a (hacked into) saying goes, so here's the new BankAccount class: class BankAccount - : public basic_lockable_adapter + : public basic_lockable_adapter { int balance_; public: @@ -280,7 +280,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n balance_ += amount; } void Deposit(int amount) { - strict_lock guard(*this); // Internally locked + strict_lock guard(*this); // Internally locked Deposit(amount, guard); } void Withdraw(int amount, strict_lock&) { @@ -288,7 +288,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n balance_ -= amount; } void Withdraw(int amount) { - strict_lock guard(*this); // Internally locked + strict_lock guard(*this); // Internally locked Withdraw(amount, guard); } }; @@ -327,7 +327,7 @@ The scheme is useful because the likelihood of a programmer forgetting about any Using `strict_lock` permits compile-time checking of the most common source of errors, and runtime checking of the less frequent problem. Let's see how to enforce that the appropriate BankAccount object is locked. First, we need to add a member function to the `strict_lock` class template. -The `bool strict_lock::owns_lock(Loclable*)` function returns a reference to the locked object. +The `bool strict_lock::owns_lock(Lockable*)` function returns a reference to the locked object. template class strict_lock { ... as before ... @@ -338,7 +338,7 @@ The `bool strict_lock::owns_lock(Loclable*)` function returns a reference to Second, BankAccount needs to use this function compare the locked object against this: class BankAccount { - : public basic_lockable_adapter + : public basic_lockable_adapter int balance_; public: void Deposit(int amount, strict_lock& guard) { @@ -403,7 +403,7 @@ The solution is to use a little bridge template `externally_locked` that control T& get(strict_lock& lock) { #ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED - if (!lock.owns_lock(&lockable_)) throw lock_error(); run time check throw if not locks the same + if (!lock.owns_lock(&lockable_)) throw lock_error(); //run time check throw if not locks the same #endif return obj_; } @@ -421,10 +421,10 @@ The solution is to use a little bridge template `externally_locked` that control Instead of making `checkingAcct_` and `savingsAcct_` of type `BankAccount`, `AccountManager` holds objects of type `externally_locked`: class AccountManager - : public basic_lockable_adapter + : public basic_lockable_adapter { public: - typedef basic_lockable_adapter lockable_base_type; + typedef basic_lockable_adapter lockable_base_type; AccountManager() : checkingAcct_(*this) , savingsAcct_(*this) @@ -498,7 +498,7 @@ Now we need to state that both classes are `strict_lock`s. Well let me show what this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function. -First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction it will restore the ownership. Note the use of `lock_traits` and that the `Locker` needs to have a reference to the mutex otherwise and exception is thrown. +First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction it will restore the ownership. Note the use of `lock_traits` and that the `Locker` needs to have a reference to the mutex otherwise an exception is thrown. template class nested_strict_lock @@ -510,7 +510,7 @@ First `nested_strict_lock` class will store on a temporary lock the `Locker`, an nested_strict_lock(Locker& lock) : lock_(lock) // Store reference to locker - , tmp_lock_(lock.move()) // Move ownership to temporaty locker + , tmp_lock_(lock.move()) // Move ownership to temporary locker { #ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED if (tmp_lock_.mutex()==0) { From 946fac633ec5a0f919b0418b0b28b43ca57af80e Mon Sep 17 00:00:00 2001 From: Wojciech Mamrak Date: Wed, 4 Mar 2015 12:22:33 +0100 Subject: [PATCH 04/23] Fixed documentation bugs. --- doc/mutex_concepts.qbk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/mutex_concepts.qbk b/doc/mutex_concepts.qbk index 78ec5884..825d22c2 100644 --- a/doc/mutex_concepts.qbk +++ b/doc/mutex_concepts.qbk @@ -2664,7 +2664,7 @@ Only the specificities respect to __Lockable are described here. [endsect] [///////////////////////////////] -[section:get2 `get(strict_lock>&)`] +[section:get2 `get(nested_strict_lock&)`] template T& get(nested_strict_lock& lk); @@ -2684,7 +2684,7 @@ Only the specificities respect to __Lockable are described here. [endsect] [///////////////////////////////] -[section:get3 `get(strict_lock>&)`] +[section:get3 `get(Lock&)`] template T& get(Lock& lk); @@ -2826,7 +2826,7 @@ Only the specificities respect to __Lockable are described here. [endsect] [///////////////////////////////] -[section:get2 `get(strict_lock>&)`] +[section:get2 `get(nested_strict_lock&)`] template T& get(nested_strict_lock& lk); @@ -2846,7 +2846,7 @@ Only the specificities respect to __Lockable are described here. [endsect] [///////////////////////////////] -[section:get3 `get(strict_lock>&)`] +[section:get3 `get(Lock&)`] template T& get(Lock& lk); From 9fc06a87418af20d6024b8bd6b788ee22031919e Mon Sep 17 00:00:00 2001 From: Wojciech Mamrak Date: Thu, 5 Mar 2015 12:37:10 +0100 Subject: [PATCH 05/23] Fixed documentation bugs. --- doc/synchronized_value_ref.qbk | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/synchronized_value_ref.qbk b/doc/synchronized_value_ref.qbk index 20b304c8..2826282e 100644 --- a/doc/synchronized_value_ref.qbk +++ b/doc/synchronized_value_ref.qbk @@ -88,9 +88,9 @@ typedef T value_type; typedef Lockable mutex_type; - synchronized_value() noexept(is_nothrow_default_constructible::value); - synchronized_value(T const& other) noexept(is_nothrow_copy_constructible::value); - synchronized_value(T&& other) noexept(is_nothrow_move_constructible::value); + synchronized_value() noexcept(is_nothrow_default_constructible::value); + synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible::value); + synchronized_value(T&& other) noexcept(is_nothrow_move_constructible::value); synchronized_value(synchronized_value const& rhs); synchronized_value(synchronized_value&& other); @@ -129,7 +129,7 @@ [section:constructor `synchronized_value()`] - synchronized_value() noexept(is_nothrow_default_constructible::value); + synchronized_value() noexcept(is_nothrow_default_constructible::value); [variablelist @@ -145,7 +145,7 @@ [section:constructor_vt `synchronized_value(T const&)`] - synchronized_value(T const& other) noexept(is_nothrow_copy_constructible::value); + synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible::value); [variablelist @@ -175,11 +175,11 @@ [section:move_vt `synchronized_value(T&&)`] - synchronized_value(T&& other) noexept(is_nothrow_move_constructible::value); + synchronized_value(T&& other) noexcept(is_nothrow_move_constructible::value); [variablelist -[[Requires:] [`T` is `CopyMovable `.]] +[[Requires:] [`T` is `MoveConstructible `.]] [[Effects:] [Move constructs the cloaked value_type]] [[Throws:] [Any exception thrown by `value_type(value_type&&)`.]] @@ -194,7 +194,7 @@ [variablelist -[[Requires:] [`T` is `CopyMovable `.]] +[[Requires:] [`T` is `MoveConstructible `.]] [[Effects:] [Move constructs the cloaked value_type]] [[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]] @@ -209,7 +209,7 @@ [variablelist -[[Requires:] [`T` is `Assignale`.]] +[[Requires:] [`T` is `Assignable`.]] [[Effects:] [Copies the underlying value on a scope protected by the two mutexes. The mutex is not copied. The locks are acquired avoiding deadlock. For example, there is no problem if one thread assigns `a = b` and the other assigns `b = a`.]] [[Return:] [`*this`]] @@ -224,7 +224,7 @@ [variablelist -[[Requires:] [`T` is `Assignale`.]] +[[Requires:] [`T` is `Assignable`.]] [[Effects:] [Copies the value on a scope protected by the mutex.]] [[Return:] [`*this`]] @@ -273,7 +273,7 @@ [variablelist -[[Requires:] [`T` is `Assignale`.]] +[[Requires:] [`T` is `Assignable`.]] [[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]] [[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]] From 17d802db817f65b7f8711e3ce60bc908ac599b68 Mon Sep 17 00:00:00 2001 From: Wojciech Mamrak Date: Thu, 5 Mar 2015 13:22:04 +0100 Subject: [PATCH 06/23] Fixed documentation bugs. --- doc/sync_queues_ref.qbk | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/sync_queues_ref.qbk b/doc/sync_queues_ref.qbk index a46f34fc..b5f20fd2 100644 --- a/doc/sync_queues_ref.qbk +++ b/doc/sync_queues_ref.qbk @@ -181,7 +181,7 @@ where [variablelist -[[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety.]] +[[Requires:] [Q::value_type is no throw move constructible. This is needed to ensure the exception safety.]] [[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element.]] @@ -206,7 +206,7 @@ where [variablelist -[/[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety. ]] +[/[Requires:] [Q::value_type is no throw move assignable. This is needed to ensure the exception safety. ]] [[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element into a shared_ptr.]] @@ -314,7 +314,7 @@ where [variablelist -[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]] +[[Effects:] [If the queue is not empty pulls the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]] [[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]] @@ -393,7 +393,7 @@ where [endsect] [/////////////////////////////////////] -[section:nonblocking_push_back_m `s = q.nonblocking_push_back(rve());`] +[section:nonblocking_push_back_m `s = q.nonblocking_push_back(rve);`] [variablelist @@ -427,7 +427,7 @@ where [variablelist -[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]] +[[Effects:] [If the queue is not empty pulls the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]] [[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]] From b678edb0d837b046777d95fc3515b7b6d0d37e94 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 8 Mar 2015 23:31:37 +0100 Subject: [PATCH 07/23] update history. --- doc/changes.qbk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index a5ce8496..9150a77f 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -15,6 +15,7 @@ * [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV. * [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available * [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back + * [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue * [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task * [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used @@ -25,7 +26,6 @@ * [@http://svn.boost.org/trac/boost/ticket/10685 #10685] mfc_thread_init.hpp does not compile. * [@http://svn.boost.org/trac/boost/ticket/10942 #10942] Boost.Thread fails to build on Cygwin. * [@http://svn.boost.org/trac/boost/ticket/10967 #10967] Timed wait points inconsistently convert relative to absolute waits. -* [@http://svn.boost.org/trac/boost/ticket/10968 #10968] The futures returned by async() and future::then() are not blocking. Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state. @@ -44,10 +44,12 @@ There are some severe bugs that prevent the use of the library on concrete conte * [@http://svn.boost.org/trac/boost/ticket/9600 #9600] Async: Add task_region * [@http://svn.boost.org/trac/boost/ticket/10611 #10611] Add emplace promise::set_value and emplace make_ready_future * [@http://svn.boost.org/trac/boost/ticket/10826 #10826] Add scheduled executor operations +* [@http://svn.boost.org/trac/boost/ticket/11048 #11048] Add a serial_executor based on continuations [*Fixed Bugs:] +* [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back * [@http://svn.boost.org/trac/boost/ticket/10734 #10734] Submit method work differently on different executors, some throw exception and some silently ignore error (thread_executor and inline_executor) * [@http://svn.boost.org/trac/boost/ticket/10736 #10736] Task exceptions silently ignored. I think std::terminate solution from N3785 and std::thread is better choice and more consistent. * [@http://svn.boost.org/trac/boost/ticket/10737 #10737] In serial_executor we have infinite wait if task throw exception. @@ -55,9 +57,13 @@ There are some severe bugs that prevent the use of the library on concrete conte * [@http://svn.boost.org/trac/boost/ticket/10824 #10824] Boost.Thread 1.57 breaks Windows XP compatibility for SP2 and below. * [@http://svn.boost.org/trac/boost/ticket/10963 #10963] future>::then Has No Implementation * [@http://svn.boost.org/trac/boost/ticket/10964 #10964] future>::unwrap().then() Deadlocks +* [@http://svn.boost.org/trac/boost/ticket/10968 #10968] The futures returned by async() and future::then() are not blocking. * [@http://svn.boost.org/trac/boost/ticket/10971 #10971] shared_future::get()/get_or() must be const * [@http://svn.boost.org/trac/boost/ticket/10972 #10972] shared_future::then() can be called multiple times. * [@http://svn.boost.org/trac/boost/ticket/10979 #10979] Support T& type deduction when the make_ready_future parameter is reference_wrapper +* [@http://svn.boost.org/trac/boost/ticket/10996 #10996] Thread physical_concurrency() is failing on Windows +* [@http://svn.boost.org/trac/boost/ticket/11035 #11035] BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE not defined for Android +* [@http://svn.boost.org/trac/boost/ticket/11053 #11053] The attached code results in a R6025 - pure virtual function call in run_thread_exit_callbacks [heading Version 4.4.0 - boost 1.57] @@ -76,6 +82,7 @@ There are some severe bugs that prevent the use of the library on concrete conte * [@http://svn.boost.org/trac/boost/ticket/10537 #10537] Application crash on throw exception * [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler + Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state. Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot. From d7721940f39198705b298beb772f204f97844aca Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Mon, 9 Mar 2015 23:17:35 +0100 Subject: [PATCH 08/23] update history. --- doc/changes.qbk | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 9150a77f..e158388b 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -14,30 +14,28 @@ * [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV. * [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available -* [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back - -* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue * [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task * [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used * [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11 * [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0 -* [@http://svn.boost.org/trac/boost/ticket/9856 #9856] [windows] condition_variable::wait_for returns wrong cv_status on timeout. +* [@http://svn.boost.org/trac/boost/ticket/10942 #10942] Boost.Thread fails to build on Cygwin. + +[/ +* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue * [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler. * [@http://svn.boost.org/trac/boost/ticket/10685 #10685] mfc_thread_init.hpp does not compile. -* [@http://svn.boost.org/trac/boost/ticket/10942 #10942] Boost.Thread fails to build on Cygwin. * [@http://svn.boost.org/trac/boost/ticket/10967 #10967] Timed wait points inconsistently convert relative to absolute waits. +] Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state. -Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot. +Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last regression test snapshot. [*Sever limitations:] There are some severe bugs that prevent the use of the library on concrete contexts, in particular: * on thread specific storage that prevent the library to be used with dynamic libraries ( [@http://svn.boost.org/trac/boost/ticket/3926 #3926], ), -* timed operation on windows are inconsistent ( [@http://svn.boost.org/trac/boost/ticket/9856 #9856], [@http://svn.boost.org/trac/boost/ticket/10967 #10967]). -* The futures returned by async() and future::then() are not blocking ([@http://svn.boost.org/trac/boost/ticket/10968 #10968]). [*New Experimental Features:] @@ -48,7 +46,6 @@ There are some severe bugs that prevent the use of the library on concrete conte [*Fixed Bugs:] - * [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back * [@http://svn.boost.org/trac/boost/ticket/10734 #10734] Submit method work differently on different executors, some throw exception and some silently ignore error (thread_executor and inline_executor) * [@http://svn.boost.org/trac/boost/ticket/10736 #10736] Task exceptions silently ignored. I think std::terminate solution from N3785 and std::thread is better choice and more consistent. From dcebe26a114263fbd7c87a50641b6378048a4dc4 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Tue, 10 Mar 2015 00:47:38 +0100 Subject: [PATCH 09/23] try to get rid of possible deadlock. --- include/boost/thread/future.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index efc57b04..e6e22363 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -4892,7 +4892,9 @@ namespace detail make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f) { shared_ptr > h(new future_unwrap_shared_state(boost::move(f))); + lock.lock(); h->parent.future_->set_continuation_ptr(h, lock); + lock.unlock(); return BOOST_THREAD_FUTURE(h); } } @@ -4907,6 +4909,7 @@ namespace detail { BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); + lock.unlock(); return boost::detail::make_future_unwrap_shared_state >, R2>(lock, boost::move(*this)); } #endif From ec6a1fcf803b872c2841fa8fc43a2f44066491c2 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Tue, 10 Mar 2015 00:48:12 +0100 Subject: [PATCH 10/23] try to get rid of data race. --- src/pthread/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 75969f72..bbd25493 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -159,7 +159,7 @@ namespace boost static void* thread_proxy(void* param) { boost::detail::thread_data_ptr thread_info = static_cast(param)->self; - thread_info->self.reset(); + //thread_info->self.reset(); detail::set_current_thread_data(thread_info.get()); #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS BOOST_TRY From 331f0b9325e9321fba9a10ec8f1dcd9fc87b1aa1 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Tue, 10 Mar 2015 07:54:09 +0100 Subject: [PATCH 11/23] Added test for future::get_or. --- test/sync/futures/future/get_or_pass.cpp | 87 ++++++++++++------------ 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/test/sync/futures/future/get_or_pass.cpp b/test/sync/futures/future/get_or_pass.cpp index a2bd6522..64409455 100644 --- a/test/sync/futures/future/get_or_pass.cpp +++ b/test/sync/futures/future/get_or_pass.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #if defined BOOST_THREAD_USES_CHRONO @@ -128,49 +129,49 @@ int main() BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; } } -// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; -// { -// typedef int& T; -// { -// boost::promise p; -// boost::future f = p.get_future(); -//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) -// boost::thread(func3, boost::move(p)).detach(); -//#else -// int j=5; -// p.set_value(j); -//#endif -// BOOST_TEST(f.valid()); -// int k=4; -// BOOST_TEST(f.get_or(k) == 5); -//#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET -// BOOST_TEST(!f.valid()); -//#endif -// } -// BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; -// { -// boost::promise p; -// boost::future f = p.get_future(); -//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) -// boost::thread(func4, boost::move(p)).detach(); -//#else -// p.set_exception(boost::make_exception_ptr(3.5)); -//#endif -// try -// { -// BOOST_TEST(f.valid()); -// int j=4; -// BOOST_TEST(f.get_or(j) == 4); -// } -// catch (...) -// { -// BOOST_TEST(false); -// } -//#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET -// BOOST_TEST(!f.valid()); -//#endif -// } -// } + BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; + { + typedef int& T; + { + boost::promise p; + boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func3, boost::move(p)).detach(); +#else + int j=5; + p.set_value(j); +#endif + BOOST_TEST(f.valid()); + int k=4; + BOOST_TEST(f.get_or(boost::ref(k)) == 5); +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + BOOST_TEST(!f.valid()); +#endif + } + BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; + { + boost::promise p; + boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func4, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(3.5)); +#endif + try + { + BOOST_TEST(f.valid()); + int j=4; + BOOST_TEST(f.get_or(boost::ref(j)) == 4); + } + catch (...) + { + BOOST_TEST(false); + } +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + BOOST_TEST(!f.valid()); +#endif + } + } BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; From e989d2f626daa655271611ae0950aff3adf833cf Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Thu, 12 Mar 2015 04:08:42 +0100 Subject: [PATCH 12/23] Add comments. --- include/boost/thread/pthread/thread_data.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 8c22bda5..dc8ba0fb 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -115,8 +115,13 @@ namespace boost boost::detail::thread_exit_callback_node* thread_exit_callbacks; std::map tss_data; +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. + // Another option is to have them always pthread_mutex_t* cond_mutex; pthread_cond_t* current_cond; +//#endif typedef std::vector //, hidden_allocator > > notify_list_t; @@ -136,8 +141,10 @@ namespace boost thread_handle(0), done(false),join_started(false),joined(false), thread_exit_callbacks(0), +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS cond_mutex(0), current_cond(0), +//#endif notify(), async_states_() //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS From 82b9a4e28c7c95f1086671bef56d7a93f5fb0631 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Thu, 12 Mar 2015 04:09:34 +0100 Subject: [PATCH 13/23] Use coherently size_type. --- doc/sync_queues_ref.qbk | 16 +++---- .../concurrent_queues/deque_adaptor.hpp | 14 +++--- .../thread/concurrent_queues/deque_base.hpp | 44 +++++++++---------- .../detail/sync_deque_base.hpp | 2 +- .../detail/sync_queue_base.hpp | 2 +- .../concurrent_queues/queue_adaptor.hpp | 14 +++--- .../thread/concurrent_queues/queue_base.hpp | 42 +++++++++--------- .../concurrent_queues/sync_priority_queue.hpp | 3 +- 8 files changed, 69 insertions(+), 68 deletions(-) diff --git a/doc/sync_queues_ref.qbk b/doc/sync_queues_ref.qbk index b5f20fd2..eba795fc 100644 --- a/doc/sync_queues_ref.qbk +++ b/doc/sync_queues_ref.qbk @@ -636,12 +636,12 @@ Closed queues add the following valid expressions namespace boost { - template + template class queue_base { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base() {}; @@ -671,7 +671,7 @@ Closed queues add the following valid expressions virtual queue_op_status wait_push_back(const value_type& x) = 0; virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_pull_front(value_type& elem) = 0; }; } @@ -685,11 +685,11 @@ Closed queues add the following valid expressions namespace boost { template - class queue_adaptor : public queue_base + class queue_adaptor : public queue_base { public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -1002,13 +1002,13 @@ Closed queues add the following valid expressions namespace boost { - template + template > class sync_queue { public: typedef ValueType value_type; - typedef csbl::deque underlying_queue_type; - typedef std::size_t size_type; + typedef Container underlying_queue_type; + typedef typename Container::size_type size_type; sync_queue(sync_queue const&) = delete; sync_queue& operator=(sync_queue const&) = delete; diff --git a/include/boost/thread/concurrent_queues/deque_adaptor.hpp b/include/boost/thread/concurrent_queues/deque_adaptor.hpp index b9f8c950..a8f45f86 100644 --- a/include/boost/thread/concurrent_queues/deque_adaptor.hpp +++ b/include/boost/thread/concurrent_queues/deque_adaptor.hpp @@ -27,12 +27,12 @@ namespace detail template class deque_adaptor_copyable_only : - public boost::deque_base + public boost::deque_base { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors deque_adaptor_copyable_only() {} @@ -63,12 +63,12 @@ namespace detail }; template class deque_adaptor_movable_only : - public boost::deque_base + public boost::deque_base { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -102,12 +102,12 @@ namespace detail template class deque_adaptor_copyable_and_movable : - public boost::deque_base + public boost::deque_base { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -195,7 +195,7 @@ namespace detail { public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors virtual ~deque_adaptor() {}; }; diff --git a/include/boost/thread/concurrent_queues/deque_base.hpp b/include/boost/thread/concurrent_queues/deque_base.hpp index 61b256b5..f76e8a76 100644 --- a/include/boost/thread/concurrent_queues/deque_base.hpp +++ b/include/boost/thread/concurrent_queues/deque_base.hpp @@ -27,12 +27,12 @@ namespace concurrent namespace detail { - template + template class deque_base_copyable_only { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~deque_base_copyable_only() {}; @@ -58,16 +58,16 @@ namespace detail virtual queue_op_status nonblocking_pull_front(value_type&) = 0; virtual queue_op_status wait_push_back(const value_type& x) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_pull_front(value_type& elem) = 0; }; - template + template class deque_base_movable_only { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~deque_base_movable_only() {}; @@ -88,7 +88,7 @@ namespace detail virtual queue_op_status nonblocking_pull_front(value_type&) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_pull_front(value_type& elem) = 0; virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; @@ -97,12 +97,12 @@ namespace detail }; - template + template class deque_base_copyable_and_movable { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~deque_base_copyable_and_movable() {}; @@ -129,7 +129,7 @@ namespace detail virtual queue_op_status nonblocking_pull_front(value_type&) = 0; virtual queue_op_status wait_push_back(const value_type& x) = 0; - virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + virtual queue_op_status wait_pull_front(value_type& elem) = 0; virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; @@ -137,7 +137,7 @@ namespace detail virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; }; - template struct deque_base; - template - struct deque_base { - typedef deque_base_copyable_and_movable type; + template + struct deque_base { + typedef deque_base_copyable_and_movable type; }; - template - struct deque_base { - typedef deque_base_copyable_only type; + template + struct deque_base { + typedef deque_base_copyable_only type; }; - template - struct deque_base { - typedef deque_base_movable_only type; + template + struct deque_base { + typedef deque_base_movable_only type; }; } - template + template class deque_base : - public detail::deque_base::type + public detail::deque_base::type { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~deque_base() {}; }; diff --git a/include/boost/thread/concurrent_queues/detail/sync_deque_base.hpp b/include/boost/thread/concurrent_queues/detail/sync_deque_base.hpp index 0cc8417d..877e1e2e 100644 --- a/include/boost/thread/concurrent_queues/detail/sync_deque_base.hpp +++ b/include/boost/thread/concurrent_queues/detail/sync_deque_base.hpp @@ -37,7 +37,7 @@ namespace detail public: typedef ValueType value_type; typedef Queue underlying_queue_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; typedef queue_op_status op_status; typedef typename chrono::steady_clock clock; diff --git a/include/boost/thread/concurrent_queues/detail/sync_queue_base.hpp b/include/boost/thread/concurrent_queues/detail/sync_queue_base.hpp index 2ca314bf..653e273f 100644 --- a/include/boost/thread/concurrent_queues/detail/sync_queue_base.hpp +++ b/include/boost/thread/concurrent_queues/detail/sync_queue_base.hpp @@ -37,7 +37,7 @@ namespace detail public: typedef ValueType value_type; typedef Queue underlying_queue_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; typedef queue_op_status op_status; typedef typename chrono::steady_clock clock; diff --git a/include/boost/thread/concurrent_queues/queue_adaptor.hpp b/include/boost/thread/concurrent_queues/queue_adaptor.hpp index 8d01bbcd..f04e0354 100644 --- a/include/boost/thread/concurrent_queues/queue_adaptor.hpp +++ b/include/boost/thread/concurrent_queues/queue_adaptor.hpp @@ -27,12 +27,12 @@ namespace detail template class queue_adaptor_copyable_only : - public boost::queue_base + public boost::queue_base { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors queue_adaptor_copyable_only() {} @@ -63,12 +63,12 @@ namespace detail }; template class queue_adaptor_movable_only : - public boost::queue_base + public boost::queue_base { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -102,12 +102,12 @@ namespace detail template class queue_adaptor_copyable_and_movable : - public boost::queue_base + public boost::queue_base { Queue queue; public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors @@ -195,7 +195,7 @@ namespace detail { public: typedef typename Queue::value_type value_type; - typedef std::size_t size_type; + typedef typename Queue::size_type size_type; // Constructors/Assignment/Destructors virtual ~queue_adaptor() {}; }; diff --git a/include/boost/thread/concurrent_queues/queue_base.hpp b/include/boost/thread/concurrent_queues/queue_base.hpp index 3b96c825..0d428391 100755 --- a/include/boost/thread/concurrent_queues/queue_base.hpp +++ b/include/boost/thread/concurrent_queues/queue_base.hpp @@ -27,12 +27,12 @@ namespace concurrent namespace detail { - template + template class queue_base_copyable_only { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base_copyable_only() {}; @@ -62,12 +62,12 @@ namespace detail }; - template + template class queue_base_movable_only { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base_movable_only() {}; @@ -88,7 +88,7 @@ namespace detail virtual queue_op_status nonblocking_pull(value_type&) = 0; - virtual queue_op_status wait_pull(ValueType& elem) = 0; + virtual queue_op_status wait_pull(value_type& elem) = 0; virtual void push(BOOST_THREAD_RV_REF(value_type) x) = 0; virtual queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) = 0; @@ -97,12 +97,12 @@ namespace detail }; - template + template class queue_base_copyable_and_movable { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base_copyable_and_movable() {}; @@ -129,7 +129,7 @@ namespace detail virtual queue_op_status nonblocking_pull(value_type&) = 0; virtual queue_op_status wait_push(const value_type& x) = 0; - virtual queue_op_status wait_pull(ValueType& elem) = 0; + virtual queue_op_status wait_pull(value_type& elem) = 0; virtual void push(BOOST_THREAD_RV_REF(value_type) x) = 0; virtual queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) = 0; @@ -137,7 +137,7 @@ namespace detail virtual queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) = 0; }; - template struct queue_base; - template - struct queue_base { - typedef queue_base_copyable_and_movable type; + template + struct queue_base { + typedef queue_base_copyable_and_movable type; }; - template - struct queue_base { - typedef queue_base_copyable_only type; + template + struct queue_base { + typedef queue_base_copyable_only type; }; - template - struct queue_base { - typedef queue_base_movable_only type; + template + struct queue_base { + typedef queue_base_movable_only type; }; } - template + template class queue_base : - public detail::queue_base::type + public detail::queue_base::type { public: typedef ValueType value_type; - typedef std::size_t size_type; + typedef SizeType size_type; // Constructors/Assignment/Destructors virtual ~queue_base() {}; }; diff --git a/include/boost/thread/concurrent_queues/sync_priority_queue.hpp b/include/boost/thread/concurrent_queues/sync_priority_queue.hpp index b02c6f48..d604faa7 100644 --- a/include/boost/thread/concurrent_queues/sync_priority_queue.hpp +++ b/include/boost/thread/concurrent_queues/sync_priority_queue.hpp @@ -43,12 +43,13 @@ namespace detail { Compare _compare; public: typedef Type value_type; + typedef typename Container::size_type size_type; explicit priority_queue(const Compare& compare = Compare()) : _elements(), _compare(compare) { } - std::size_t size() const + size_type size() const { return _elements.size(); } From 5169a5414b074755e119419c5ec0bae25155e03d Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 14 Mar 2015 16:26:35 +0100 Subject: [PATCH 14/23] mutex::unlock must not throw. --- include/boost/thread/pthread/mutex.hpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index c7cf62ac..9ac808b6 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -1,12 +1,13 @@ #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP #define BOOST_THREAD_PTHREAD_MUTEX_HPP // (C) Copyright 2007-8 Anthony Williams -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011,2012,2015 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) #include +#include #include #include #include @@ -122,10 +123,12 @@ namespace boost void unlock() { int res = posix::pthread_mutex_unlock(&m); - if (res) - { - boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); - } + (void)res; + BOOST_ASSERT(res == 0); +// if (res) +// { +// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); +// } } bool try_lock() @@ -218,10 +221,12 @@ namespace boost void unlock() { int res = posix::pthread_mutex_unlock(&m); - if (res) - { - boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); - } + (void)res; + BOOST_ASSERT(res == 0); +// if (res) +// { +// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); +// } } bool try_lock() From ba2f8143420d7abdf566cdba993843d570528ad8 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Mon, 16 Mar 2015 08:41:04 +0100 Subject: [PATCH 15/23] Don't lock while storing the exception_ptr list as only the task_region thread can do it. --- .../experimental/parallel/v2/task_region.hpp | 36 +++++++++---------- .../parallel/v2/task_region_pass.cpp | 4 ++- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/include/boost/thread/experimental/parallel/v2/task_region.hpp b/include/boost/thread/experimental/parallel/v2/task_region.hpp index 7f3d0e2b..3a278c50 100755 --- a/include/boost/thread/experimental/parallel/v2/task_region.hpp +++ b/include/boost/thread/experimental/parallel/v2/task_region.hpp @@ -3,7 +3,7 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost +// (C) Copyright Vicente J. Botet Escriba 2014-2015. 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) // @@ -50,12 +50,13 @@ BOOST_THREAD_INLINE_NAMESPACE(v2) void handle_task_region_exceptions(exception_list& errors) { try { - boost::rethrow_exception(boost::current_exception()); - //throw boost::current_exception(); + throw; } +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED catch (task_canceled_exception& ex) { } +#endif catch (exception_list const& el) { for (exception_list::const_iterator it = el.begin(); it != el.end(); ++it) @@ -94,7 +95,7 @@ BOOST_THREAD_INLINE_NAMESPACE(v2) { lock_guard lk(tr.mtx); tr.canceled = true; - handle_task_region_exceptions(tr.exs); + throw; } } }; @@ -123,8 +124,6 @@ BOOST_THREAD_INLINE_NAMESPACE(v2) { wait_for_all(group.begin(), group.end()); - #if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED - for (group_type::iterator it = group.begin(); it != group.end(); ++it) { future& f = *it; @@ -140,11 +139,9 @@ BOOST_THREAD_INLINE_NAMESPACE(v2) } } } - #endif if (exs.size() != 0) { boost::throw_exception(exs); - //throw exs; } } protected: @@ -187,6 +184,7 @@ protected: } #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED + mutable mutex mtx; bool canceled; #endif #if defined BOOST_THREAD_PROVIDES_EXECUTORS @@ -195,8 +193,6 @@ protected: exception_list exs; typedef csbl::vector > group_type; group_type group; - mutable mutex mtx; - public: BOOST_DELETED_FUNCTION(task_region_handle_gen(const task_region_handle_gen&)) @@ -207,11 +203,12 @@ protected: template void run(BOOST_THREAD_FWD_REF(F) f) { - lock_guard lk(mtx); #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED - if (canceled) { - boost::throw_exception(task_canceled_exception()); - //throw task_canceled_exception(); + { + lock_guard lk(mtx); + if (canceled) { + boost::throw_exception(task_canceled_exception()); + } } #if defined BOOST_THREAD_PROVIDES_EXECUTORS group.push_back(async(*ex, detail::wrapped, F>(*this, forward(f)))); @@ -229,11 +226,12 @@ protected: void wait() { - lock_guard lk(mtx); #if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED - if (canceled) { - boost::throw_exception(task_canceled_exception()); - //throw task_canceled_exception{}; + { + lock_guard lk(mtx); + if (canceled) { + boost::throw_exception(task_canceled_exception()); + } } #endif wait_all(); @@ -276,7 +274,6 @@ protected: } catch (...) { - lock_guard lk(tr.mtx); detail::handle_task_region_exceptions(tr.exs); } tr.wait_all(); @@ -298,7 +295,6 @@ protected: } catch (...) { - lock_guard lk(tr.mtx); detail::handle_task_region_exceptions(tr.exs); } tr.wait_all(); diff --git a/test/experimental/parallel/v2/task_region_pass.cpp b/test/experimental/parallel/v2/task_region_pass.cpp index 3ecb4fbc..814ef28e 100644 --- a/test/experimental/parallel/v2/task_region_pass.cpp +++ b/test/experimental/parallel/v2/task_region_pass.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014 Vicente J. Botet Escriba +// Copyright (C) 2014-2015 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) @@ -132,7 +132,9 @@ void run_exception_1() { std::cout << "task3" << std::endl; }); +#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED BOOST_TEST(false); +#endif }); BOOST_TEST(false); } From a5c34e7be29ae861e37987ef508d4a688de0d846 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 21 Mar 2015 15:43:04 +0100 Subject: [PATCH 16/23] update version and copyright. --- doc/thread.qbk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/thread.qbk b/doc/thread.qbk index efac8747..9605234d 100644 --- a/doc/thread.qbk +++ b/doc/thread.qbk @@ -8,10 +8,10 @@ [library Thread [quickbook 1.5] - [version 4.4.0] + [version 4.5.0] [authors [Williams, Anthony] [Botet Escriba, Vicente J.]] [copyright 2007-11 Anthony Williams] - [copyright 2011-14 Vicente J. Botet Escriba] + [copyright 2011-15 Vicente J. Botet Escriba] [purpose C++ Library for launching threads and synchronizing data between them] [category text] [license From b5c6f760c5b714d40c09305660bddd2890f7b9ad Mon Sep 17 00:00:00 2001 From: Marcel Raad Date: Thu, 26 Mar 2015 13:43:44 +0100 Subject: [PATCH 17/23] Respect BOOST_USE_WINDOWS_H again With the GetTickCount64 and WinRT fixes, the Windows API functions were always re-declared regardless of BOOST_USE_WINDOWS_H. This breaks clang-cl, which complains about conflicting definitions. --- .../boost/thread/win32/thread_primitives.hpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index d9f63e6c..d0d4f0ae 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -35,6 +35,7 @@ namespace boost typedef HANDLE handle; typedef SYSTEM_INFO system_info; typedef unsigned __int64 ticks_type; + typedef FARPROC farproc_t; unsigned const infinite=INFINITE; unsigned const timeout=WAIT_TIMEOUT; handle const invalid_handle_value=INVALID_HANDLE_VALUE; @@ -58,17 +59,20 @@ namespace boost using ::CreateSemaphoreExW; # endif using ::OpenEventW; + using ::GetModuleGandleW; # else using ::CreateMutexA; using ::CreateEventA; using ::OpenEventA; using ::CreateSemaphoreA; + using ::GetModuleHandleA; # endif #if BOOST_PLAT_WINDOWS_RUNTIME using ::GetNativeSystemInfo; using ::GetTickCount64; #else using ::GetSystemInfo; + using ::GetTickCount; #endif using ::CloseHandle; using ::ReleaseMutex; @@ -86,6 +90,7 @@ namespace boost using ::SleepEx; using ::Sleep; using ::QueueUserAPC; + using ::GetProcAddress; #endif } } @@ -135,6 +140,7 @@ namespace boost typedef void* handle; typedef _SYSTEM_INFO system_info; typedef unsigned __int64 ticks_type; + typedef int (__stdcall *farproc_t)(); unsigned const infinite=~0U; unsigned const timeout=258U; handle const invalid_handle_value=(handle)(-1); @@ -160,17 +166,20 @@ namespace boost __declspec(dllimport) void* __stdcall CreateSemaphoreExW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*,unsigned long,unsigned long); # endif __declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*); + __declspec(dllimport) void* __stdcall GetModuleHandleW(wchar_t const*); # else __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*); __declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*); __declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*); __declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*); + __declspec(dllimport) void* __stdcall GetModuleHandleA(char const*); # endif #if BOOST_PLAT_WINDOWS_RUNTIME __declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*); __declspec(dllimport) ticks_type __stdcall GetTickCount64(); #else __declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*); + __declspec(dllimport) unsigned long __stdcall GetTickCount(); #endif __declspec(dllimport) int __stdcall CloseHandle(void*); __declspec(dllimport) int __stdcall ReleaseMutex(void*); @@ -183,6 +192,7 @@ namespace boost __declspec(dllimport) void __stdcall Sleep(unsigned long); typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr); __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr); + __declspec(dllimport) farproc_t __stdcall GetProcAddress(void *, const char *); #endif # ifndef UNDER_CE @@ -216,17 +226,10 @@ namespace boost { namespace win32 { - namespace detail { typedef int (__stdcall *farproc_t)(); typedef ticks_type (__stdcall *gettickcount64_t)(); } + namespace detail { typedef ticks_type (__stdcall *gettickcount64_t)(); } #if !BOOST_PLAT_WINDOWS_RUNTIME extern "C" { - __declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *); -#if !defined(BOOST_NO_ANSI_APIS) - __declspec(dllimport) void * __stdcall GetModuleHandleA(const char *); -#else - __declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *); -#endif - __declspec(dllimport) unsigned long __stdcall GetTickCount(); #ifdef _MSC_VER long _InterlockedCompareExchange(long volatile *, long, long); #pragma intrinsic(_InterlockedCompareExchange) @@ -285,6 +288,7 @@ namespace boost // Oops, we weren't called often enough, we're stuck return 0xFFFFFFFF; } +#else #endif inline detail::gettickcount64_t GetTickCount64_() { @@ -297,7 +301,7 @@ namespace boost #if BOOST_PLAT_WINDOWS_RUNTIME gettickcount64impl = &GetTickCount64; #else - detail::farproc_t addr=GetProcAddress( + farproc_t addr=GetProcAddress( #if !defined(BOOST_NO_ANSI_APIS) GetModuleHandleA("KERNEL32.DLL"), #else From dbf793e7eb5c8d041dd81fd7cd154371efd38c5a Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 29 Mar 2015 19:28:05 +0200 Subject: [PATCH 18/23] Don't execute test for launch::deferred if BOOST_THREAD_PROVIDES_VARIADIC_THREAD is not defined. --- test/sync/futures/when_all/iterators_pass.cpp | 2 +- test/sync/futures/when_all/one_pass.cpp | 2 +- test/sync/futures/when_all/variadic_pass.cpp | 2 +- test/sync/futures/when_any/iterators_pass.cpp | 2 +- test/sync/futures/when_any/one_pass.cpp | 2 +- test/sync/futures/when_any/variadic_pass.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/sync/futures/when_all/iterators_pass.cpp b/test/sync/futures/when_all/iterators_pass.cpp index 2316a8d1..cebf4192 100644 --- a/test/sync/futures/when_all/iterators_pass.cpp +++ b/test/sync/futures/when_all/iterators_pass.cpp @@ -281,7 +281,7 @@ int main() BOOST_TEST(res[1].is_ready()); BOOST_TEST(res[1].get() == 321); } -#if ! defined BOOST_NO_CXX11_DECLTYPE_N3276 +#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD // fixme darwin-4.8.0_11 terminate called without an active exception { // deferred future copy-constructible boost::future f1 = boost::async(boost::launch::deferred, &p1); diff --git a/test/sync/futures/when_all/one_pass.cpp b/test/sync/futures/when_all/one_pass.cpp index 437d3ea5..a39e638e 100644 --- a/test/sync/futures/when_all/one_pass.cpp +++ b/test/sync/futures/when_all/one_pass.cpp @@ -152,7 +152,7 @@ int main() BOOST_TEST(boost::csbl::get<0>(res).is_ready()); BOOST_TEST(boost::csbl::get<0>(res).get() == 123); } -#if ! defined BOOST_NO_CXX11_DECLTYPE_N3276 +#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD // fixme darwin-4.8.0_11 terminate called without an active exception { // deferred future copy-constructible boost::future f1 = boost::async(boost::launch::deferred, &p1); diff --git a/test/sync/futures/when_all/variadic_pass.cpp b/test/sync/futures/when_all/variadic_pass.cpp index 4d34e6f8..1c864c59 100644 --- a/test/sync/futures/when_all/variadic_pass.cpp +++ b/test/sync/futures/when_all/variadic_pass.cpp @@ -236,7 +236,7 @@ int main() BOOST_TEST(boost::csbl::get<1>(res).is_ready()); BOOST_TEST(boost::csbl::get<1>(res).get() == 321); } -#if ! defined BOOST_NO_CXX11_DECLTYPE_N3276 +#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD // fixme darwin-4.8.0_11 terminate called without an active exception { // deferred future copy-constructible boost::future f1 = boost::async(boost::launch::deferred, &p1); diff --git a/test/sync/futures/when_any/iterators_pass.cpp b/test/sync/futures/when_any/iterators_pass.cpp index 21e2a0ef..75a30cc4 100644 --- a/test/sync/futures/when_any/iterators_pass.cpp +++ b/test/sync/futures/when_any/iterators_pass.cpp @@ -283,7 +283,7 @@ int main() BOOST_TEST(res[1].is_ready()); BOOST_TEST(res[1].get() == 321); } -#if ! defined BOOST_NO_CXX11_DECLTYPE_N3276 +#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD // fixme darwin-4.8.0_11 terminate called without an active exception { // deferred future copy-constructible boost::future f1 = boost::async(boost::launch::deferred, &p1); diff --git a/test/sync/futures/when_any/one_pass.cpp b/test/sync/futures/when_any/one_pass.cpp index 50f5dab5..f54d8376 100644 --- a/test/sync/futures/when_any/one_pass.cpp +++ b/test/sync/futures/when_any/one_pass.cpp @@ -125,7 +125,7 @@ int main() BOOST_TEST(boost::csbl::get<0>(res).is_ready()); BOOST_TEST(boost::csbl::get<0>(res).get() == 123); } -#if ! defined BOOST_NO_CXX11_DECLTYPE_N3276 +#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD // fixme darwin-4.8.0_11 terminate called without an active exception { // deferred future copy-constructible boost::future f1 = boost::async(boost::launch::deferred, &p1); diff --git a/test/sync/futures/when_any/variadic_pass.cpp b/test/sync/futures/when_any/variadic_pass.cpp index e59b3a79..cee81ef1 100644 --- a/test/sync/futures/when_any/variadic_pass.cpp +++ b/test/sync/futures/when_any/variadic_pass.cpp @@ -225,7 +225,7 @@ int main() BOOST_TEST(boost::csbl::get<0>(res).get() == 123); BOOST_TEST(boost::csbl::get<1>(res).get() == 321); } -#if ! defined BOOST_NO_CXX11_DECLTYPE_N3276 +#if defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD // fixme darwin-4.8.0_11 terminate called without an active exception { // deferred future copy-constructible boost::future f1 = boost::async(boost::launch::deferred, &p1); From 74f479d5c902fc4ab37dc79bdcb19b1f3aa0455b Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 29 Mar 2015 19:34:28 +0200 Subject: [PATCH 19/23] Fix non_copyable class in queue/dequeue view tests. --- test/sync/mutual_exclusion/deque_views/single_thread_pass.cpp | 2 +- test/sync/mutual_exclusion/queue_views/single_thread_pass.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/sync/mutual_exclusion/deque_views/single_thread_pass.cpp b/test/sync/mutual_exclusion/deque_views/single_thread_pass.cpp index 96e8e268..ec310192 100644 --- a/test/sync/mutual_exclusion/deque_views/single_thread_pass.cpp +++ b/test/sync/mutual_exclusion/deque_views/single_thread_pass.cpp @@ -21,9 +21,9 @@ class non_copyable { - BOOST_THREAD_MOVABLE_ONLY(non_copyable) int val; public: + BOOST_THREAD_MOVABLE_ONLY(non_copyable) non_copyable(int v) : val(v){} non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {} non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; } diff --git a/test/sync/mutual_exclusion/queue_views/single_thread_pass.cpp b/test/sync/mutual_exclusion/queue_views/single_thread_pass.cpp index 41cf1cf3..d40c1157 100644 --- a/test/sync/mutual_exclusion/queue_views/single_thread_pass.cpp +++ b/test/sync/mutual_exclusion/queue_views/single_thread_pass.cpp @@ -21,9 +21,9 @@ class non_copyable { - BOOST_THREAD_MOVABLE_ONLY(non_copyable) int val; public: + BOOST_THREAD_MOVABLE_ONLY(non_copyable) non_copyable(int v) : val(v){} non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {} non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; } From 45c9a1d7fd16ab828fe9b6aa48e0ac0670e53b02 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Fri, 17 Apr 2015 18:30:49 +0200 Subject: [PATCH 20/23] ref #11192- boost::future<>::then() with an executor doesn't compile when the callback returns a future --- example/executor.cpp | 16 ++++++++++++++++ include/boost/thread/future.hpp | 5 +++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/example/executor.cpp b/example/executor.cpp index 7f6b1ce3..10c77a00 100644 --- a/example/executor.cpp +++ b/example/executor.cpp @@ -28,6 +28,10 @@ #include #include +boost::future p(boost::future) { + return boost::make_ready_future(); +} + void p1() { // std::cout << BOOST_CONTEXTOF << std::endl; @@ -147,4 +151,16 @@ int test_executor_adaptor() int main() { return test_executor_adaptor(); + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \ + && defined BOOST_THREAD_PROVIDES_EXECUTORS \ + && ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + + // compiles + boost::make_ready_future().then(&p); + + boost::basic_thread_pool executor; + // doesn't compile + boost::make_ready_future().then(executor, &p); +#endif } diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index e6e22363..dd752db8 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -1420,7 +1420,7 @@ namespace boost typedef typename base_type::move_dest_type move_dest_type; - public: // when_all + public: // // todo move to private and add the needed friends (when_all, executors, ...) BOOST_THREAD_FUTURE(future_ptr a_future): base_type(a_future) @@ -1626,12 +1626,13 @@ namespace boost typedef typename base_type::move_dest_type move_dest_type; + public: // todo move to private and add the needed friends + BOOST_THREAD_FUTURE(future_ptr a_future): base_type(a_future) { } - public: BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) typedef future_state::state state; typedef R value_type; // EXTENSION From 66193b0d3815d00f54ea46253beac46a9eae5664 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Fri, 17 Apr 2015 18:31:34 +0200 Subject: [PATCH 21/23] Test with generic lambdas. --- example/lambda_future.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/example/lambda_future.cpp b/example/lambda_future.cpp index 6df1cee7..fd15d448 100644 --- a/example/lambda_future.cpp +++ b/example/lambda_future.cpp @@ -42,6 +42,14 @@ int main() int result = f2.get(); BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG; } +#if ! defined BOOST_NO_CXX14_GENERIC_LAMBDAS + { + boost::future f1 = boost::async(boost::launch::async, []() {return 123;}); + boost::future f2 = f1.then([](auto f) {return 2*f.get(); }); + int result = f2.get(); + BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG; + } +#endif } catch (std::exception& ex) { From 0bed674233a3c94b7254037dc4903961b54eb141 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 18 Apr 2015 07:04:50 +0200 Subject: [PATCH 22/23] ref #11192- boost::future<>::then() with an executor doesn't compile when the callback returns a future --- include/boost/thread/future.hpp | 165 ++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 6 deletions(-) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index dd752db8..28239c4a 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -1363,6 +1363,28 @@ namespace boost template BOOST_THREAD_FUTURE make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_deferred_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_async_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + BOOST_THREAD_FUTURE + make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f); + #endif #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP template @@ -1372,6 +1394,36 @@ namespace boost make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f); #endif } +#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY) + template< typename InputIterator> + typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last); + + inline BOOST_THREAD_FUTURE > when_all(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif + + template< typename InputIterator> + typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last); + + inline BOOST_THREAD_FUTURE > when_any(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY + template class BOOST_THREAD_FUTURE : public detail::basic_future @@ -1395,6 +1447,28 @@ namespace boost template friend BOOST_THREAD_FUTURE detail::make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_deferred_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_async_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f); + #endif #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP template @@ -1403,6 +1477,35 @@ namespace boost friend BOOST_THREAD_FUTURE detail::make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f); #endif +#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY) + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last); + + //friend inline BOOST_THREAD_FUTURE > when_all(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif + + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last); + + //friend inline BOOST_THREAD_FUTURE > when_any(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK template friend class packaged_task; // todo check if this works in windows #else @@ -1418,9 +1521,7 @@ namespace boost friend BOOST_THREAD_FUTURE detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); - typedef typename base_type::move_dest_type move_dest_type; - public: // // todo move to private and add the needed friends (when_all, executors, ...) BOOST_THREAD_FUTURE(future_ptr a_future): base_type(a_future) @@ -1588,7 +1689,7 @@ namespace boost friend class shared_future; friend class promise; - #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION template friend struct detail::future_async_continuation_shared_state; template @@ -1601,7 +1702,30 @@ namespace boost template friend BOOST_THREAD_FUTURE detail::make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); - #endif + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_deferred_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_async_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f); + #endif + +#endif #if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP template friend struct detail::future_unwrap_shared_state; @@ -1609,6 +1733,36 @@ namespace boost friend BOOST_THREAD_FUTURE detail::make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f); #endif +#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY) + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last); + + friend inline BOOST_THREAD_FUTURE > when_all(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif + + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last); + + friend inline BOOST_THREAD_FUTURE > when_any(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK template friend class packaged_task; // todo check if this works in windows #else @@ -1626,12 +1780,11 @@ namespace boost typedef typename base_type::move_dest_type move_dest_type; - public: // todo move to private and add the needed friends - BOOST_THREAD_FUTURE(future_ptr a_future): base_type(a_future) { } + public: BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) typedef future_state::state state; From 5c442e068c421ee9eece466fc7795ae526e4afbb Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sat, 18 Apr 2015 07:10:43 +0200 Subject: [PATCH 23/23] update compliance. --- doc/compliance.qbk | 59 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/doc/compliance.qbk b/doc/compliance.qbk index 6846f54c..06e4ca82 100644 --- a/doc/compliance.qbk +++ b/doc/compliance.qbk @@ -1,13 +1,15 @@ [/ - (C) Copyright 2011-2013 Vicente J. Botet Escriba. + (C) Copyright 2011-2015 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). ] [section:compliance Conformance and Extension] +[////////////////////////////////////////////] [section:cpp11 C++11 standard Thread library] +[///////////////////////////////////////////] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 - Standard for Programming Language C++]]] @@ -88,6 +90,7 @@ ] [endsect] [section:cxx14 C++14 standard Thread library - accepted changes] +[//////////////////////////////////////////////////////////////] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.html Working Draft, Standard for Programming Language C++]] @@ -103,6 +106,7 @@ [section:cxx1y C++14 TS Extensions for Concurrency V1 ] +[/////////////////////////////////////////////////////] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4107.html N4107-Extensions for Concurrency]] @@ -126,8 +130,10 @@ [endsect] [section:cxx1y C++1z TS Concurrency - On going proposals] +[///////////////////////////////////////////////////////] [section:latch C++ Latches and Barriers] +[//////////////////////////////////////] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3600 C++ Latches and Barriers]] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3817.html N3817 C++ Latches and Barriers]] @@ -140,6 +146,7 @@ [endsect] [section:queue C++ Concurrent Queues] +[///////////////////////////////////] [note [@ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html N3533 C++ Concurrent Queues]] @@ -183,24 +190,25 @@ [[X.3.4] [Managed Indirection] [No] [ - ]] ] [endsect] -[section:executors Asynchronous Executors] +[section:executors Executors and Schedulers] +[//////////////////////////////////////////] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3785.pdf N3785 Executors and Schedulers]] -[table Asynchronous Executors +[table Executors and Schedulers [[Section] [Description] [Status] [Comments]] - [[V.1.1] [Class executor] [Yes] [ - ]] - [[V.1.1] [add] [Yes] [ renamed with a function template submit ]] - [[V.1.1] [num_of_pendin_closures] [No] [ ]] + [[V.1.1] [Class `executor`] [Yes] [ - ]] + [[V.1.1] [`add`] [Yes] [ renamed with a function template `submit` ]] + [[V.1.1] [`num_of_pendin_closures`] [No] [ ]] [[V.1.2] [Class sceduled_executor] [No] [ - ]] - [[V.1.2] [add_at] [No] [ renamed with a function template submit_at ]] - [[V.1.2] [add_after] [No] [ renamed with a function template submit_after ]] + [[V.1.2] [`add_at`] [No] [ renamed with a function template `scheduler::submit_at` ]] + [[V.1.2] [`add_after`] [No] [ renamed with a function template `scheduler::submit_after` ]] [[V.2] [Concrete executor classes] [No] [ - ]] - [[V.2.1] [thread_pool] [Yes] [ static version Basic_thread_pool, dynamic one execduler_adaptor ]] - [[V.2.2] [serial_executor] [yes] [ - ]] - [[V.2.3] [loop_executor] [Yes] [ static version loop_scheduler, dynamic one execduler_adaptor ]] - [[V.2.4] [inline_executor] [Yes] [ static version inline_executor, dynamic one execduler_adaptor ]] - [[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor ]] + [[V.2.1] [`thread_pool`] [Yes] [ static version `basic_thread_pool`, dynamic one `execduler_adaptor` ]] + [[V.2.2] [`serial_executor`] [yes] [ - ]] + [[V.2.3] [`loop_executor`] [Yes] [ static version loop_scheduler, dynamic one `execduler_adaptor` ]] + [[V.2.4] [`inline_executor`] [Yes] [ static version `inline_executor`, dynamic one `execduler_adaptor` ]] + [[V.2.5] [`thread_executor`] [Yes] [ static version `thread_executor`, dynamic one `execduler_adaptor` ]] ] [note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3784.pdf N3784-Improvements to `std::future and Related APIs]] @@ -212,8 +220,31 @@ [[30.6.8] [`async`] [Yes] [ - ]] ] +[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4143.pdf N4143-Executors and schedulers, revision 4]] + +[table Executors and Schedulers - revision 4 + [[Section] [Description] [Status] [Comments]] + [[VI.A] [Executor Concept] [Yes] [ `wrapper_type` renamed by `work` and `spawn by `submit` ]] + [[VI.A.1] [`thread_per_task_executor] [Yes] [ renamed `thread_executor`]] + [[VI.A.2] [`thread_pool_executor`] [Yes] [ renamed `basic_thread_pool`]] + [[VI.A.3] [`system_executor`] [No] [ - ]] + [[VI.A.4] [`loop_executor`] [Yes] [ - ]] + [[VI.A.5] [`serial_executor`] [yes] [ - ]] + [[VI.B] [`executor_ref`] [yes] [ - ]] + [[VI.C] [`executor`] [yes] [ renamed `gen_executor_ref` ]] + [[VI.D] [Free Functions and Helper Objects] [partial] [ - ]] + [[VI.D] [`make_package`] [No] [ - ]] + [[VI.D] [`spawn_future`] [No] [ `async(Ex&, ...)` is similar but returns a blocking future. ]] + [[VI.D] [`spawn`] [No] [ - ]] + [[VI.D] [`task_wrapper`] [No] [ renamed `resubmitter` ]] + [[VI.D] [`set_executor`] [No] [ renamed `resubmit` ]] + [[VI.D] [`function_wrapper`] [Partial] [ renamed `work` ]] +] + [endsect] +[////////////////////////////////////////////////////////////// [section:stream_mutex C++ Stream Mutexes - C++ Stream Guards] +[/////////////////////////////////////////////////////////////] While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard. @@ -241,7 +272,7 @@ While Boost.Thread implementation of stream mutexes differ in the approach, it i [endsect] - +///////////////////////////////] [endsect] [endsect]