22 changes: 11 additions & 11 deletions doc/external_locking.qbk
@@ -1,5 +1,5 @@
[/
/ Copyright (c) 2008,2012 Vicente J. Botet Escriba
/ Copyright (c) 2008,2012,2014 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)
Expand All @@ -8,7 +8,7 @@
[section External Locking -- `strict_lock` and `externally_locked` classes]


[note This tutorial is an adaptation of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System"
[note This tutorial is an adaptation of the paper by Andrei Alexandrescu "Multithreading and the C++ Type System"
to the Boost library.]

[/
Expand Down Expand Up @@ -163,7 +163,7 @@ Obviously, the caller-ensured locking approach has a safety problem. BankAccount
To conclude, if in designing a multi-threaded class you settle on internal locking, you expose yourself to inefficiency or deadlocks. On the other hand, if you rely on caller-provided locking, you make your class error-prone and difficult to use. Finally, external locking completely avoids the issue by leaving it all to the client code.
[endsect]
]
[section Locks as Permits]
[section Locks as permits]

So what to do? Ideally, the BankAccount class should do the following:

Expand All @@ -182,9 +182,9 @@ For now, let's make a couple of enhancements to the `lock_guard` class template
We'll call the enhanced version `strict_lock`. Essentially, a `strict_lock`'s role is only to live on the stack as an automatic variable.
`strict_lock` must adhere to a non-copy and non-alias policy.
`strict_lock` disables copying by making the copy constructor and the assignment operator private.
[/
While we're at it, let's disable operator new and operator delete.

[/
`strict_lock` are not intended to be allocated on the heap.
`strict_lock` avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.
]
Expand Down Expand Up @@ -293,7 +293,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n
}
};

Now, if you want the benefit of internal locking, you simply call Deposit(int) and Withdraw(int). If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
Now, if you want the benefit of internal locking, you simply call `Deposit(int)` and `Withdraw(int)`. If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:

void ATMWithdrawal(BankAccount& acct, int sum) {
strict_lock<BankAccount> guard(acct);
Expand Down Expand Up @@ -453,7 +453,7 @@ We achieved two important goals. First, the declaration of `checkingAcct_` and `

[section Allowing other strict locks]

Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compiles:
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compile:

void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
unique_lock<AccountManager> guard(*this, defer_lock);
Expand All @@ -465,7 +465,7 @@ Now imagine that the AccountManager function needs to take a `unique_lock` in or
do_something_else();
}

We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` during the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.

void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
unique_lock<AccountManager> guard1(*this, defer_lock);
Expand All @@ -480,9 +480,9 @@ We need a way to transfer the ownership from the `unique_lock` to a `strict_lock
guard1.unlock();
}

In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. We also need to store which kind of reference we have stored, and in the destructor call either to the Lockable `unlock` or restore the ownership.

This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.
This seems too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that checks that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to believe it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.

Now we need to state that both classes are `strict_lock`s.

Expand All @@ -496,9 +496,9 @@ Now we need to state that both classes are `strict_lock`s.
struct is_strict_lock<nested_strict_lock<Locker> > : mpl::true_ {}


Well let me show how this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
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 he will restore the ownership. Note also that the Locker needs to have already a reference to the mutex otherwise an exception is thrown and the use of the `lock_traits`.
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.

template <typename Locker >
class nested_strict_lock
Expand Down
98 changes: 85 additions & 13 deletions doc/future_ref.qbk
Expand Up @@ -9,7 +9,7 @@
[///////////////////////////////////]
[section:reference Futures Reference]

//#include <boost/thread/futures.hpp>
//#include <boost/thread/future.hpp>

namespace boost
{
Expand All @@ -30,6 +30,7 @@
{
async = unspecified,
deferred = unspecified,
executor = unspecified,
any = async | deferred
};

Expand All @@ -51,6 +52,8 @@

class future_error;

class exceptional_ptr;

template <typename R>
class promise;

Expand Down Expand Up @@ -88,6 +91,9 @@
template <class F, class... Args>
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(launch policy, F&& f, Args&&... args);
template <class Executor, class F, class... Args>
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);

template<typename Iterator>
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
Expand All @@ -106,10 +112,16 @@
template <typename T>
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
future<void> make_ready_future(); // EXTENSION
template <typename T>
future<T> make_ready_future(exception_ptr ex); // EXTENSION
template <typename T, typename E>
future<T> make_ready_future(E ex); // EXTENSION
//template <typename T>
//future<T> make_ready_future(exception_ptr ex); // DEPRECATED
//template <typename T, typename E>
//future<T> make_ready_future(E ex); // DEPRECATED

exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
template <typename E>
exceptional_ptr make_exceptional(E ex); // EXTENSION
exceptional_ptr make_exceptional(); // EXTENSION


template <typename T>
shared_future<typename decay<T>::type> make_shared_future(T&& value); // DEPRECATED
Expand Down Expand Up @@ -147,6 +159,7 @@
{
async = unspecified,
deferred = unspecified,
executor = unspecified,
any = async | deferred
};

Expand Down Expand Up @@ -260,6 +273,42 @@ The object's `name` virtual function returns a pointer to the string "future".]]
};

[endsect]

[/////////////////////////////////////////]
[section:future_error Class `exceptional_ptr` EXPERIMENTAL]

class exceptional_ptr
{
public:
exceptional_ptr();
explicit exceptional_ptr(exception_ptr ex);
template <class E>
explicit exceptional_ptr(E&& ex);
};

[///////////////////////////////]
[section:constructor Constructor]

exceptional_ptr();
explicit exceptional_ptr(exception_ptr ex);
template <class E>
explicit exceptional_ptr(E&& ex);

[variablelist

[[Effects:] [The exception that is passed in to the constructor or the current exception if no parameter is moved into the constructed `exceptional_ptr` if it is an rvalue. Otherwise the exception is copied into the constructed `exceptional_ptr`.]]

[[Postconditions:] [
`valid() == true && is_ready() = true && has_value() = false`
]]

[[Throws:] [Nothing.]]
]

[endsect]
[endsect]


[////////////////////////////////////////////////////]
[section:unique_future __unique_future class template]

Expand Down Expand Up @@ -557,8 +606,6 @@ associated with `*this` is not ready at the point of the call, and the current t
[warning
DEPRECATED since 3.00.

Available only up to Boost 1.56.

Use instead __wait_for.
]

Expand Down Expand Up @@ -595,8 +642,6 @@ elapsed, `false` otherwise.]]
[warning
DEPRECATED since 3.00.

Available only up to Boost 1.56.

Use instead __wait_until.
]

Expand Down Expand Up @@ -1892,7 +1937,9 @@ provides the result of the function in a future object with which it shares a sh
template <class F>
__unique_future__<typename result_of<typename decay<F>::type()>::type>
async(launch policy, F&& f);

template <class Executor, class F>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
[variablelist

[[Requires:] [
Expand Down Expand Up @@ -1957,7 +2004,10 @@ If the implementation chooses the `launch::async` policy,
template <class F, class... Args>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(launch policy, F&& f, Args&&... args);

template <class Executor, class F, class... Args>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);

[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple> (waiting for a boost::tuple that is move aware), and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.]

[variablelist
Expand Down Expand Up @@ -2115,9 +2165,9 @@ __unique_future__ or __shared_future__.]]
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
future<void> make_ready_future(); // EXTENSION
template <typename T>
future<T> make_ready_future(exception_ptr ex); // EXTENSION
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
template <typename T, typename E>
future<T> make_ready_future(E ex); // EXTENSION
future<T> make_ready_future(E ex); // DEPRECATED

[variablelist

Expand Down Expand Up @@ -2152,6 +2202,28 @@ Otherwise the value is copied to the shared state of the returned function.
]

[endsect]
[/////////////////////////////////////////////////////////////////////////////]
[section:make_exceptional Non-member function `make_exceptional()` EXTENSION]

exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
template <typename E>
exceptional_ptr make_exceptional(E ex); // EXTENSION
exceptional_ptr make_exceptional(); // EXTENSION

[variablelist

[[Effects:] [
The exception that is passed in to the function or the current exception if no parameter is given is moved into the returned `exceptional_ptr` if it is an rvalue. Otherwise the exception is copied into the returned `exceptional_ptr`.
]]

[[Returns:] [
An exceptional_ptr instance implicitly convertible to a future<T>
]]

]

[endsect]

[//////////////////////////////////////////////////////////////////]
[section:make_future Non-member function `make_future()` DEPRECATED]

Expand Down
18 changes: 9 additions & 9 deletions doc/internal_locking.qbk
@@ -1,5 +1,5 @@
[/
/ Copyright (c) 2008 Vicente J. Botet Escriba
/ Copyright (c) 2008,2014 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)
Expand All @@ -14,7 +14,7 @@ Consider, for example, modeling a bank account class that supports simultaneous

From here a component is a model of the `Callable` concept.

On C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
I C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):

boost::thread thread1(S);

Expand Down Expand Up @@ -53,12 +53,12 @@ The following example includes a bank account of a person (Joe) and two componen
return 0;
}

From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. Joe will similarly withdraw $100 from his account. These sentences describe that the bankAgent and Joe are executed concurrently.
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. `Joe` will similarly withdraw $100 from his account. These sentences describe that the `bankAgent` and `Joe` are executed concurrently.

[endsect]
[section Internal locking]

The above example works well as long as the bankAgent and Joe doesn't access JoesAccount at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
The above example works well as long as the components `bankAgent` and `Joe` doesn't access `JoesAccount` at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.

class BankAccount {
boost::mutex mtx_;
Expand All @@ -82,11 +82,11 @@ The above example works well as long as the bankAgent and Joe doesn't access Joe
}
};

Execution of the Deposit and Withdraw operations will no longer be able to make simultaneous access to balance.
Execution of the `Deposit` and `Withdraw` operations will no longer be able to make simultaneous access to balance.

Mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
A mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.

With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object `mtx_`, and guard's destructor unlocks `mtx_`.

class BankAccount {
boost::mutex mtx_; // explicit mutex declaration
Expand Down Expand Up @@ -135,10 +135,10 @@ In an attempt to solve this problem, let's lock the account from the outside dur
acct.Withdraw(2);
}

Notice that the code above doesn't compiles, the `mtx_` field is private.
Notice that the code above doesn't compile, the `mtx_` field is private.
We have two possibilities:

* make `mtx_` public which seams odd
* make `mtx_` public which seems odd
* make the `BankAccount` lockable by adding the lock/unlock functions

We can add these functions explicitly
Expand Down
42 changes: 38 additions & 4 deletions doc/mutex_concepts.qbk
Expand Up @@ -298,8 +298,6 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.]
[warning
DEPRECATED since 4.00. The following expressions were required on version 2, but are now deprecated.

Available only up to Boost 1.58.

Use instead __try_lock_for, __try_lock_until.
]

Expand Down Expand Up @@ -460,8 +458,6 @@ ownership of `m`.]]
[warning
DEPRECATED since 3.00. The following expressions were required on version 2, but are now deprecated.

Available only up to Boost 1.56.

Use instead __try_lock_shared_for, __try_lock_shared_until.
]

Expand Down Expand Up @@ -1119,6 +1115,44 @@ object passed to the constructor.]]
]


[endsect]
[endsect]


[section:with_lock_guard With Lock Guard]

// #include <boost/thread/with_lock_guard.hpp>

namespace boost
{
template <class Lockable, class Function, class... Args>
auto with_lock_guard(Lockable& m, Function&& func, Args&&... args) -> decltype(func(boost::forward<Args>(args)...));
}

[section:with_lock_guard Non Member Function `with_lock_guard`]

template <class Lockable, class Function, class... Args>
auto with_lock_guard(
Lockable& m,
Function&& func,
Args&&... args
) -> decltype(func(boost::forward<Args>(args)...));

[variablelist

[[Precondition:] [`m` must be in unlocked state]]
[[Effects:] [call `func` in scope locked by `m`]]
[[Returns:] [Result of `func(args...)` call]]
[[Throws:] [Any exception thrown by the call to `m.lock` and `func(args...)`]]
[[Postcondition:] [`m` is in unlocked state]]

[[Limitations:] [Without c++11 variadic templates support number of arguments is limited to `4`]]
[[] [Without rvalue references support calling class method with `boost::bind` must be const]]
[[] [For correct work with lambda macro `BOOST_RESULT_OF_USE_DECLTYPE` may be needed to define]]


]

[endsect]
[endsect]

Expand Down
7 changes: 4 additions & 3 deletions doc/scoped_thread.qbk
Expand Up @@ -34,9 +34,10 @@ Scoped Threads are wrappers around a thread that allows the user to state what t

The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface than __thread and forwards all the operations.

boost::strict_scoped_thread<> t1((boost::thread(F)));
boost::strict_scoped_thread<> t2((boost::thread(F)));
t2.interrupt();
boost::strict_scoped_thread<> t1((boost::thread(f)));
//t1.detach(); // compile fails
boost::scoped_thread<> t2((boost::thread(f)));
t2.detach();

[endsect]

Expand Down
335 changes: 256 additions & 79 deletions doc/sync_queues_ref.qbk

Large diffs are not rendered by default.

46 changes: 33 additions & 13 deletions doc/sync_tutorial.qbk
Expand Up @@ -20,24 +20,44 @@ In addition to the C++11 standard locks, Boost.Thread provides other locks and s

[section:with Executing Around a Function]

In particular, the library provides some lock factories.

template <class Lockable, class Function>
auto with_lock_guard(Lockable& m, Function f) -> decltype(f())
{
auto&& _ = boost::make_lock_guard(m);
f();
In particular, the library provides a way to lock around the execution of a function.

template <class Lockable, class Function, class... Args>
auto with_lock_guard(
Lockable& m,
Function&& func,
Args&&... args
) -> decltype(func(boost::forward<Args>(args)...)) {
boost::lock_guard<Lockable> lock(m);
return func(boost::forward<Args>(args)...);
}

that can be used with regular functions:

int func(int, int&);
//...
boost::mutex m;
int a;
int result = boost::with_lock_guard(m, func, 1, boost::ref(a));

with boost::bind:

that can be used as
int result = boost::with_lock_guard(
m, boost::bind(func, 2, boost::ref(a))
);

int i = with_lock_guard(mtx, []()
{
// access the protected state
return true;
});
or with lambda expression:

int a;
int result = boost::with_lock_guard(
m,
[&a](int x) {
// this scope is protected by mutex m
a = 3;
return x + 4;
},
5
);

[endsect] [/ With]

Expand Down
8 changes: 4 additions & 4 deletions doc/thread.qbk
Expand Up @@ -8,10 +8,10 @@

[library Thread
[quickbook 1.5]
[version 4.2.0]
[version 4.3.0]
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
[copyright 2007-11 Anthony Williams]
[copyright 2011-13 Vicente J. Botet Escriba]
[copyright 2011-14 Vicente J. Botet Escriba]
[purpose C++ Library for launching threads and synchronizing data between them]
[category text]
[license
Expand Down Expand Up @@ -239,9 +239,9 @@
[include condition_variables.qbk]
[include once.qbk]
[include barrier.qbk]
[/include latch.qbk]
[include latch.qbk]
[include async_executors.qbk]
[include futures.qbk]
[/include async_executors.qbk]
[endsect]


Expand Down
39 changes: 5 additions & 34 deletions doc/thread_ref.qbk
Expand Up @@ -533,24 +533,14 @@ This behavior is incompatible with the current Boost.Thread design, so the use o

thread& operator=(thread&& other) noexcept;


[warning
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE behavior.

Available only up to Boost 1.56.

Join the thread before moving.
]


[variablelist

[[Effects:] [Transfers ownership of the thread managed by `other` (if
any) to `*this`.

- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If there was a thread previously associated with `*this` then that thread is detached, DEPRECATED
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable call __detach__, DEPRECATED

- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate.
- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: 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.]]
Expand Down Expand Up @@ -707,24 +697,17 @@ are copied into internal storage for access by the new thread.]]]

~thread();

[warning
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE behavior.

Available only up to Boost 1.56.

Join the thread before destroying or use a scoped thread.
]

[variablelist

[[Effects:] [
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If `*this` has an associated thread of execution, calls __detach__, DEPRECATED
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls __detach__, DEPRECATED

- BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate. Destroys `*this`.]]
- if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to `std::terminate`. Destroys `*this`.]]

[[Throws:] [Nothing.]]

[[Note:] [Either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.]]
[[Note:] [The reason to moving to std::terminate is that either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. Join the thread before destroying or use an scoped thread.]]

]

Expand Down Expand Up @@ -795,8 +778,6 @@ corresponding successful `join()` return. ]]
[warning
DEPRECATED since 3.00.

Available only up to Boost 1.56.

Use instead __try_join_for, __try_join_until.
]

Expand Down Expand Up @@ -1030,8 +1011,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
[warning
DEPRECATED since 4.0.0.

Available only up to Boost 1.58.

Use `a.__get_id()==b.__get_id()` instead`.
]

Expand All @@ -1052,8 +1031,6 @@ Use `a.__get_id()==b.__get_id()` instead`.
[warning
DEPRECATED since 4.0.0.

Available only up to Boost 1.58.

Use `a.__get_id()!=b.__get_id()` instead`.
]

Expand All @@ -1072,8 +1049,6 @@ Use `a.__get_id()!=b.__get_id()` instead`.
[warning
DEPRECATED since 3.0.0.

Available only up to Boost 1.56.

Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
]

Expand All @@ -1097,8 +1072,6 @@ Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
[warning
DEPRECATED since 3.0.0.

Available only up to Boost 1.56.

Use `this_thread::__yield()`.
]

Expand Down Expand Up @@ -1490,8 +1463,6 @@ thread attributes implementation. If no such instance exists, `native_handle()`
[warning
DEPRECATED since 3.0.0.

Available only up to Boost 1.56.

Use `__sleep_for()` and `__sleep_until()` instead.
]

Expand Down
124 changes: 85 additions & 39 deletions example/executor.cpp
Expand Up @@ -3,86 +3,132 @@
// 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 <boost/config.hpp>
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#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 <boost/thread/thread_pool.hpp>
#include <boost/thread/user_scheduler.hpp>
#include <boost/thread/caller_context.hpp>
#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/thread/executors/loop_executor.hpp>
#include <boost/thread/executors/serial_executor.hpp>
#include <boost/thread/executors/inline_executor.hpp>
#include <boost/thread/executors/thread_executor.hpp>
#include <boost/thread/executors/executor.hpp>
#include <boost/thread/executors/executor_adaptor.hpp>
#include <boost/thread/executor.hpp>
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <string>
#include <boost/thread/caller_context.hpp>
#include <iostream>

void p1()
{
std::cout << BOOST_CONTEXTOF << std::endl;
// std::cout << BOOST_CONTEXTOF << std::endl;
//boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
}

void p2()
{
std::cout << BOOST_CONTEXTOF << std::endl;
// std::cout << BOOST_CONTEXTOF << std::endl;
//boost::this_thread::sleep_for(boost::chrono::seconds(10));
}

int f1()
{
std::cout << BOOST_CONTEXTOF << std::endl;
// std::cout << BOOST_CONTEXTOF << std::endl;
boost::this_thread::sleep_for(boost::chrono::seconds(1));
return 1;
}
int f2(int i)
{
std::cout << BOOST_CONTEXTOF << std::endl;
// std::cout << BOOST_CONTEXTOF << std::endl;
boost::this_thread::sleep_for(boost::chrono::seconds(2));
return i + 1;
}

void submit_some(boost::executor& tp)
{
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
for (int i = 0; i < 3; ++i) {
tp.submit(&p2);
}
for (int i = 0; i < 3; ++i) {
tp.submit(&p1);
}

}

void at_th_entry(boost::basic_thread_pool& )
{

}

int main()
{
std::cout << BOOST_CONTEXTOF << std::endl;
// std::cout << BOOST_CONTEXTOF << std::endl;
{
try
{
boost::executor_adaptor<boost::thread_pool> ea;
submit_some(ea);
{
boost::future<int> t1 = boost::async(ea, &f1);
boost::future<int> t2 = boost::async(ea, &f1);
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
boost::executor_adaptor < boost::basic_thread_pool > ea(4);
submit_some( ea);
{
boost::future<int> t1 = boost::async(ea, &f1);
boost::future<int> t2 = boost::async(ea, &f1);
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
}
submit_some(ea);
{
boost::basic_thread_pool ea3(1);
boost::future<int> t1 = boost::async(ea3, &f1);
boost::future<int> t2 = boost::async(ea3, &f1);
//boost::future<int> t2 = boost::async(ea3, f2, 1); // todo this doesn't compiles yet on C++11
//boost::future<int> t2 = boost::async(ea3, boost::bind(f2, 1)); // todo this doesn't compiles yet on C++98
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
}
submit_some(ea);
}
submit_some(ea);
// std::cout << BOOST_CONTEXTOF << std::endl;
{
boost::thread_pool ea3(1);
boost::future<int> t1 = boost::async(ea3, &f1);
boost::future<int> t2 = boost::async(ea3, &f1);
//boost::future<int> t2 = boost::async(ea3, f2, 1); // todo this doesn't compiles yet on C++11
//boost::future<int> t2 = boost::async(ea3, boost::bind(f2, 1)); // todo this doesn't compiles yet on C++98
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
boost::executor_adaptor < boost::loop_executor > ea2;
submit_some( ea2);
ea2.underlying_executor().run_queued_closures();
}
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
// std::cout << BOOST_CONTEXTOF << std::endl;
{
boost::executor_adaptor < boost::basic_thread_pool > ea1(4);
boost::executor_adaptor < boost::serial_executor > ea2(ea1);
submit_some(ea2);
}
#endif
// std::cout << BOOST_CONTEXTOF << std::endl;
{
boost::executor_adaptor < boost::inline_executor > ea1;
submit_some(ea1);
}
// std::cout << BOOST_CONTEXTOF << std::endl;
{
boost::executor_adaptor < boost::thread_executor > ea1;
submit_some(ea1);
}
// std::cout << BOOST_CONTEXTOF << std::endl;
{
boost::basic_thread_pool ea(4, at_th_entry);
boost::future<int> t1 = boost::async(ea, &f1);
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
}
submit_some(ea);

boost::executor_adaptor<boost::user_scheduler> ea2;
submit_some(ea2);
ea2.underlying_executor().run_queued_closures();

}
catch (std::exception& ex)
{
Expand All @@ -95,6 +141,6 @@ int main()
return 2;
}
}
std::cout << BOOST_CONTEXTOF << std::endl;
// std::cout << BOOST_CONTEXTOF << std::endl;
return 0;
}
8 changes: 8 additions & 0 deletions example/future_fallback_to.cpp
Expand Up @@ -3,6 +3,14 @@
// 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 <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

#define BOOST_THREAD_VERSION 4
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
Expand Down
98 changes: 57 additions & 41 deletions example/future_then.cpp
Expand Up @@ -3,6 +3,16 @@
// 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 <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
//&& ! defined BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif


#define BOOST_THREAD_VERSION 4
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
Expand All @@ -11,8 +21,6 @@
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <string>
#include <iostream>

#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION

int p1()
Expand All @@ -23,7 +31,7 @@ int p1()

int p2(boost::future<int> f)
{
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
BOOST_THREAD_LOG << "P2<" << BOOST_THREAD_END_LOG;
try
{
return 2 * f.get();
Expand All @@ -43,7 +51,7 @@ int p2(boost::future<int> f)
}
int p2s(boost::shared_future<int> f)
{
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
BOOST_THREAD_LOG << "<P2S" << BOOST_THREAD_END_LOG;
try
{
return 2 * f.get();
Expand All @@ -59,52 +67,60 @@ int p2s(boost::shared_future<int> f)
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_ASSERT(false);
}
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
BOOST_THREAD_LOG << "P2S>" << BOOST_THREAD_END_LOG;
}

int main()
{
const int number_of_tests = 100;
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
for (int i=0; i< number_of_tests; i++)
{
try
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
boost::future<int> f2 = f1.then(&p2);
(void)f2.get();
}
catch (std::exception& ex)
{
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
{
for (int i=0; i< number_of_tests; i++)
try
{
boost::shared_future<int> f1 = boost::async(boost::launch::async, &p1).share();
boost::future<int> f2 = f1.then(&p2s);
(void)f2.get();
for (int i=0; i< number_of_tests; i++)
try
{
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
boost::future<int> f1 = boost::async(&p1);
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
boost::future<int> f2 = f1.then(&p2);
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
(void)f2.get();
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
}
catch (std::exception& ex)
{
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
catch (std::exception& ex)
{
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
for (int i=0; i< number_of_tests; i++)
try
{
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
boost::shared_future<int> f1 = boost::async(&p1).share();
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
boost::future<int> f2 = f1.then(&p2s);
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
(void)f2.get();
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
}
catch (std::exception& ex)
{
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
Expand Down
8 changes: 8 additions & 0 deletions example/future_unwrap.cpp
Expand Up @@ -3,6 +3,14 @@
// 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 <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

#define BOOST_THREAD_VERSION 4
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
Expand Down
22 changes: 7 additions & 15 deletions example/future_when_all.cpp
Expand Up @@ -3,27 +3,19 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/config.hpp>

#if ! defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_WHEN_ALL_WHEN_ANY

#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)

#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

// ! defined(BOOST_NO_SFINAE_EXPR) &&
// ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) &&
// ! defined(BOOST_NO_CXX11_AUTO) &&
// ! defined(BOOST_NO_CXX11_DECLTYPE) &&
// ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) &&

#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID

#include <boost/thread/future.hpp>
#include <boost/thread/csbl/vector.hpp>
Expand Down
4 changes: 4 additions & 0 deletions example/lambda_future.cpp
Expand Up @@ -8,6 +8,10 @@
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif

#define BOOST_THREAD_VERSION 4
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
Expand Down
65 changes: 55 additions & 10 deletions example/make_future.cpp
Expand Up @@ -3,6 +3,14 @@
// 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 <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
//#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

#define BOOST_THREAD_VERSION 4

#include <boost/thread/future.hpp>
Expand All @@ -19,6 +27,7 @@ namespace boost
}

int p1() { return 5; }
int& p1r() { static int i=0; return i; }

void p() { }

Expand All @@ -32,44 +41,80 @@ boost::future<void> void_compute()
boost::future<int> compute(int x)
{
if (x == 0) return boost::make_ready_future(0);
//if (x < 0) return boost::make_ready_future<int>(boost::make_exception_ptr(std::logic_error("Error")));
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error"));
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
if (x < 0) return boost::make_exceptional_future<int>(std::logic_error("Error"));
#else
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
#endif
//boost::future<int> f1 = boost::async([]() { return x+1; });
boost::future<int> f1 = boost::async(boost::launch::async, p1);
boost::future<int> f1 = boost::async(p1);
return boost::move(f1);
}

boost::future<int&> compute_ref(int x)
{
static int i = 0;
//if (x == 0) return boost::make_ready_future<int&>(i); //This must not compile as the type is deduced as boost::future<int>
if (x == 0) return boost::make_ready_no_decay_future<int&>(i);
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
if (x < 0) return boost::make_exceptional_future<int&>(std::logic_error("Error"));
#else
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
#endif
boost::future<int&> f1 = boost::async(p1r);
return boost::move(f1);
}

boost::shared_future<int> shared_compute(int x)
{
if (x == 0) return boost::make_ready_future(0).share();
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error")).share();
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
if (x < 0) return boost::make_exceptional_future<int>(std::logic_error("Error")).share();
#else
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
#endif
//boost::future<int> f1 = boost::async([]() { return x+1; });
boost::shared_future<int> f1 = boost::async(p1).share();
return boost::move(f1);
boost::shared_future<int> f1 = boost::async(&p1).share();
return f1;
}


int main()
{
const int number_of_tests = 100;
for (int i=0; i< number_of_tests; i++)
try
try
{
// {
// std::cout << __FILE__ << " "<<__LINE__ << std::endl;
// boost::future<int> f = boost::async(boost::launch::async, p1);
// std::cout << i << " "<<f.get() << std::endl;
// }
#if defined BOOST_THREAD_USES_MOVE
{
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
boost::future<void> f = void_compute();
f.get();
}
#endif
{
boost::future<int> f = compute(2);
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
boost::future<int> f = compute(0);
std::cout << f.get() << std::endl;
}
{
boost::future<int> f = compute(0);
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
boost::future<int&> f = compute_ref(0);
std::cout << f.get() << std::endl;
}
// {
// std::cout << __FILE__ << " "<< __LINE__ << std::endl;
// boost::future<int> f = compute(2);
// std::cout << f.get() << std::endl;
// }
{
boost::shared_future<int> f = shared_compute(2);
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
boost::shared_future<int> f = shared_compute(0);
std::cout << f.get() << std::endl;
}
}
Expand Down
100 changes: 100 additions & 0 deletions example/parallel_accumulate.cpp
@@ -0,0 +1,100 @@
// 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)

#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_EXECUTORS
#define BOOST_THREAD_USES_LOG_THREAD_ID
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
#if ! defined BOOST_NO_CXX11_DECLTYPE
//#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/thread/future.hpp>

#include <numeric>
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)

template<typename Iterator,typename T>
struct accumulate_block
{
//typedef T result_type;
T operator()(Iterator first,Iterator last)
{
return std::accumulate(first,last,T());
}
};

template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{
unsigned long const length=std::distance(first,last);

if(!length)
return init;

unsigned long const block_size=25;
unsigned long const num_blocks=(length+block_size-1)/block_size;

boost::csbl::vector<boost::future<T> > futures(num_blocks-1);
boost::basic_thread_pool pool;

Iterator block_start=first;
for(unsigned long i=0;i<(num_blocks-1);++i)
{
Iterator block_end=block_start;
std::advance(block_end,block_size);
futures[i]=boost::async(pool, accumulate_block<Iterator,T>(), block_start, block_end);
block_start=block_end;
}
T last_result=accumulate_block<Iterator,T>()(block_start,last);
T result=init;
for(unsigned long i=0;i<(num_blocks-1);++i)
{
result+=futures[i].get();
}
result += last_result;
return result;
}


int main()
{
try
{
const int s = 1001;
std::vector<int> vec;
vec.reserve(s);
for (int i=0; i<s;++i)
vec.push_back(1);
int r = parallel_accumulate(vec.begin(), vec.end(),0);
std::cout << r << std::endl;

}
catch (std::exception& ex)
{
std::cout << "ERROR= " << ex.what() << "" << std::endl;
return 1;
}
catch (...)
{
std::cout << " ERROR= exception thrown" << std::endl;
return 2;
}
return 0;
}

#else
///#warning "This compiler doesn't supports variadics"
int main()
{
return 0;
}
#endif
21 changes: 11 additions & 10 deletions example/producer_consumer_bounded.cpp
Expand Up @@ -8,6 +8,7 @@

#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
#define XXXX

#include <iostream>
#include <boost/thread/scoped_thread.hpp>
Expand All @@ -29,17 +30,17 @@ void producer(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
{
sbq.push_back(i);
//sbq << i;
mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
//mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
this_thread::sleep_for(chrono::milliseconds(200));
}
}
catch(sync_queue_is_closed&)
{
mos << "closed !!!\n";
//mos << "closed !!!\n";
}
catch(...)
{
mos << "exception !!!\n";
//mos << "exception !!!\n";
}
}

Expand All @@ -52,17 +53,17 @@ void consumer(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
int r;
sbq.pull_front(r);
//sbq >> r;
mos << i << " pull_front(" << r << ") "<< sbq.size()<<"\n";
//mos << i << " pull_front(" << r << ") "<< sbq.size()<<"\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
catch(sync_queue_is_closed&)
{
mos << "closed !!!\n";
//mos << "closed !!!\n";
}
catch(...)
{
mos << "exception !!!\n";
//mos << "exception !!!\n";
}
}
void consumer2(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
Expand All @@ -75,14 +76,14 @@ void consumer2(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
queue_op_status st = sbq.try_pull_front(r);
if (queue_op_status::closed == st) break;
if (queue_op_status::success == st) {
mos << i << " pull(" << r << ")\n";
//mos << i << " pull(" << r << ")\n";
}
this_thread::sleep_for(chrono::milliseconds(250));
}
}
catch(...)
{
mos << "exception !!!\n";
//mos << "exception !!!\n";
}
}
//void consumer3(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
Expand All @@ -95,13 +96,13 @@ void consumer2(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
// int r;
// queue_op_status res = sbq.wait_and_pull(r);
// if (res==queue_op_status::closed) break;
// mos << i << " wait_and_pull(" << r << ")\n";
// //mos << i << " wait_and_pull(" << r << ")\n";
// this_thread::sleep_for(chrono::milliseconds(250));
// }
// }
// catch(...)
// {
// mos << "exception !!!\n";
// //mos << "exception !!!\n";
// }
//}

Expand Down
6 changes: 3 additions & 3 deletions example/thread_pool.cpp
Expand Up @@ -9,7 +9,7 @@
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD

#include <boost/thread/detail/log.hpp>
#include <boost/thread/thread_pool.hpp>
#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/assert.hpp>
#include <string>

Expand All @@ -25,7 +25,7 @@ void p2()
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
}

void submit_some(boost::thread_pool& tp) {
void submit_some(boost::basic_thread_pool& tp) {
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
Expand All @@ -46,7 +46,7 @@ int main()
{
try
{
boost::thread_pool tp;
boost::basic_thread_pool tp;
submit_some(tp);
}
catch (std::exception& ex)
Expand Down
6 changes: 3 additions & 3 deletions example/user_scheduler.cpp
Expand Up @@ -8,7 +8,7 @@
#define BOOST_THREAD_USES_LOG_THREAD_ID

#include <boost/thread/detail/log.hpp>
#include <boost/thread/user_scheduler.hpp>
#include <boost/thread/executors/loop_executor.hpp>
#include <boost/assert.hpp>
#include <string>

Expand All @@ -24,7 +24,7 @@ void p2()
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
}

void submit_some(boost::user_scheduler& tp) {
void submit_some(boost::loop_executor& tp) {
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
Expand All @@ -44,7 +44,7 @@ int main()
{
try
{
boost::user_scheduler tp;
boost::loop_executor tp;
submit_some(tp);
tp.run_queued_closures();
submit_some(tp);
Expand Down
53 changes: 53 additions & 0 deletions example/with_lock_guard.cpp
@@ -0,0 +1,53 @@
// (C) Copyright 2013 Ruslan Baratov
// 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)

// See www.boost.org/libs/thread for documentation.

#define BOOST_THREAD_VERSION 4

#include <iostream> // std::cout
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/with_lock_guard.hpp>

boost::mutex m; // protection for 'x' and 'std::cout'
int x;

#if defined(BOOST_NO_CXX11_LAMBDAS)
void print_x() {
++x;
std::cout << "x = " << x << std::endl;
}

void job() {
for (int i = 0; i < 10; ++i) {
boost::with_lock_guard(m, print_x);
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
}
}
#else
void job() {
for (int i = 0; i < 10; ++i) {
boost::with_lock_guard(
m,
[]() {
++x;
std::cout << "x = " << x << std::endl;
}
);
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
}
}
#endif

int main() {
#if defined(BOOST_NO_CXX11_LAMBDAS)
std::cout << "(no lambdas)" << std::endl;
#endif
boost::scoped_thread<> thread_1(job);
boost::scoped_thread<> thread_2(job);
boost::scoped_thread<> thread_3(job);
return 0;
}
1 change: 1 addition & 0 deletions include/boost/thread/caller_context.hpp
Expand Up @@ -12,6 +12,7 @@
#include <boost/thread/thread.hpp>
#endif
#include <boost/current_function.hpp>
#include <iomanip>

#include <boost/config/abi_prefix.hpp>

Expand Down
7 changes: 5 additions & 2 deletions include/boost/thread/csbl/deque.hpp
Expand Up @@ -11,7 +11,10 @@

#include <boost/config.hpp>

#if defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#ifndef BOOST_THREAD_USES_BOOST_DEQUE
#define BOOST_THREAD_USES_BOOST_DEQUE
#endif
#include <boost/container/deque.hpp>
#else
#include <deque>
Expand All @@ -21,7 +24,7 @@ namespace boost
{
namespace csbl
{
#if defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_DEQUE
using ::boost::container::deque;

#else
Expand Down
7 changes: 5 additions & 2 deletions include/boost/thread/csbl/functional.hpp
Expand Up @@ -13,15 +13,18 @@

#include <functional>

#if defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL || defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#ifndef BOOST_THREAD_USES_BOOST_FUNCTIONAL
#define BOOST_THREAD_USES_BOOST_FUNCTIONAL
#endif
#include <boost/function.hpp>
#endif

namespace boost
{
namespace csbl
{
#if defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL
using ::boost::function;
#else
// D.8.1, base (deprecated):
Expand Down
7 changes: 5 additions & 2 deletions include/boost/thread/csbl/list.hpp
Expand Up @@ -11,7 +11,10 @@

#include <boost/config.hpp>

#if defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#ifndef BOOST_THREAD_USES_BOOST_LIST
#define BOOST_THREAD_USES_BOOST_LIST
#endif
#include <boost/container/list.hpp>
#else
#include <list>
Expand All @@ -21,7 +24,7 @@ namespace boost
{
namespace csbl
{
#if defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_LIST
using ::boost::container::list;
#else
using ::std::list;
Expand Down
8 changes: 4 additions & 4 deletions include/boost/thread/csbl/memory/unique_ptr.hpp
Expand Up @@ -67,23 +67,23 @@ namespace boost
{}
unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u)
{
this->base_type.operator=(boost::move(static_cast<base_type&>(u)));
this->base_type::operator=(boost::move(static_cast<base_type&>(u)));
return *this;
}
template <class U, class E>
unique_ptr& operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u)
{
this->base_type.template operator=<U,E>(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)));
this->base_type::template operator=<U,E>(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)));
return *this;
}
unique_ptr& operator=(nullptr_t t)
{
this->base_type.operator=(t);
this->base_type::operator=(t);
return *this;
}
void swap(unique_ptr& u)
{
this->base_type.swap(u);
this->base_type::swap(u);
}
};
template <class T, class D>
Expand Down
10 changes: 8 additions & 2 deletions include/boost/thread/csbl/tuple.hpp
Expand Up @@ -11,8 +11,12 @@

#include <boost/config.hpp>

#if defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_TUPLE || defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#include <boost/tuple/tuple.hpp>
#ifndef BOOST_THREAD_USES_BOOST_TUPLE
#define BOOST_THREAD_USES_BOOST_TUPLE
#endif

#else
#include <tuple>
#endif
Expand All @@ -21,11 +25,13 @@ namespace boost
{
namespace csbl
{
#if defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_TUPLE
using ::boost::tuple;
using ::boost::get;
#else
// 20.4.2, class template tuple:
using ::std::tuple;
using ::std::get;
// 20.4.2.4, tuple creation functions:
// 20.4.2.5, tuple helper classes:
// 20.4.2.6, element access:
Expand Down
7 changes: 5 additions & 2 deletions include/boost/thread/csbl/vector.hpp
Expand Up @@ -11,7 +11,10 @@

#include <boost/config.hpp>

#if defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#ifndef BOOST_THREAD_USES_BOOST_VECTOR
#define BOOST_THREAD_USES_BOOST_VECTOR
#endif
#include <boost/container/vector.hpp>
#else
#include <vector>
Expand All @@ -21,7 +24,7 @@ namespace boost
{
namespace csbl
{
#if defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined BOOST_THREAD_USES_BOOST_VECTOR
using ::boost::container::vector;
#else
using ::std::vector;
Expand Down
19 changes: 18 additions & 1 deletion include/boost/thread/detail/config.hpp
Expand Up @@ -239,14 +239,31 @@
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
! defined(BOOST_NO_CXX11_DECLTYPE) && \
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
! defined(BOOST_NO_CXX11_AUTO) && \
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)

#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD
#endif
#endif

#if ! defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_WHEN_ALL_WHEN_ANY

#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)

#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
#endif
#endif

// ! defined(BOOST_NO_SFINAE_EXPR) &&
// ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) &&
// ! defined(BOOST_NO_CXX11_AUTO) &&
// ! defined(BOOST_NO_CXX11_DECLTYPE) &&
// ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) &&


// MAKE_READY_AT_THREAD_EXIT
#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \
Expand Down
287 changes: 250 additions & 37 deletions include/boost/thread/detail/invoke.hpp

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions include/boost/thread/detail/nullary_function.hpp
Expand Up @@ -66,13 +66,13 @@ namespace boost
public:
BOOST_THREAD_MOVABLE(nullary_function)

nullary_function(void (*f)()):
explicit nullary_function(void (*f)()):
impl(new impl_type_ptr(f))
{}

#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
template<typename F>
nullary_function(F& f):
explicit nullary_function(F& f):
impl(new impl_type<F>(f))
{}
#endif
Expand Down
4 changes: 1 addition & 3 deletions include/boost/thread/detail/thread.hpp
Expand Up @@ -64,11 +64,9 @@ namespace boost
{
public:
BOOST_THREAD_NO_COPYABLE(thread_data)
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_):
fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...)
{}
#endif
template <std::size_t ...Indices>
void run2(tuple_indices<Indices...>)
{
Expand Down Expand Up @@ -174,7 +172,7 @@ namespace boost
private:
bool start_thread_noexcept();
bool start_thread_noexcept(const attributes& attr);
public:
//public:
void start_thread()
{
if (!start_thread_noexcept())
Expand Down
4 changes: 2 additions & 2 deletions include/boost/thread/detail/variadic_header.hpp
Expand Up @@ -5,7 +5,7 @@

#include <boost/config.hpp>

#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
//#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES

#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
Expand All @@ -15,5 +15,5 @@
#define BOOST_THREAD_MAX_ARGS 9
#endif

#endif
//#endif

44 changes: 44 additions & 0 deletions include/boost/thread/exceptional_ptr.hpp
@@ -0,0 +1,44 @@
// 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)
// (C) Copyright 2014 Vicente J. Botet Escriba

#ifndef BOOST_THREAD_EXCEPTIONAL_PTR_HPP
#define BOOST_THREAD_EXCEPTIONAL_PTR_HPP

#include <boost/thread/detail/move.hpp>
#include <boost/exception_ptr.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{
struct exceptional_ptr {
exception_ptr ptr_;

exceptional_ptr() : ptr_() {}
explicit exceptional_ptr(exception_ptr ex) : ptr_(ex) {}
template <class E>
explicit exceptional_ptr(BOOST_FWD_REF(E) ex) : ptr_(boost::copy_exception(boost::forward<E>(ex))) {}
};

template <class E>
inline exceptional_ptr make_exceptional(BOOST_FWD_REF(E) ex) {
return exceptional_ptr(boost::forward<E>(ex));
}

inline exceptional_ptr make_exceptional(exception_ptr ex)
{
return exceptional_ptr(ex);
}

inline exceptional_ptr make_exceptional()
{
return exceptional_ptr();
}

} // namespace boost

#include <boost/config/abi_suffix.hpp>

#endif
225 changes: 2 additions & 223 deletions include/boost/thread/executor.hpp
Expand Up @@ -9,228 +9,7 @@
#ifndef BOOST_THREAD_EXECUTOR_HPP
#define BOOST_THREAD_EXECUTOR_HPP

#include <boost/thread/detail/config.hpp>


#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/detail/work.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{

class executor
{
public:
/// type-erasure to store the works to do
typedef thread_detail::work work;

/// executor is not copyable.
BOOST_THREAD_NO_COPYABLE(executor)
executor() {}

/**
* \b Effects: Destroys the executor.
*
* \b Synchronization: The completion of all the closures happen before the completion of the executor destructor.
*/
virtual ~executor() {};

/**
* \b Effects: close the \c executor for submissions.
* The worker threads will work until there is no more closures to run.
*/
virtual void close() = 0;

/**
* \b Returns: whether the pool is closed for submissions.
*/
virtual bool closed() = 0;

/**
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/
virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0;

/**
* \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
*
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
submit(boost::move(w));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
submit(boost::move(w));
}

template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w = boost::move(closure);
submit(boost::move(w));
}

/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
virtual bool try_executing_one() = 0;

/**
* \b Requires: This must be called from an scheduled task.
*
* \b Effects: reschedule functions until pred()
*/
template <typename Pred>
bool reschedule_until(Pred const& pred)
{
do {
//schedule_one_or_yield();
if ( ! try_executing_one())
{
return false;
}
} while (! pred());
return true;
}
};

/**
* Polymorphic adaptor of a model of Executor to an executor.
*/
template <typename Executor>
class executor_adaptor : public executor
{
Executor ex;
public:
/// type-erasure to store the works to do
typedef executor::work work;

/// executor is not copyable.
BOOST_THREAD_NO_COPYABLE(executor_adaptor)

/**
* executor_adaptor constructor
*/
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename ...Args>
executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward<Args>(args)...) {}
#else
/**
* executor_adaptor constructor
*/
executor_adaptor() : ex() {}

template <typename A1>
executor_adaptor(
BOOST_THREAD_FWD_REF(A1) a1
) :
ex(
boost::forward<A1>(a1)
) {}
template <typename A1, typename A2>
executor_adaptor(
BOOST_THREAD_FWD_REF(A1) a1,
BOOST_THREAD_FWD_REF(A2) a2
) :
ex(
boost::forward<A1>(a1),
boost::forward<A2>(a2)
) {}
template <typename A1, typename A2, typename A3>
executor_adaptor(
BOOST_THREAD_FWD_REF(A1) a1,
BOOST_THREAD_FWD_REF(A2) a2,
BOOST_THREAD_FWD_REF(A3) a3
) :
ex(
boost::forward<A1>(a1),
boost::forward<A2>(a2),
boost::forward<A3>(a3)
) {}
#endif
Executor& underlying_executor() { return ex; }

/**
* \b Effects: close the \c executor for submissions.
* The worker threads will work until there is no more closures to run.
*/
void close() { ex.close(); }

/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed() { return ex.closed(); }

/**
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/
void submit(BOOST_THREAD_RV_REF(work) closure) {
return ex.submit(boost::move(closure));
}

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
submit(boost::move(w));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
submit(boost::move(w));
}

template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
submit(boost::move(w));
}

/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one() { return ex.try_executing_one(); }

};

}

#include <boost/config/abi_suffix.hpp>
#include <boost/thread/executors/executor.hpp>
#include <boost/thread/executors/executor_adaptor.hpp>

#endif
326 changes: 326 additions & 0 deletions include/boost/thread/executors/basic_thread_pool.hpp
@@ -0,0 +1,326 @@
// Copyright (C) 2013 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)
//
// 2013/09 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation
// first implementation of a simple pool thread using a vector of threads and a sync_queue.

#ifndef BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
#define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP

#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/sync_queue.hpp>
#include <boost/thread/executors/work.hpp>
#include <boost/thread/csbl/vector.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{
namespace executors
{
class basic_thread_pool
{
public:
/// type-erasure to store the works to do
typedef executors::work work;
private:
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
/// A move aware vector type
typedef scoped_thread<> thread_t;
typedef csbl::vector<thread_t> thread_vector;

/// the thread safe work queue
sync_queue<work > work_queue;
/// A move aware vector
thread_vector threads;

public:
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one()
{
work task;
try
{
if (work_queue.try_pull_front(task) == queue_op_status::success)
{
task();
return true;
}
return false;
}
catch (std::exception& )
{
return false;
}
catch (...)
{
return false;
}
}
private:
/**
* Effects: schedule one task or yields
* Throws: whatever the current task constructor throws or the task() throws.
*/
void schedule_one_or_yield()
{
if ( ! try_executing_one())
{
this_thread::yield();
}
}

/**
* The main loop of the worker threads
*/
void worker_thread()
{
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
}
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class AtThreadEntry>
void worker_thread1(AtThreadEntry& at_thread_entry)
{
at_thread_entry(*this);
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
}
#endif
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
{
at_thread_entry(*this);
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
}
template <class AtThreadEntry>
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
{
at_thread_entry(*this);
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
}
static void do_nothing_at_thread_entry(basic_thread_pool&) {}

public:
/// basic_thread_pool is not copyable.
BOOST_THREAD_NO_COPYABLE(basic_thread_pool)

/**
* \b Effects: creates a thread pool that runs closures on \c thread_count threads.
*
* \b Throws: Whatever exception is thrown while initializing the needed resources.
*/
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
{
try
{
threads.reserve(thread_count);
for (unsigned i = 0; i < thread_count; ++i)
{
#if 1
thread th (&basic_thread_pool::worker_thread, this);
threads.push_back(thread_t(boost::move(th)));
#else
threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
#endif
}
}
catch (...)
{
close();
throw;
}
}
/**
* \b Effects: creates a thread pool that runs closures on \c thread_count threads
* and executes the at_thread_entry function at the entry of each created thread. .
*
* \b Throws: Whatever exception is thrown while initializing the needed resources.
*/
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <class AtThreadEntry>
basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry)
{
try
{
threads.reserve(thread_count);
for (unsigned i = 0; i < thread_count; ++i)
{
thread th (&basic_thread_pool::worker_thread1<AtThreadEntry>, this, at_thread_entry);
threads.push_back(thread_t(boost::move(th)));
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
}
}
catch (...)
{
close();
throw;
}
}
#endif
basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool&))
{
try
{
threads.reserve(thread_count);
for (unsigned i = 0; i < thread_count; ++i)
{
thread th (&basic_thread_pool::worker_thread2, this, at_thread_entry);
threads.push_back(thread_t(boost::move(th)));
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
}
}
catch (...)
{
close();
throw;
}
}
template <class AtThreadEntry>
basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
{
try
{
threads.reserve(thread_count);
for (unsigned i = 0; i < thread_count; ++i)
{
thread th (&basic_thread_pool::worker_thread3<AtThreadEntry>, this, boost::forward<AtThreadEntry>(at_thread_entry));
threads.push_back(thread_t(boost::move(th)));
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
}
}
catch (...)
{
close();
throw;
}
}
/**
* \b Effects: Destroys the thread pool.
*
* \b Synchronization: The completion of all the closures happen before the completion of the \c basic_thread_pool destructor.
*/
~basic_thread_pool()
{
// signal to all the worker threads that there will be no more submissions.
close();
// joins all the threads as the threads were scoped_threads
}

/**
* \b Effects: close the \c basic_thread_pool for submissions.
* The worker threads will work until there is no more closures to run.
*/
void close()
{
work_queue.close();
}

/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed()
{
return work_queue.closed();
}

/**
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
*
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the \c basic_thread_pool will call \c std::terminate, as is the case with threads.
*
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
//work w ((closure));
//work_queue.push_back(boost::move(w));
work_queue.push_back(work(closure)); // todo check why this doesn't work
}
#endif
void submit(void (*closure)())
{
//work w ((closure));
//work_queue.push_back(boost::move(w));
work_queue.push_back(work(closure)); // todo check why this doesn't work
}

#if 0
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w = boost::move(closure);
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
}
#else
template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
work_queue.push_back(work(boost::forward<Closure>(closure)));
}
#endif
/**
* \b Requires: This must be called from an scheduled task.
*
* \b Effects: reschedule functions until pred()
*/
template <typename Pred>
bool reschedule_until(Pred const& pred)
{
do {
if ( ! try_executing_one())
{
return false;
}
} while (! pred());
return true;
}

};
}
using executors::basic_thread_pool;

}

#include <boost/config/abi_suffix.hpp>

#endif
129 changes: 129 additions & 0 deletions include/boost/thread/executors/executor.hpp
@@ -0,0 +1,129 @@
// Copyright (C) 2013,2014 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)
//
// 2013/09 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation

#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP

#include <boost/thread/detail/config.hpp>

#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/executors/work.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{
namespace executors
{
class executor
{
public:
/// type-erasure to store the works to do
typedef executors::work work;

/// executor is not copyable.
BOOST_THREAD_NO_COPYABLE(executor)
executor() {}

/**
* \b Effects: Destroys the executor.
*
* \b Synchronization: The completion of all the closures happen before the completion of the executor destructor.
*/
virtual ~executor() {};

/**
* \b Effects: close the \c executor for submissions.
* The worker threads will work until there is no more closures to run.
*/
virtual void close() = 0;

/**
* \b Returns: whether the pool is closed for submissions.
*/
virtual bool closed() = 0;

/**
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/
virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0;

/**
* \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
*
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
submit(boost::move(w));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
submit(boost::move(w));
}

template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w = boost::move(closure);
submit(boost::move(w));
}

/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
virtual bool try_executing_one() = 0;

/**
* \b Requires: This must be called from an scheduled task.
*
* \b Effects: reschedule functions until pred()
*/
template <typename Pred>
bool reschedule_until(Pred const& pred)
{
do {
//schedule_one_or_yield();
if ( ! try_executing_one())
{
return false;
}
} while (! pred());
return true;
}
};


}
using executors::executor;
}

#include <boost/config/abi_suffix.hpp>

#endif
148 changes: 148 additions & 0 deletions include/boost/thread/executors/executor_adaptor.hpp
@@ -0,0 +1,148 @@
// Copyright (C) 2013,2014 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)
//
// 2013/09 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation

#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP

#include <boost/thread/detail/config.hpp>

#include <boost/thread/executors/executor.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{
namespace executors
{
/**
* Polymorphic adaptor of a model of Executor to an executor.
*/
template <typename Executor>
class executor_adaptor : public executor
{
Executor ex;
public:
/// type-erasure to store the works to do
typedef executor::work work;

/// executor is not copyable.
BOOST_THREAD_NO_COPYABLE(executor_adaptor)

/**
* executor_adaptor constructor
*/
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename ...Args>
executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward<Args>(args)...) {}
#else
/**
* executor_adaptor constructor
*/
executor_adaptor() : ex() {}

template <typename A1>
executor_adaptor(
BOOST_THREAD_FWD_REF(A1) a1
) :
ex(
boost::forward<A1>(a1)
) {}
template <typename A1, typename A2>
executor_adaptor(
BOOST_THREAD_FWD_REF(A1) a1,
BOOST_THREAD_FWD_REF(A2) a2
) :
ex(
boost::forward<A1>(a1),
boost::forward<A2>(a2)
) {}
template <typename A1, typename A2, typename A3>
executor_adaptor(
BOOST_THREAD_FWD_REF(A1) a1,
BOOST_THREAD_FWD_REF(A2) a2,
BOOST_THREAD_FWD_REF(A3) a3
) :
ex(
boost::forward<A1>(a1),
boost::forward<A2>(a2),
boost::forward<A3>(a3)
) {}
#endif
Executor& underlying_executor() { return ex; }

/**
* \b Effects: close the \c executor for submissions.
* The worker threads will work until there is no more closures to run.
*/
void close() { ex.close(); }

/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed() { return ex.closed(); }

/**
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/
void submit(BOOST_THREAD_RV_REF(work) closure) {
return ex.submit(boost::move(closure));
//return ex.submit(boost::forward<work>(closure));
}

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
submit(boost::move(w));
//submit(work(closure));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
submit(boost::move(w));
//submit(work(closure));
}

#if 0
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
submit(boost::move(w));
}
#else
template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
submit(work(boost::forward<Closure>(closure)));
}
#endif

/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one() { return ex.try_executing_one(); }

};
}
using executors::executor_adaptor;
}

#include <boost/config/abi_suffix.hpp>

#endif
131 changes: 131 additions & 0 deletions include/boost/thread/executors/inline_executor.hpp
@@ -0,0 +1,131 @@
// Copyright (C) 2014 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)
//
// 2013/11 Vicente J. Botet Escriba
// first implementation of a simple serial scheduler.

#ifndef BOOST_THREAD_INLINE_EXECUTOR_HPP
#define BOOST_THREAD_INLINE_EXECUTOR_HPP

#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/executors/work.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{
namespace executors
{
class inline_executor
{
public:
/// type-erasure to store the works to do
typedef executors::work work;
bool closed_;
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one()
{
return false;
}

public:
/// inline_executor is not copyable.
BOOST_THREAD_NO_COPYABLE(inline_executor)

/**
* \b Effects: creates a inline executor that runs closures immediately.
*
* \b Throws: Nothing.
*/
inline_executor()
: closed_(false)
{
}
/**
* \b Effects: Destroys the inline executor.
*
* \b Synchronization: The completion of all the closures happen before the completion of the \c inline_executor destructor.
*/
~inline_executor()
{
// signal to all the worker thread that there will be no more submissions.
close();
}

/**
* \b Effects: close the \c inline_executor for submissions.
* The loop will work until there is no more closures to run.
*/
void close()
{
closed_ = true;
}

/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed()
{
return closed_;
}

/**
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
*
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the \c inline_executor will call \c std::terminate, as is the case with threads.
*
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
if (closed()) return;
closure();
}
#endif
void submit(void (*closure)())
{
if (closed()) return;
closure();
}

template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
if (closed()) return;
closure();
}

/**
* \b Requires: This must be called from an scheduled task.
*
* \b Effects: reschedule functions until pred()
*/
template <typename Pred>
bool reschedule_until(Pred const& )
{
return false;
}

};
}
using executors::inline_executor;
}

#include <boost/config/abi_suffix.hpp>

#endif
209 changes: 209 additions & 0 deletions include/boost/thread/executors/loop_executor.hpp
@@ -0,0 +1,209 @@
// Copyright (C) 2013,2014 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)
//
// 2013/11 Vicente J. Botet Escriba
// first implementation of a simple user scheduler.
// 2013/11 Vicente J. Botet Escriba
// rename loop_executor.

#ifndef BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
#define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP

#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/sync_queue.hpp>
#include <boost/thread/executors/work.hpp>

#include <boost/config/abi_prefix.hpp>

namespace boost
{
namespace executors
{

class loop_executor
{
public:
/// type-erasure to store the works to do
typedef executors::work work;
private:
/// the thread safe work queue
sync_queue<work > work_queue;

public:
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one()
{
work task;
try
{
if (work_queue.try_pull_front(task) == queue_op_status::success)
{
task();
return true;
}
return false;
}
catch (std::exception& )
{
return false;
}
catch (...)
{
return false;
}
}
private:
/**
* Effects: schedule one task or yields
* Throws: whatever the current task constructor throws or the task() throws.
*/
void schedule_one_or_yield()
{
if ( ! try_executing_one())
{
this_thread::yield();
}
}


/**
* The main loop of the worker thread
*/
void worker_thread()
{
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
}

public:
/// loop_executor is not copyable.
BOOST_THREAD_NO_COPYABLE(loop_executor)

/**
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
*
* \b Throws: Whatever exception is thrown while initializing the needed resources.
*/
loop_executor()
{
}
/**
* \b Effects: Destroys the thread pool.
*
* \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor.
*/
~loop_executor()
{
// signal to all the worker thread that there will be no more submissions.
close();
}

/**
* loop
*/
void loop() { worker_thread(); }
/**
* \b Effects: close the \c loop_executor for submissions.
* The loop will work until there is no more closures to run.
*/
void close()
{
work_queue.close();
}

/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed()
{
return work_queue.closed();
}

/**
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
*
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
* If invoked closure throws an exception the \c loop_executor will call \c std::terminate, as is the case with threads.
*
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
*
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
work_queue.push_back(boost::move(w));
//work_queue.push(work(closure)); // todo check why this doesn't work
}
#endif
void submit(void (*closure)())
{
work w ((closure));
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(closure)); // todo check why this doesn't work
}

template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
}

/**
* \b Requires: This must be called from an scheduled task.
*
* \b Effects: reschedule functions until pred()
*/
template <typename Pred>
bool reschedule_until(Pred const& pred)
{
do {
if ( ! try_executing_one())
{
return false;
}
} while (! pred());
return true;
}
/**
* run queued closures
*/
void run_queued_closures()
{
sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
while (q.empty())
{
work task = q.front();
q.pop_front();
task();
}
}

};
}
using executors::loop_executor;

}

#include <boost/config/abi_suffix.hpp>

#endif