mirror of
https://github.com/boostorg/thread.git
synced 2026-02-09 23:42:18 +00:00
Compare commits
70 Commits
boost-1.58
...
fix/make_e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bde5a1ef55 | ||
|
|
4d45da6c06 | ||
|
|
e39703ff18 | ||
|
|
aafd5ca726 | ||
|
|
9b69912801 | ||
|
|
259c08473d | ||
|
|
6ca3a99cbc | ||
|
|
3dcd875944 | ||
|
|
58e8addad6 | ||
|
|
87615d54dd | ||
|
|
d322aba077 | ||
|
|
c0afe2d873 | ||
|
|
5488482a44 | ||
|
|
71d9a0a120 | ||
|
|
b7b2a463cf | ||
|
|
1b2736012c | ||
|
|
5205fa71bf | ||
|
|
ba2988a8f7 | ||
|
|
e598796eaf | ||
|
|
bce7eabba2 | ||
|
|
0218136ed7 | ||
|
|
461bf803fc | ||
|
|
1bd78bbeea | ||
|
|
348da6b7e4 | ||
|
|
e850218c49 | ||
|
|
385eefd3b3 | ||
|
|
2ddf7aad0b | ||
|
|
c9433c2a5b | ||
|
|
8853a4cbdf | ||
|
|
6f53279b50 | ||
|
|
a741bd1bba | ||
|
|
5c442e068c | ||
|
|
0bed674233 | ||
|
|
66193b0d38 | ||
|
|
45c9a1d7fd | ||
|
|
0d8ddfe378 | ||
|
|
74f479d5c9 | ||
|
|
dbf793e7eb | ||
|
|
b5c6f760c5 | ||
|
|
caaa7b4cc2 | ||
|
|
9a05211faa | ||
|
|
7ffcec448c | ||
|
|
62bffed368 | ||
|
|
5a1de7a722 | ||
|
|
33ee3445af | ||
|
|
8511771816 | ||
|
|
7dbd04197d | ||
|
|
a53f31fb99 | ||
|
|
b2b8684d0c | ||
|
|
df14c8ac18 | ||
|
|
6e5a46c16f | ||
|
|
264ed4c308 | ||
|
|
65c4693c87 | ||
|
|
05d6eca09d | ||
|
|
c192777aef | ||
|
|
fdd1db970d | ||
|
|
3bc5fb1725 | ||
|
|
9481562b5c | ||
|
|
e44b5309ae | ||
|
|
eecf8f6c36 | ||
|
|
532d215de9 | ||
|
|
71bce54c71 | ||
|
|
41bde57707 | ||
|
|
ff7e394084 | ||
|
|
81f67eeb54 | ||
|
|
a4827a31f3 | ||
|
|
cd31e9c34f | ||
|
|
9492bcd485 | ||
|
|
ff9457e79c | ||
|
|
de580474a3 |
@@ -1,5 +1,5 @@
|
|||||||
[/
|
[/
|
||||||
/ 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
|
/ 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)
|
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -174,7 +174,7 @@ This has several advantages:
|
|||||||
* The scheduled operations are available for all the executors via wrappers.
|
* The scheduled operations are available for all the executors via wrappers.
|
||||||
* The template functions could accept any chrono `time_point` and `duration` respectively as we are not working with virtual functions.
|
* The template functions could accept any chrono `time_point` and `duration` respectively as we are not working with virtual functions.
|
||||||
|
|
||||||
In order to manage with all the clocks, this library propose generic solution. `scheduler<Clock>` know how to manage with the `submit_at`/`submit_after` `Clock::time_point`/`Clock::duration` tasks. Note that the durations on different clocks differ.
|
In order to manage with all the clocks, this library propose a generic solution. `scheduler<Clock>` know how to manage with the `submit_at`/`submit_after` `Clock::time_point`/`Clock::duration` tasks. Note that the durations on different clocks differ.
|
||||||
|
|
||||||
[heading Not Handled Exceptions]
|
[heading Not Handled Exceptions]
|
||||||
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
|
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
|
||||||
@@ -506,9 +506,6 @@ Executor abstract base class.
|
|||||||
public:
|
public:
|
||||||
typedef boost::work work;
|
typedef boost::work work;
|
||||||
|
|
||||||
executor(executor const&) = delete;
|
|
||||||
executor& operator=(executor const&) = delete;
|
|
||||||
|
|
||||||
executor();
|
executor();
|
||||||
virtual ~executor() {};
|
virtual ~executor() {};
|
||||||
|
|
||||||
@@ -573,9 +570,6 @@ Polymorphic adaptor of a model of Executor to an executor.
|
|||||||
public:
|
public:
|
||||||
typedef executor::work work;
|
typedef executor::work work;
|
||||||
|
|
||||||
executor_adaptor(executor_adaptor const&) = delete;
|
|
||||||
executor_adaptor& operator=(executor_adaptor const&) = delete;
|
|
||||||
|
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
executor_adaptor(Args&& ... args);
|
executor_adaptor(Args&& ... args);
|
||||||
|
|
||||||
@@ -641,20 +635,24 @@ Polymorphic adaptor of a model of Executor to an executor.
|
|||||||
[/////////////////////////////////]
|
[/////////////////////////////////]
|
||||||
[section:generic_executor_ref Class `generic_executor_ref`]
|
[section:generic_executor_ref Class `generic_executor_ref`]
|
||||||
|
|
||||||
Executor abstract base class.
|
Type erased executor class.
|
||||||
|
|
||||||
#include <boost/thread/generic_executor_ref.hpp>
|
#include <boost/thread/generic_executor_ref.hpp>
|
||||||
namespace boost {
|
namespace boost {
|
||||||
class generic_executor_ref
|
class generic_executor_ref
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
generic_executor_ref(generic_executor_ref const&);
|
|
||||||
generic_executor_ref& operator=(generic_executor_ref const&);
|
|
||||||
|
|
||||||
template <class Executor>
|
template <class Executor>
|
||||||
generic_executor_ref(Executor& ex);
|
generic_executor_ref(Executor& ex);
|
||||||
generic_executor_ref() {};
|
generic_executor_ref() = delete;
|
||||||
|
generic_executor_ref(generic_executor_ref const&) = default;
|
||||||
|
generic_executor_ref(generic_executor_ref &&) = default;
|
||||||
|
generic_executor_ref& operator=(generic_executor_ref const&) = default;
|
||||||
|
generic_executor_ref& operator=(generic_executor_ref &&) = default;
|
||||||
|
|
||||||
|
executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
void close() = 0;
|
void close() = 0;
|
||||||
bool closed() = 0;
|
bool closed() = 0;
|
||||||
|
|
||||||
@@ -669,6 +667,44 @@ Executor abstract base class.
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
[/////////////////////////////////]
|
||||||
|
[section:generic_executor Class `generic_executor`]
|
||||||
|
|
||||||
|
Type erased executor class.
|
||||||
|
|
||||||
|
#include <boost/thread/generic_executor.hpp>
|
||||||
|
namespace boost {
|
||||||
|
class generic_executor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
template <class Executor>
|
||||||
|
generic_executor(Executor& ex);
|
||||||
|
generic_executor() = delete;
|
||||||
|
|
||||||
|
generic_executor(generic_executor const&) = default;
|
||||||
|
generic_executor(generic_executor &&) = default;
|
||||||
|
generic_executor& operator=(generic_executor const&) = default;
|
||||||
|
generic_executor& operator=(generic_executor &&) = default;
|
||||||
|
|
||||||
|
executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
|
void close() = 0;
|
||||||
|
bool closed() = 0;
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(Closure&& closure);
|
||||||
|
|
||||||
|
virtual bool try_executing_one() = 0;
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& pred);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
[//////////////////////////////////////////////////////////]
|
[//////////////////////////////////////////////////////////]
|
||||||
[section: scheduler Template Class `scheduler `]
|
[section: scheduler Template Class `scheduler `]
|
||||||
|
|
||||||
@@ -683,10 +719,7 @@ Scheduler providing time related functions. Note that `scheduler` is not an Exec
|
|||||||
public:
|
public:
|
||||||
using work = boost::function<void()> ;
|
using work = boost::function<void()> ;
|
||||||
using clock = Clock;
|
using clock = Clock;
|
||||||
|
|
||||||
scheduler(scheduler const&) = delete;
|
|
||||||
scheduler& operator=(scheduler const&) = delete;
|
|
||||||
|
|
||||||
scheduler();
|
scheduler();
|
||||||
~scheduler();
|
~scheduler();
|
||||||
|
|
||||||
@@ -733,7 +766,7 @@ Scheduler providing time related functions. Note that `scheduler` is not an Exec
|
|||||||
|
|
||||||
[[Effects:] [Destroys the scheduler.]]
|
[[Effects:] [Destroys the scheduler.]]
|
||||||
|
|
||||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
[[Synchronization:] [The completion of all the closures happen before the completion of the destructor.]]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1339,10 +1372,6 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
class serial_executor
|
class serial_executor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
serial_executor(serial_executor const&) = delete;
|
|
||||||
serial_executor& operator=(serial_executor const&) = delete;
|
|
||||||
|
|
||||||
template <class Executor>
|
|
||||||
serial_executor(Executor& ex);
|
serial_executor(Executor& ex);
|
||||||
|
|
||||||
Executor& underlying_executor() noexcept;
|
Executor& underlying_executor() noexcept;
|
||||||
@@ -1393,7 +1422,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
[/////////////////////////////////////]
|
[/////////////////////////////////////]
|
||||||
[section:underlying_executor Function member `underlying_executor()`]
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
|
|
||||||
generic_executor_ref& underlying_executor() noexcept;
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
@@ -1418,13 +1447,10 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
class generic_serial_executor
|
class generic_serial_executor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
generic_serial_executor(generic_serial_executor const&) = delete;
|
|
||||||
generic_serial_executor& operator=(generic_serial_executor const&) = delete;
|
|
||||||
|
|
||||||
template <class Executor>
|
template <class Executor>
|
||||||
generic_serial_executor(Executor& ex);
|
generic_serial_executor(Executor& ex);
|
||||||
|
|
||||||
generic_executor_ref& underlying_executor() noexcept;
|
generic_executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
bool closed();
|
bool closed();
|
||||||
@@ -1433,6 +1459,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
void submit(Closure&& closure);
|
void submit(Closure&& closure);
|
||||||
|
|
||||||
bool try_executing_one();
|
bool try_executing_one();
|
||||||
|
|
||||||
template <typename Pred>
|
template <typename Pred>
|
||||||
bool reschedule_until(Pred const& pred);
|
bool reschedule_until(Pred const& pred);
|
||||||
|
|
||||||
@@ -1456,7 +1483,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
[/////////////////////////////////////]
|
[/////////////////////////////////////]
|
||||||
[section:destructor Destructor `~serial_executor()`]
|
[section:destructor Destructor `~generic_serial_executor()`]
|
||||||
|
|
||||||
~generic_serial_executor();
|
~generic_serial_executor();
|
||||||
|
|
||||||
@@ -1468,6 +1495,80 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
[/////////////////////////////////////]
|
||||||
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
|
|
||||||
|
generic_executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Return:] [The underlying executor instance. ]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[//////////////////////////////////////////////////////////]
|
||||||
|
[section:serial_executor_cont Template Class `serial_executor_cont`]
|
||||||
|
|
||||||
|
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||||
|
|
||||||
|
#include <boost/thread/serial_executor_cont.hpp>
|
||||||
|
namespace boost {
|
||||||
|
template <class Executor>
|
||||||
|
class serial_executor_cont
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
serial_executor_cont(Executor& ex);
|
||||||
|
|
||||||
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
|
void close();
|
||||||
|
bool closed();
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(Closure&& closure);
|
||||||
|
|
||||||
|
bool try_executing_one();
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& pred);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[/////////////////////////////////////]
|
||||||
|
[section:constructor Constructor `serial_executor_cont(Executor&)`]
|
||||||
|
|
||||||
|
template <class Executor>
|
||||||
|
serial_executor_cont(Executor& ex);
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Constructs a serial_executor_cont. ]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing. ]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
[/////////////////////////////////////]
|
||||||
|
[section:destructor Destructor `~serial_executor_cont()`]
|
||||||
|
|
||||||
|
~serial_executor_cont();
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Destroys the serial_executor.]]
|
||||||
|
|
||||||
|
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
[/////////////////////////////////////]
|
[/////////////////////////////////////]
|
||||||
[section:underlying_executor Function member `underlying_executor()`]
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
@@ -1478,6 +1579,8 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
|
|
||||||
[[Return:] [The underlying executor instance. ]]
|
[[Return:] [The underlying executor instance. ]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -1485,6 +1588,82 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
[//////////////////////////////////////////////////////////]
|
||||||
|
[section:generic_serial_cont_executor Class `generic_serial_cont_executor`]
|
||||||
|
|
||||||
|
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||||
|
|
||||||
|
#include <boost/thread/generic_serial_cont_executor.hpp>
|
||||||
|
namespace boost {
|
||||||
|
class generic_serial_cont_executor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <class Executor>
|
||||||
|
generic_serial_cont_executor(Executor& ex);
|
||||||
|
|
||||||
|
generic_executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
|
void close();
|
||||||
|
bool closed();
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(Closure&& closure);
|
||||||
|
|
||||||
|
bool try_executing_one();
|
||||||
|
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& pred);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[/////////////////////////////////////]
|
||||||
|
[section:constructor Constructor `generic_serial_cont_executor(Executor&)`]
|
||||||
|
|
||||||
|
template <class Executor>
|
||||||
|
generic_serial_cont_executor(Executor& ex);
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Constructs a generic_serial_cont_executor. ]]
|
||||||
|
|
||||||
|
[[Throws:] [Nothing. ]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
[/////////////////////////////////////]
|
||||||
|
[section:destructor Destructor `~generic_serial_cont_executor()`]
|
||||||
|
|
||||||
|
~generic_serial_cont_executor();
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Effects:] [Destroys the generic_serial_cont_executor.]]
|
||||||
|
|
||||||
|
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
[/////////////////////////////////////]
|
||||||
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
|
|
||||||
|
generic_executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[Return:] [The underlying executor instance. ]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[//////////////////////////////////////////////////////////]
|
[//////////////////////////////////////////////////////////]
|
||||||
[section:inline_executor Class `inline_executor`]
|
[section:inline_executor Class `inline_executor`]
|
||||||
@@ -1496,10 +1675,8 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
class inline_executor
|
class inline_executor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline_executor(inline_executor const&) = delete;
|
|
||||||
inline_executor& operator=(inline_executor const&) = delete;
|
|
||||||
|
|
||||||
inline_executor();
|
inline_executor();
|
||||||
|
~inline_executor();
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
bool closed();
|
bool closed();
|
||||||
@@ -1560,9 +1737,6 @@ A thread pool with up to a fixed number of threads.
|
|||||||
class basic_thread_pool
|
class basic_thread_pool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
basic_thread_pool(basic_thread_pool const&) = delete;
|
|
||||||
basic_thread_pool& operator=(basic_thread_pool const&) = delete;
|
|
||||||
|
|
||||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency());
|
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency());
|
||||||
template <class AtThreadEntry>
|
template <class AtThreadEntry>
|
||||||
@@ -1623,9 +1797,6 @@ A thread_executor with a threads for each task.
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
thread_executor(thread_executor const&) = delete;
|
|
||||||
thread_executor& operator=(thread_executor const&) = delete;
|
|
||||||
|
|
||||||
thread_executor();
|
thread_executor();
|
||||||
template <class AtThreadEntry>
|
template <class AtThreadEntry>
|
||||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
|
basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
|
||||||
@@ -1680,9 +1851,6 @@ A user scheduled executor.
|
|||||||
class loop_executor
|
class loop_executor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
loop_executor(loop_executor const&) = delete;
|
|
||||||
loop_executor& operator=(loop_executor const&) = delete;
|
|
||||||
|
|
||||||
loop_executor();
|
loop_executor();
|
||||||
~loop_executor();
|
~loop_executor();
|
||||||
|
|||||||
@@ -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.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
(See accompanying file LICENSE_1_0.txt or copy at
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
http://www.boost.org/LICENSE_1_0.txt).
|
http://www.boost.org/LICENSE_1_0.txt).
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:compliance Conformance and Extension]
|
[section:compliance Conformance and Extension]
|
||||||
|
[////////////////////////////////////////////]
|
||||||
|
|
||||||
[section:cpp11 C++11 standard Thread library]
|
[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++]]]
|
[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]
|
[endsect]
|
||||||
[section:cxx14 C++14 standard Thread library - accepted changes]
|
[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++]]
|
[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 ]
|
[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]]
|
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4107.html N4107-Extensions for Concurrency]]
|
||||||
|
|
||||||
@@ -126,8 +130,10 @@
|
|||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section:cxx1y C++1z TS Concurrency - On going proposals]
|
[section:cxx1y C++1z TS Concurrency - On going proposals]
|
||||||
|
[///////////////////////////////////////////////////////]
|
||||||
|
|
||||||
[section:latch C++ Latches and Barriers]
|
[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/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]]
|
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3817.html N3817 C++ Latches and Barriers]]
|
||||||
@@ -140,6 +146,7 @@
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
[section:queue C++ Concurrent Queues]
|
[section:queue C++ Concurrent Queues]
|
||||||
|
[///////////////////////////////////]
|
||||||
|
|
||||||
[note [@ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html N3533 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] [ - ]]
|
[[X.3.4] [Managed Indirection] [No] [ - ]]
|
||||||
]
|
]
|
||||||
[endsect]
|
[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]]
|
[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]]
|
[[Section] [Description] [Status] [Comments]]
|
||||||
[[V.1.1] [Class executor] [Yes] [ - ]]
|
[[V.1.1] [Class `executor`] [Yes] [ - ]]
|
||||||
[[V.1.1] [add] [Yes] [ renamed with a function template submit ]]
|
[[V.1.1] [`add`] [Yes] [ renamed with a function template `submit` ]]
|
||||||
[[V.1.1] [num_of_pendin_closures] [No] [ ]]
|
[[V.1.1] [`num_of_pendin_closures`] [No] [ ]]
|
||||||
[[V.1.2] [Class sceduled_executor] [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_at`] [No] [ renamed with a function template `scheduler::submit_at` ]]
|
||||||
[[V.1.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
[[V.1.2] [`add_after`] [No] [ renamed with a function template `scheduler::submit_after` ]]
|
||||||
[[V.2] [Concrete executor classes] [No] [ - ]]
|
[[V.2] [Concrete executor classes] [No] [ - ]]
|
||||||
[[V.2.1] [thread_pool] [Yes] [ static version Basic_thread_pool, dynamic one execduler_adaptor<basic_thread_pool> ]]
|
[[V.2.1] [`thread_pool`] [Yes] [ static version `basic_thread_pool`, dynamic one `execduler_adaptor<basic_thread_pool>` ]]
|
||||||
[[V.2.2] [serial_executor] [yes] [ - ]]
|
[[V.2.2] [`serial_executor`] [yes] [ - ]]
|
||||||
[[V.2.3] [loop_executor] [Yes] [ static version loop_scheduler, dynamic one execduler_adaptor<loop_scheduler> ]]
|
[[V.2.3] [`loop_executor`] [Yes] [ static version loop_scheduler, dynamic one `execduler_adaptor<loop_scheduler>` ]]
|
||||||
[[V.2.4] [inline_executor] [Yes] [ static version inline_executor, dynamic one execduler_adaptor<inline_executor> ]]
|
[[V.2.4] [`inline_executor`] [Yes] [ static version `inline_executor`, dynamic one `execduler_adaptor<inline_executor>` ]]
|
||||||
[[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor<thread_executor> ]]
|
[[V.2.5] [`thread_executor`] [Yes] [ static version `thread_executor`, dynamic one `execduler_adaptor<thread_executor>` ]]
|
||||||
]
|
]
|
||||||
|
|
||||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3784.pdf N3784-Improvements to `std::future<T> and Related APIs]]
|
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3784.pdf N3784-Improvements to `std::future<T> and Related APIs]]
|
||||||
@@ -212,8 +220,31 @@
|
|||||||
[[30.6.8] [`async`] [Yes] [ - ]]
|
[[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]
|
[endsect]
|
||||||
|
[//////////////////////////////////////////////////////////////
|
||||||
[section:stream_mutex C++ Stream Mutexes - C++ Stream Guards]
|
[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.
|
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]
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
[section:tutorial Tutorial]
|
[section:tutorial Tutorial]
|
||||||
|
|
||||||
[@http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost.
|
[@http://web.archive.org/web/20140531071228/http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost.
|
||||||
|
|
||||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html Mutex, Lock, Condition Variable Rationale] adds rationale for the design decisions made for mutexes, locks and condition variables.
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html Mutex, Lock, Condition Variable Rationale] adds rationale for the design decisions made for mutexes, locks and condition variables.
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#include <boost/thread/caller_context.hpp>
|
#include <boost/thread/caller_context.hpp>
|
||||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
#include <boost/thread/executors/loop_executor.hpp>
|
#include <boost/thread/executors/loop_executor.hpp>
|
||||||
#include <boost/thread/executors/serial_executor.hpp>
|
#include <boost/thread/executors/generic_serial_executor.hpp>
|
||||||
#include <boost/thread/executors/inline_executor.hpp>
|
#include <boost/thread/executors/inline_executor.hpp>
|
||||||
#include <boost/thread/executors/thread_executor.hpp>
|
#include <boost/thread/executors/thread_executor.hpp>
|
||||||
#include <boost/thread/executors/executor.hpp>
|
#include <boost/thread/executors/executor.hpp>
|
||||||
@@ -27,6 +27,12 @@
|
|||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
boost::future<void> p(boost::future<void> f) {
|
||||||
|
assert(f.is_ready());
|
||||||
|
return boost::make_ready_future();
|
||||||
|
}
|
||||||
|
|
||||||
void p1()
|
void p1()
|
||||||
{
|
{
|
||||||
@@ -65,7 +71,7 @@ void submit_some(boost::executor& tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void at_th_entry(boost::basic_thread_pool& )
|
void at_th_entry(boost::basic_thread_pool )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -76,6 +82,10 @@ int test_executor_adaptor()
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool e1;
|
||||||
|
boost::basic_thread_pool e2 = e1;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
boost::executor_adaptor < boost::basic_thread_pool > ea(4);
|
boost::executor_adaptor < boost::basic_thread_pool > ea(4);
|
||||||
submit_some( ea);
|
submit_some( ea);
|
||||||
@@ -98,25 +108,65 @@ int test_executor_adaptor()
|
|||||||
submit_some(ea);
|
submit_some(ea);
|
||||||
}
|
}
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::loop_executor e1;
|
||||||
|
boost::loop_executor e2 = e1;
|
||||||
|
boost::executor_adaptor < boost::loop_executor > ea2(e2);
|
||||||
|
submit_some( ea2);
|
||||||
|
ea2.underlying_executor().run_queued_closures();
|
||||||
|
}
|
||||||
{
|
{
|
||||||
boost::executor_adaptor < boost::loop_executor > ea2;
|
boost::executor_adaptor < boost::loop_executor > ea2;
|
||||||
submit_some( ea2);
|
submit_some( ea2);
|
||||||
ea2.underlying_executor().run_queued_closures();
|
ea2.underlying_executor().run_queued_closures();
|
||||||
}
|
}
|
||||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
{
|
{
|
||||||
boost::executor_adaptor < boost::basic_thread_pool > ea1(4);
|
boost::basic_thread_pool tp;
|
||||||
boost::executor_adaptor < boost::serial_executor > ea2(ea1);
|
boost::generic_serial_executor e1(tp);
|
||||||
|
boost::generic_serial_executor e2 = e1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool ea1(4);
|
||||||
|
boost::generic_serial_executor ea2(ea1);
|
||||||
|
boost::executor_adaptor < boost::generic_serial_executor > ea3(ea2);
|
||||||
|
submit_some(ea3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool ea1(4);
|
||||||
|
boost::generic_serial_executor ea2(ea1);
|
||||||
|
boost::executor_adaptor < boost::generic_serial_executor > ea3(ea2);
|
||||||
|
submit_some(ea3);
|
||||||
|
}
|
||||||
|
//#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool ea1(4);
|
||||||
|
boost::executor_adaptor < boost::generic_serial_executor > ea2(ea1);
|
||||||
submit_some(ea2);
|
submit_some(ea2);
|
||||||
}
|
}
|
||||||
#endif
|
//#endif
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::inline_executor e1;
|
||||||
|
boost::inline_executor e2 = e1;
|
||||||
|
boost::executor_adaptor < boost::inline_executor > ea2(e2);
|
||||||
|
submit_some(ea2);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
boost::executor_adaptor < boost::inline_executor > ea1;
|
boost::executor_adaptor < boost::inline_executor > ea1;
|
||||||
submit_some(ea1);
|
submit_some(ea1);
|
||||||
}
|
}
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::thread_executor e1;
|
||||||
|
boost::thread_executor e2 = e1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::thread_executor e1;
|
||||||
|
boost::executor_adaptor < boost::generic_executor > ea2(e1);
|
||||||
|
submit_some(ea2);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::executor_adaptor < boost::thread_executor > ea1;
|
boost::executor_adaptor < boost::thread_executor > ea1;
|
||||||
submit_some(ea1);
|
submit_some(ea1);
|
||||||
@@ -147,4 +197,19 @@ int test_executor_adaptor()
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
return test_executor_adaptor();
|
return test_executor_adaptor();
|
||||||
|
|
||||||
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||||
|
&& defined BOOST_THREAD_PROVIDES_EXECUTORS \
|
||||||
|
&& ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||||
|
|
||||||
|
boost::basic_thread_pool executor;
|
||||||
|
// compiles
|
||||||
|
boost::make_ready_future().then(&p);
|
||||||
|
|
||||||
|
// ??
|
||||||
|
boost::make_ready_future().then(executor, &p);
|
||||||
|
|
||||||
|
// doesn't compile
|
||||||
|
boost::make_ready_future().then(executor, &p);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
184
example/generic_executor.cpp
Normal file
184
example/generic_executor.cpp
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
// 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 <boost/config.hpp>
|
||||||
|
#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 <boost/thread/caller_context.hpp>
|
||||||
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
|
#include <boost/thread/executors/loop_executor.hpp>
|
||||||
|
#include <boost/thread/executors/generic_serial_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/executors/generic_executor.hpp>
|
||||||
|
#include <boost/thread/executor.hpp>
|
||||||
|
#include <boost/thread/future.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void p1()
|
||||||
|
{
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
//boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
void p2()
|
||||||
|
{
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
//boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
int f1()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_some(boost::generic_executor tp)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
tp.submit(&p2);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
tp.submit(&p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template < class Executor>
|
||||||
|
void submit_some2(Executor& tp)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
tp.submit(&p2);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
tp.submit(&p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Executor>
|
||||||
|
void submit_some3(boost::serial_executor<Executor>& tp)
|
||||||
|
{
|
||||||
|
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 test_generic_executor()
|
||||||
|
{
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::loop_executor ea2;
|
||||||
|
submit_some( ea2);
|
||||||
|
ea2.run_queued_closures();
|
||||||
|
}
|
||||||
|
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
|
// // std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
// {
|
||||||
|
// boost::basic_thread_pool ea1(4);
|
||||||
|
// boost::generic_serial_executor ea2(ea1);
|
||||||
|
// submit_some(ea2);
|
||||||
|
// }
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool ea1(4);
|
||||||
|
boost::serial_executor<boost::basic_thread_pool> ea2(ea1);
|
||||||
|
submit_some3(ea2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::inline_executor ea1;
|
||||||
|
submit_some(ea1);
|
||||||
|
}
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::cout << " ERROR= exception thrown" << std::endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return test_generic_executor();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,11 +17,12 @@
|
|||||||
#include <boost/thread/caller_context.hpp>
|
#include <boost/thread/caller_context.hpp>
|
||||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
#include <boost/thread/executors/loop_executor.hpp>
|
#include <boost/thread/executors/loop_executor.hpp>
|
||||||
#include <boost/thread/executors/serial_executor.hpp>
|
#include <boost/thread/executors/generic_serial_executor.hpp>
|
||||||
#include <boost/thread/executors/inline_executor.hpp>
|
#include <boost/thread/executors/inline_executor.hpp>
|
||||||
#include <boost/thread/executors/thread_executor.hpp>
|
#include <boost/thread/executors/thread_executor.hpp>
|
||||||
#include <boost/thread/executors/executor.hpp>
|
#include <boost/thread/executors/executor.hpp>
|
||||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||||
|
#include <boost/thread/executors/generic_executor_ref.hpp>
|
||||||
#include <boost/thread/executor.hpp>
|
#include <boost/thread/executor.hpp>
|
||||||
#include <boost/thread/future.hpp>
|
#include <boost/thread/future.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
@@ -64,7 +65,7 @@ void submit_some(boost::generic_executor_ref tp)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void at_th_entry(boost::basic_thread_pool& )
|
void at_th_entry(boost::basic_thread_pool)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -108,7 +109,7 @@ int test_generic_executor_ref()
|
|||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
{
|
{
|
||||||
boost::basic_thread_pool ea1(4);
|
boost::basic_thread_pool ea1(4);
|
||||||
boost::serial_executor ea2(ea1);
|
boost::generic_serial_executor ea2(ea1);
|
||||||
submit_some(ea2);
|
submit_some(ea2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
117
example/generic_serial_executor.cpp
Normal file
117
example/generic_serial_executor.cpp
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// Copyright (C) 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 <boost/config.hpp>
|
||||||
|
#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 <boost/thread/caller_context.hpp>
|
||||||
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
|
#include <boost/thread/executors/generic_serial_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 <iostream>
|
||||||
|
|
||||||
|
void p1()
|
||||||
|
{
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(30));
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void p2()
|
||||||
|
{
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f1()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_some(boost::generic_serial_executor& tp)
|
||||||
|
{
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
tp.submit(&p2);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
tp.submit(&p1);
|
||||||
|
}
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void at_th_entry(boost::basic_thread_pool )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_executor_adaptor()
|
||||||
|
{
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool tp;
|
||||||
|
boost::generic_serial_executor e1(tp);
|
||||||
|
boost::generic_serial_executor e2 = e1;
|
||||||
|
}
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool ea1(4);
|
||||||
|
boost::generic_serial_executor ea2(ea1);
|
||||||
|
submit_some(ea2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// std::cout << BOOST_CONTEXTOF << 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return test_executor_adaptor();
|
||||||
|
}
|
||||||
118
example/generic_serial_executor_cont.cpp
Normal file
118
example/generic_serial_executor_cont.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright (C) 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 <boost/config.hpp>
|
||||||
|
#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 <boost/thread/caller_context.hpp>
|
||||||
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
|
#include <boost/thread/executors/generic_serial_executor_cont.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 <iostream>
|
||||||
|
|
||||||
|
void p1()
|
||||||
|
{
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(30));
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void p2()
|
||||||
|
{
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f1()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_some(boost::generic_serial_executor_cont& tp)
|
||||||
|
{
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
tp.submit(&p2);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
tp.submit(&p1);
|
||||||
|
}
|
||||||
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void at_th_entry(boost::basic_thread_pool)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_executor_adaptor()
|
||||||
|
{
|
||||||
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool tp;
|
||||||
|
boost::generic_serial_executor_cont e1(tp);
|
||||||
|
boost::generic_serial_executor_cont e2 = e1;
|
||||||
|
}
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool ea1(4);
|
||||||
|
boost::generic_serial_executor_cont ea2(ea1);
|
||||||
|
submit_some(ea2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// std::cout << BOOST_CONTEXTOF << 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return test_executor_adaptor();
|
||||||
|
}
|
||||||
@@ -42,6 +42,14 @@ int main()
|
|||||||
int result = f2.get();
|
int result = f2.get();
|
||||||
BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG;
|
BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG;
|
||||||
}
|
}
|
||||||
|
#if ! defined BOOST_NO_CXX14_GENERIC_LAMBDAS
|
||||||
|
{
|
||||||
|
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
|
||||||
|
boost::future<int> 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)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -94,6 +94,11 @@ int main()
|
|||||||
f.get();
|
f.get();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||||
|
boost::future<int> f = compute(-1);
|
||||||
|
f.wait();
|
||||||
|
}
|
||||||
{
|
{
|
||||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||||
boost::future<int> f = compute(0);
|
boost::future<int> f = compute(0);
|
||||||
@@ -124,11 +129,11 @@ int main()
|
|||||||
boost::future<int const&> f = boost::make_ready_future(boost::cref(i));
|
boost::future<int const&> f = boost::make_ready_future(boost::cref(i));
|
||||||
std::cout << f.get() << std::endl;
|
std::cout << f.get() << std::endl;
|
||||||
}
|
}
|
||||||
// {
|
{
|
||||||
// std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||||
// boost::future<int> f = compute(2);
|
boost::future<int> f = compute(2);
|
||||||
// std::cout << f.get() << std::endl;
|
std::cout << f.get() << std::endl;
|
||||||
// }
|
}
|
||||||
{
|
{
|
||||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||||
boost::shared_future<int> f = shared_compute(0);
|
boost::shared_future<int> f = shared_compute(0);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||||
|
|
||||||
void producer(the_ostream &mos, boost::sync_queue<int> & sbq)
|
void producer(the_ostream & /*mos*/, boost::sync_queue<int> & sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
try {
|
try {
|
||||||
@@ -32,22 +32,22 @@ void producer(the_ostream &mos, boost::sync_queue<int> & sbq)
|
|||||||
{
|
{
|
||||||
sbq.push(i);
|
sbq.push(i);
|
||||||
//sbq << i;
|
//sbq << i;
|
||||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
//mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||||
this_thread::sleep_for(chrono::milliseconds(200));
|
this_thread::sleep_for(chrono::milliseconds(200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(sync_queue_is_closed&)
|
catch(sync_queue_is_closed&)
|
||||||
{
|
{
|
||||||
mos << "closed !!!\n";
|
//mos << "closed !!!\n";
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void consumer(
|
void consumer(
|
||||||
the_ostream &mos,
|
the_ostream & /*mos*/,
|
||||||
boost::sync_queue<int> & sbq)
|
boost::sync_queue<int> & sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
@@ -57,21 +57,21 @@ void consumer(
|
|||||||
int r;
|
int r;
|
||||||
sbq.pull(r);
|
sbq.pull(r);
|
||||||
//sbq >> r;
|
//sbq >> r;
|
||||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
//mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||||
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(250));
|
this_thread::sleep_for(chrono::milliseconds(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(sync_queue_is_closed&)
|
catch(sync_queue_is_closed&)
|
||||||
{
|
{
|
||||||
mos << "closed !!!\n";
|
//mos << "closed !!!\n";
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
|
void consumer2(the_ostream &/*mos*/, boost::sync_queue<int> & sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
try {
|
try {
|
||||||
@@ -81,17 +81,17 @@ void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
|
|||||||
queue_op_status st = sbq.try_pull(r);
|
queue_op_status st = sbq.try_pull(r);
|
||||||
if (queue_op_status::closed == st) break;
|
if (queue_op_status::closed == st) break;
|
||||||
if (queue_op_status::success == st) {
|
if (queue_op_status::success == st) {
|
||||||
mos << i << " pull(" << r << ")\n";
|
//mos << i << " pull(" << r << ")\n";
|
||||||
}
|
}
|
||||||
this_thread::sleep_for(chrono::milliseconds(250));
|
this_thread::sleep_for(chrono::milliseconds(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
void consumer3(the_ostream &/*mos*/, boost::sync_queue<int> & sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
try {
|
try {
|
||||||
@@ -100,13 +100,13 @@ void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
|||||||
int r;
|
int r;
|
||||||
queue_op_status res = sbq.wait_pull(r);
|
queue_op_status res = sbq.wait_pull(r);
|
||||||
if (res==queue_op_status::closed) break;
|
if (res==queue_op_status::closed) break;
|
||||||
mos << i << " wait_pull(" << r << ")\n";
|
//mos << i << " wait_pull(" << r << ")\n";
|
||||||
this_thread::sleep_for(chrono::milliseconds(250));
|
this_thread::sleep_for(chrono::milliseconds(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
#include <boost/type_traits.hpp>
|
#include <boost/type_traits.hpp>
|
||||||
|
|
||||||
void producer(the_ostream &mos, boost::queue_back<int> sbq)
|
void producer(the_ostream &/*mos*/, boost::queue_back<int> sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
try {
|
try {
|
||||||
@@ -35,22 +35,22 @@ void producer(the_ostream &mos, boost::queue_back<int> sbq)
|
|||||||
{
|
{
|
||||||
sbq.push(i);
|
sbq.push(i);
|
||||||
//sbq << i;
|
//sbq << i;
|
||||||
mos << "push(" << i << ") " << sbq.size() <<"\n";
|
//mos << "push(" << i << ") " << sbq.size() <<"\n";
|
||||||
this_thread::sleep_for(chrono::milliseconds(200));
|
this_thread::sleep_for(chrono::milliseconds(200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(sync_queue_is_closed&)
|
catch(sync_queue_is_closed&)
|
||||||
{
|
{
|
||||||
mos << "closed !!!\n";
|
//mos << "closed !!!\n";
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void consumer(
|
void consumer(
|
||||||
the_ostream &mos,
|
the_ostream &/*mos*/,
|
||||||
boost::queue_front<int> sbq)
|
boost::queue_front<int> sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
@@ -60,21 +60,21 @@ void consumer(
|
|||||||
int r;
|
int r;
|
||||||
sbq.pull(r);
|
sbq.pull(r);
|
||||||
//sbq >> r;
|
//sbq >> r;
|
||||||
mos << i << " pull(" << r << ") " << sbq.size() <<"\n";
|
//mos << i << " pull(" << r << ") " << sbq.size() <<"\n";
|
||||||
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(250));
|
this_thread::sleep_for(chrono::milliseconds(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(sync_queue_is_closed&)
|
catch(sync_queue_is_closed&)
|
||||||
{
|
{
|
||||||
mos << "closed !!!\n";
|
//mos << "closed !!!\n";
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void consumer2(the_ostream &mos, boost::queue_front<int> sbq)
|
void consumer2(the_ostream &/*mos*/, boost::queue_front<int> sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
try {
|
try {
|
||||||
@@ -84,17 +84,17 @@ void consumer2(the_ostream &mos, boost::queue_front<int> sbq)
|
|||||||
queue_op_status st = sbq.try_pull(r);
|
queue_op_status st = sbq.try_pull(r);
|
||||||
if (queue_op_status::closed == st) break;
|
if (queue_op_status::closed == st) break;
|
||||||
if (queue_op_status::success == st) {
|
if (queue_op_status::success == st) {
|
||||||
mos << i << " try_pull(" << r << ")\n";
|
//mos << i << " try_pull(" << r << ")\n";
|
||||||
}
|
}
|
||||||
this_thread::sleep_for(chrono::milliseconds(250));
|
this_thread::sleep_for(chrono::milliseconds(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void consumer3(the_ostream &mos, boost::queue_front<int> sbq)
|
void consumer3(the_ostream &/*mos*/, boost::queue_front<int> sbq)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
try {
|
try {
|
||||||
@@ -103,13 +103,13 @@ void consumer3(the_ostream &mos, boost::queue_front<int> sbq)
|
|||||||
int r;
|
int r;
|
||||||
queue_op_status res = sbq.wait_pull(r);
|
queue_op_status res = sbq.wait_pull(r);
|
||||||
if (res==queue_op_status::closed) break;
|
if (res==queue_op_status::closed) break;
|
||||||
mos << i << " wait_pull(" << r << ")\n";
|
//mos << i << " wait_pull(" << r << ")\n";
|
||||||
this_thread::sleep_for(chrono::milliseconds(250));
|
this_thread::sleep_for(chrono::milliseconds(250));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
mos << "exception !!!\n";
|
//mos << "exception !!!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ counter c;
|
|||||||
|
|
||||||
void change_count()
|
void change_count()
|
||||||
{
|
{
|
||||||
std::cout << "count == " << c.increment() << std::endl;
|
//std::cout << "count == " << c.increment() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int, char*[])
|
int main(int, char*[])
|
||||||
|
|||||||
@@ -27,16 +27,16 @@
|
|||||||
|
|
||||||
void p1()
|
void p1()
|
||||||
{
|
{
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(30));
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(30));
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void p2()
|
void p2()
|
||||||
{
|
{
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int f1()
|
int f1()
|
||||||
@@ -51,10 +51,9 @@ int f2(int i)
|
|||||||
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
template <class Executor>
|
||||||
void submit_some(boost::serial_executor& tp)
|
void submit_some(boost::serial_executor<Executor>& tp)
|
||||||
{
|
{
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
tp.submit(&p2);
|
tp.submit(&p2);
|
||||||
@@ -63,7 +62,6 @@ void submit_some(boost::serial_executor& tp)
|
|||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
tp.submit(&p1);
|
tp.submit(&p1);
|
||||||
}
|
}
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,21 +73,17 @@ void at_th_entry(boost::basic_thread_pool& )
|
|||||||
|
|
||||||
int test_executor_adaptor()
|
int test_executor_adaptor()
|
||||||
{
|
{
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
|
||||||
{
|
{
|
||||||
boost::basic_thread_pool ea1(4);
|
boost::basic_thread_pool ea1(4);
|
||||||
boost::serial_executor ea2(ea1);
|
boost::serial_executor<boost::basic_thread_pool> ea2(ea1);
|
||||||
submit_some(ea2);
|
submit_some(ea2);
|
||||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
@@ -102,7 +96,6 @@ int test_executor_adaptor()
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,18 +52,19 @@ int f2(int i)
|
|||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void submit_some(boost::serial_executor_cont& tp)
|
template < class Executor>
|
||||||
|
void submit_some(boost::serial_executor_cont<Executor>& tp)
|
||||||
{
|
{
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
tp.submit(&p2);
|
tp.submit(&p2);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
tp.submit(&p1);
|
tp.submit(&p1);
|
||||||
}
|
}
|
||||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,9 +85,8 @@ int test_executor_adaptor()
|
|||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
{
|
{
|
||||||
boost::basic_thread_pool ea1(4);
|
boost::basic_thread_pool ea1(4);
|
||||||
boost::serial_executor_cont ea2(ea1);
|
boost::serial_executor_cont<boost::basic_thread_pool> ea2(ea1);
|
||||||
submit_some(ea2);
|
submit_some(ea2);
|
||||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ int main()
|
|||||||
threads.remove_thread(th);
|
threads.remove_thread(th);
|
||||||
BOOST_TEST(! threads.is_thread_in(th));
|
BOOST_TEST(! threads.is_thread_in(th));
|
||||||
th->join();
|
th->join();
|
||||||
|
delete th;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,7 +173,6 @@ namespace boost
|
|||||||
private:
|
private:
|
||||||
bool start_thread_noexcept();
|
bool start_thread_noexcept();
|
||||||
bool start_thread_noexcept(const attributes& attr);
|
bool start_thread_noexcept(const attributes& attr);
|
||||||
//public:
|
|
||||||
void start_thread()
|
void start_thread()
|
||||||
{
|
{
|
||||||
if (!start_thread_noexcept())
|
if (!start_thread_noexcept())
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2013-2014 Vicente J. Botet Escriba
|
// Copyright (C) 2013-2015 Vicente J. Botet Escriba
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,11 +13,16 @@
|
|||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#include <boost/thread/detail/delete.hpp>
|
#include <boost/thread/detail/delete.hpp>
|
||||||
#include <boost/thread/detail/move.hpp>
|
#include <boost/thread/detail/move.hpp>
|
||||||
#include <boost/thread/scoped_thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||||
#include <boost/thread/executors/work.hpp>
|
#include <boost/thread/executors/work.hpp>
|
||||||
#include <boost/thread/csbl/vector.hpp>
|
#include <boost/thread/csbl/vector.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
#include <boost/smart_ptr/enable_shared_from_this.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
@@ -30,125 +35,256 @@ namespace executors
|
|||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
private:
|
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
|
struct shared_state : enable_shared_from_this<shared_state> {
|
||||||
concurrent::sync_queue<work > work_queue;
|
typedef executors::work work;
|
||||||
/// A move aware vector
|
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
|
||||||
thread_vector threads;
|
/// A move aware vector type
|
||||||
|
//typedef scoped_thread<> thread_t;
|
||||||
|
typedef thread thread_t;
|
||||||
|
typedef csbl::vector<thread_t> thread_vector;
|
||||||
|
|
||||||
public:
|
/// the thread safe work queue
|
||||||
/**
|
concurrent::sync_queue<work > work_queue;
|
||||||
* Effects: try to execute one task.
|
/// A move aware vector
|
||||||
* Returns: whether a task has been executed.
|
thread_vector threads;
|
||||||
* Throws: whatever the current task constructor throws or the task() throws.
|
unsigned const thread_count;
|
||||||
*/
|
boost::function<void(basic_thread_pool)> at_thread_entry;
|
||||||
bool try_executing_one()
|
friend class basic_thread_pool;
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
work task;
|
|
||||||
if (work_queue.try_pull(task) == queue_op_status::success)
|
|
||||||
{
|
|
||||||
task();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::terminate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main loop of the worker threads
|
public:
|
||||||
*/
|
/**
|
||||||
void worker_thread()
|
* Effects: try to execute one task.
|
||||||
{
|
* Returns: whether a task has been executed.
|
||||||
try
|
* Throws: whatever the current task constructor throws or the task() throws.
|
||||||
|
*/
|
||||||
|
bool try_executing_one()
|
||||||
{
|
{
|
||||||
for(;;)
|
try
|
||||||
{
|
{
|
||||||
work task;
|
work task;
|
||||||
queue_op_status st = work_queue.wait_pull(task);
|
if (work_queue.try_pull(task) == queue_op_status::success)
|
||||||
if (st == queue_op_status::closed) return;
|
{
|
||||||
task();
|
task();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
/**
|
||||||
|
* Effects: schedule one task or yields
|
||||||
|
* Throws: whatever the current task constructor throws or the task() throws.
|
||||||
|
*/
|
||||||
|
void schedule_one_or_yield()
|
||||||
{
|
{
|
||||||
std::terminate();
|
if ( ! try_executing_one())
|
||||||
return;
|
{
|
||||||
|
this_thread::yield();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
private:
|
||||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
|
||||||
template <class AtThreadEntry>
|
|
||||||
void worker_thread1(AtThreadEntry& at_thread_entry)
|
|
||||||
{
|
|
||||||
at_thread_entry(*this);
|
|
||||||
worker_thread();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
|
|
||||||
{
|
|
||||||
at_thread_entry(*this);
|
|
||||||
worker_thread();
|
|
||||||
}
|
|
||||||
template <class AtThreadEntry>
|
|
||||||
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
|
||||||
{
|
|
||||||
at_thread_entry(*this);
|
|
||||||
worker_thread();
|
|
||||||
}
|
|
||||||
static void do_nothing_at_thread_entry(basic_thread_pool&) {}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main loop of the worker threads
|
||||||
|
*/
|
||||||
|
void worker_thread()
|
||||||
|
{
|
||||||
|
// fixme: this call results on segmentation fault
|
||||||
|
//at_thread_entry(basic_thread_pool(this->shared_from_this()));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
work task;
|
||||||
|
queue_op_status st = work_queue.wait_pull(task);
|
||||||
|
if (st == queue_op_status::closed) break;
|
||||||
|
task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_nothing_at_thread_entry(basic_thread_pool) {}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
threads.reserve(thread_count);
|
||||||
|
for (unsigned i = 0; i < thread_count; ++i)
|
||||||
|
{
|
||||||
|
thread th (&shared_state::worker_thread, this);
|
||||||
|
threads.push_back(thread_t(boost::move(th)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// basic_thread_pool is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
shared_state(unsigned const thread_count = thread::hardware_concurrency()+1)
|
||||||
|
: thread_count(thread_count),
|
||||||
|
at_thread_entry(do_nothing_at_thread_entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \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>
|
||||||
|
shared_state( unsigned const thread_count, AtThreadEntry& at_thread_entry)
|
||||||
|
: thread_count(thread_count),
|
||||||
|
at_thread_entry(at_thread_entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
shared_state( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool))
|
||||||
|
: thread_count(thread_count),
|
||||||
|
at_thread_entry(at_thread_entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
template <class AtThreadEntry>
|
||||||
|
shared_state( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||||
|
: thread_count(thread_count),
|
||||||
|
at_thread_entry(boost::move(at_thread_entry))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to all the worker threads that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
join();
|
||||||
|
// joins all the threads as the threads were scoped_threads
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: join all the threads.
|
||||||
|
*/
|
||||||
|
void join()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < threads.size(); ++i)
|
||||||
|
{
|
||||||
|
if (this_thread::get_id() == threads[i].get_id()) continue;
|
||||||
|
threads[i].join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
work_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
work_queue.push(work(boost::forward<Closure>(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& pred)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if ( ! try_executing_one())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (! pred());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: creates a thread pool with this shared state.
|
||||||
|
*
|
||||||
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
|
*/
|
||||||
|
friend struct shared_state;
|
||||||
|
basic_thread_pool(shared_ptr<shared_state> ptr)
|
||||||
|
: pimpl(ptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
public:
|
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 Effects: creates a thread pool that runs closures on \c thread_count threads.
|
||||||
*
|
*
|
||||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
*/
|
*/
|
||||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
|
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
|
||||||
|
: pimpl(make_shared<shared_state>(thread_count))
|
||||||
{
|
{
|
||||||
try
|
pimpl->init();
|
||||||
{
|
|
||||||
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
|
* \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. .
|
* and executes the at_thread_entry function at the entry of each created thread. .
|
||||||
@@ -158,61 +294,24 @@ namespace executors
|
|||||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
template <class AtThreadEntry>
|
template <class AtThreadEntry>
|
||||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry)
|
basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry)
|
||||||
|
: pimpl(make_shared<shared_state>(thread_count, at_thread_entry))
|
||||||
{
|
{
|
||||||
try
|
pimpl->init();
|
||||||
{
|
|
||||||
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
|
#endif
|
||||||
basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool&))
|
|
||||||
|
basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool))
|
||||||
|
: pimpl(make_shared<shared_state>(thread_count, at_thread_entry))
|
||||||
{
|
{
|
||||||
try
|
pimpl->init();
|
||||||
{
|
|
||||||
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>
|
template <class AtThreadEntry>
|
||||||
basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||||
|
: pimpl(make_shared<shared_state>(thread_count, boost::forward<AtThreadEntry>(at_thread_entry)))
|
||||||
{
|
{
|
||||||
try
|
pimpl->init();
|
||||||
{
|
|
||||||
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 Effects: Destroys the thread pool.
|
||||||
*
|
*
|
||||||
@@ -220,9 +319,16 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
~basic_thread_pool()
|
~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
|
/**
|
||||||
|
* 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 pimpl->try_executing_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -230,10 +336,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void join()
|
void join()
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < threads.size(); ++i)
|
pimpl->join();
|
||||||
{
|
|
||||||
threads[i].join();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -242,7 +345,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
work_queue.close();
|
pimpl->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,7 +353,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
bool closed()
|
bool closed()
|
||||||
{
|
{
|
||||||
return work_queue.closed();
|
return pimpl->closed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,18 +372,18 @@ namespace executors
|
|||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(Closure & closure)
|
void submit(Closure & closure)
|
||||||
{
|
{
|
||||||
work_queue.push(work(closure));
|
pimpl->submit(closure);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
void submit(void (*closure)())
|
||||||
{
|
{
|
||||||
work_queue.push(work(closure));
|
pimpl->submit(closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
work_queue.push(work(boost::forward<Closure>(closure)));
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,15 +394,16 @@ namespace executors
|
|||||||
template <typename Pred>
|
template <typename Pred>
|
||||||
bool reschedule_until(Pred const& pred)
|
bool reschedule_until(Pred const& pred)
|
||||||
{
|
{
|
||||||
do {
|
return pimpl->reschedule_until(pred);
|
||||||
if ( ! try_executing_one())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while (! pred());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void schedule_one_or_yield()
|
||||||
|
{
|
||||||
|
return pimpl->schedule_one_or_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
using executors::basic_thread_pool;
|
using executors::basic_thread_pool;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ namespace detail
|
|||||||
class priority_executor_base
|
class priority_executor_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//typedef boost::function<void()> work;
|
|
||||||
typedef executors::work_pq work;
|
typedef executors::work_pq work;
|
||||||
protected:
|
protected:
|
||||||
typedef Queue queue_type;
|
typedef Queue queue_type;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
// Copyright (C) 2013,2015 Vicente J. Botet Escriba
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -27,8 +27,6 @@ namespace boost
|
|||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
|
|
||||||
/// executor is not copyable.
|
|
||||||
BOOST_THREAD_NO_COPYABLE(executor)
|
|
||||||
executor() {}
|
executor() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +126,6 @@ namespace boost
|
|||||||
bool reschedule_until(Pred const& pred)
|
bool reschedule_until(Pred const& pred)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
//schedule_one_or_yield();
|
|
||||||
if ( ! try_executing_one())
|
if ( ! try_executing_one())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
// Copyright (C) 2013,2015 Vicente J. Botet Escriba
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -30,9 +30,8 @@ namespace executors
|
|||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executor::work work;
|
typedef executor::work work;
|
||||||
|
|
||||||
/// executor is not copyable.
|
// executor_adaptor(executor_adaptor const&) = default;
|
||||||
BOOST_THREAD_NO_COPYABLE(executor_adaptor)
|
// executor_adaptor(executor_adaptor &&) = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* executor_adaptor constructor
|
* executor_adaptor constructor
|
||||||
*/
|
*/
|
||||||
|
|||||||
150
include/boost/thread/executors/generic_executor.hpp
Normal file
150
include/boost/thread/executors/generic_executor.hpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// Copyright (C) 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_HPP
|
||||||
|
#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/detail/delete.hpp>
|
||||||
|
#include <boost/thread/detail/move.hpp>
|
||||||
|
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
#include <boost/type_traits/decay.hpp>
|
||||||
|
|
||||||
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace executors
|
||||||
|
{
|
||||||
|
|
||||||
|
class generic_executor
|
||||||
|
{
|
||||||
|
shared_ptr<executor> ex;
|
||||||
|
public:
|
||||||
|
/// type-erasure to store the works to do
|
||||||
|
typedef executors::work work;
|
||||||
|
|
||||||
|
//generic_executor(generic_executor const&) = default;
|
||||||
|
//generic_executor(generic_executor &&) = default;
|
||||||
|
|
||||||
|
template<typename Executor>
|
||||||
|
generic_executor(Executor const& ex
|
||||||
|
, typename boost::disable_if<is_same<Executor, generic_executor>,
|
||||||
|
int* >::type = (int*)0
|
||||||
|
)
|
||||||
|
//: ex(make_shared<executor_adaptor<Executor> >(ex)) // todo check why this doesn't work with C++03
|
||||||
|
: ex( new executor_adaptor<Executor>(ex) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//generic_executor(generic_executor const& other) noexcept {}
|
||||||
|
//generic_executor& operator=(generic_executor const& other) noexcept {}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Effects
|
||||||
|
* Close the \c executor for submissions.
|
||||||
|
* The worker threads will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close() { ex->close(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* Whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed() { return ex->closed(); }
|
||||||
|
|
||||||
|
void submit(BOOST_THREAD_RV_REF(work) closure)
|
||||||
|
{
|
||||||
|
ex->submit(boost::forward<work>(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Requires
|
||||||
|
* \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||||
|
*
|
||||||
|
* \par 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.
|
||||||
|
*
|
||||||
|
* \par Synchronization
|
||||||
|
* Completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||||
|
*
|
||||||
|
* \par 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// size_t num_pending_closures() const
|
||||||
|
// {
|
||||||
|
// return ex->num_pending_closures();
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Effects
|
||||||
|
* Try to execute one task.
|
||||||
|
*
|
||||||
|
* \par Returns
|
||||||
|
* Whether a task has been executed.
|
||||||
|
*
|
||||||
|
* \par Throws
|
||||||
|
* Whatever the current task constructor throws or the task() throws.
|
||||||
|
*/
|
||||||
|
bool try_executing_one() { return ex->try_executing_one(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Requires
|
||||||
|
* This must be called from an scheduled task.
|
||||||
|
*
|
||||||
|
* \par 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::generic_executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <boost/config/abi_suffix.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
#include <boost/thread/detail/move.hpp>
|
#include <boost/thread/detail/move.hpp>
|
||||||
#include <boost/thread/executors/executor.hpp>
|
#include <boost/thread/executors/executor.hpp>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
@@ -99,8 +100,8 @@ namespace boost
|
|||||||
|
|
||||||
template<typename Executor>
|
template<typename Executor>
|
||||||
generic_executor_ref(Executor& ex)
|
generic_executor_ref(Executor& ex)
|
||||||
//: ex(make_shared<executor_ref<Executor> >(ex)) // todo check why this doesn't works with C++03
|
//: ex(make_shared<executor_ref<typename decay<Executor>::type> >(ex)) // todo check why this doesn't work with C++03
|
||||||
: ex( new executor_ref<Executor>(ex) )
|
: ex( new executor_ref<typename decay<Executor>::type>(ex) )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
284
include/boost/thread/executors/generic_serial_executor.hpp
Normal file
284
include/boost/thread/executors/generic_serial_executor.hpp
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
// Copyright (C) 2013,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)
|
||||||
|
//
|
||||||
|
// 2013/11 Vicente J. Botet Escriba
|
||||||
|
// first implementation of a simple serial scheduler.
|
||||||
|
|
||||||
|
#ifndef BOOST_THREAD_GENERIC_SERIAL_EXECUTOR_HPP
|
||||||
|
#define BOOST_THREAD_GENERIC_SERIAL_EXECUTOR_HPP
|
||||||
|
|
||||||
|
#include <boost/thread/detail/config.hpp>
|
||||||
|
#include <boost/thread/detail/delete.hpp>
|
||||||
|
#include <boost/thread/detail/move.hpp>
|
||||||
|
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||||
|
#include <boost/thread/executors/work.hpp>
|
||||||
|
#include <boost/thread/executors/generic_executor.hpp>
|
||||||
|
#include <boost/thread/future.hpp>
|
||||||
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
#include <boost/type_traits/is_same.hpp>
|
||||||
|
#include <boost/type_traits/decay.hpp>
|
||||||
|
|
||||||
|
#include <boost/thread/caller_context.hpp>
|
||||||
|
|
||||||
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace executors
|
||||||
|
{
|
||||||
|
class generic_serial_executor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// type-erasure to store the works to do
|
||||||
|
typedef executors::work work;
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct shared_state {
|
||||||
|
typedef executors::work work;
|
||||||
|
typedef scoped_thread<> thread_t;
|
||||||
|
|
||||||
|
/// the thread safe work queue
|
||||||
|
concurrent::sync_queue<work > work_queue;
|
||||||
|
generic_executor ex;
|
||||||
|
thread_t thr;
|
||||||
|
|
||||||
|
struct try_executing_one_task {
|
||||||
|
work& task;
|
||||||
|
boost::promise<void> &p;
|
||||||
|
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||||
|
: task(task), p(p) {}
|
||||||
|
void operator()() {
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
p.set_value();
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
p.set_exception(current_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
generic_executor& underlying_executor() BOOST_NOEXCEPT { return ex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main loop of the worker thread
|
||||||
|
*/
|
||||||
|
void worker_thread()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
work task;
|
||||||
|
queue_op_status st = work_queue.wait_pull(task);
|
||||||
|
if (st == queue_op_status::closed) return;
|
||||||
|
|
||||||
|
boost::promise<void> p;
|
||||||
|
try_executing_one_task tmp(task,p);
|
||||||
|
ex.submit(tmp);
|
||||||
|
p.get_future().wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// shared_state is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
template <class Executor>
|
||||||
|
shared_state(Executor const& ex)
|
||||||
|
: ex(ex), thr(&shared_state::worker_thread, this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c shared_state destructor.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to the worker thread that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c generic_serial_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 generic_serial_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_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
work_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
work_queue.push(work(boost::forward<Closure>(closure)));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// generic_serial_executor(generic_serial_executor const&) = default;
|
||||||
|
// generic_serial_executor(generic_serial_executor &&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
template <class Executor>
|
||||||
|
generic_serial_executor(Executor const& ex
|
||||||
|
, typename boost::disable_if<is_same<Executor, generic_serial_executor>,
|
||||||
|
int* >::type = (int*)0)
|
||||||
|
: pimpl(make_shared<shared_state>(ex))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c generic_serial_executor destructor.
|
||||||
|
*/
|
||||||
|
~generic_serial_executor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
generic_executor& underlying_executor() BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
return pimpl->underlying_executor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
|
*/
|
||||||
|
bool try_executing_one()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c generic_serial_executor for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
pimpl->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
return pimpl->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 generic_serial_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)
|
||||||
|
{
|
||||||
|
pimpl->submit(closure);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
pimpl->submit(closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
|
*/
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& pred)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
using executors::generic_serial_executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <boost/config/abi_suffix.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
265
include/boost/thread/executors/generic_serial_executor_cont.hpp
Normal file
265
include/boost/thread/executors/generic_serial_executor_cont.hpp
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
// Copyright (C) 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)
|
||||||
|
//
|
||||||
|
// 2013/11 Vicente J. Botet Escriba
|
||||||
|
// first implementation of a simple serial scheduler.
|
||||||
|
|
||||||
|
#ifndef BOOST_THREAD_GENERIC_SERIAL_EXECUTOR_CONT_HPP
|
||||||
|
#define BOOST_THREAD_GENERIC_SERIAL_EXECUTOR_CONT_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/thread/executors/generic_executor.hpp>
|
||||||
|
#include <boost/thread/future.hpp>
|
||||||
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
#include <boost/type_traits/is_same.hpp>
|
||||||
|
#include <boost/type_traits/decay.hpp>
|
||||||
|
|
||||||
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
namespace executors
|
||||||
|
{
|
||||||
|
class generic_serial_executor_cont
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// type-erasure to store the works to do
|
||||||
|
typedef executors::work work;
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct shared_state {
|
||||||
|
typedef executors::work work;
|
||||||
|
|
||||||
|
generic_executor ex_;
|
||||||
|
future<void> fut_; // protected by mtx_
|
||||||
|
bool closed_; // protected by mtx_
|
||||||
|
mutex mtx_;
|
||||||
|
|
||||||
|
struct continuation {
|
||||||
|
work task;
|
||||||
|
template <class X>
|
||||||
|
struct result {
|
||||||
|
typedef void type;
|
||||||
|
};
|
||||||
|
continuation(BOOST_THREAD_RV_REF(work) tsk)
|
||||||
|
: task(boost::move(tsk)) {}
|
||||||
|
void operator()(future<void> f)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
} catch (...) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool closed(lock_guard<mutex>&) const
|
||||||
|
{
|
||||||
|
return closed_;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
generic_executor& underlying_executor() BOOST_NOEXCEPT { return ex_; }
|
||||||
|
|
||||||
|
/// shared_state is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: creates a serial executor that runs closures in fifo order using one the associated executor.
|
||||||
|
*
|
||||||
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
|
*
|
||||||
|
* \b Notes:
|
||||||
|
* * The lifetime of the associated executor must outlive the serial executor.
|
||||||
|
* * The current implementation doesn't support submission from synchronous continuation, that is,
|
||||||
|
* - the executor must execute the continuation asynchronously or
|
||||||
|
* - the continuation can not submit to this serial executor.
|
||||||
|
*/
|
||||||
|
template <class Executor>
|
||||||
|
shared_state(Executor const& ex)
|
||||||
|
: ex_(ex), fut_(make_ready_future()), closed_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c generic_serial_executor_cont destructor.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to the worker thread that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c generic_serial_executor_cont for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
closed_ = true;;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
return closed(lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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 after the last submitted closure finish.
|
||||||
|
* If the invoked closure throws an exception the \c generic_serial_executor_cont will call \c std::terminate, as is the case with threads.
|
||||||
|
*
|
||||||
|
* \b Throws: \c sync_queue_is_closed if the executor 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)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
fut_ = fut_.then(ex_, continuation(work(closure)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
fut_ = fut_.then(ex_, continuation(work(closure)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
fut_ = fut_.then(ex_, continuation(work(boost::forward<Closure>(closure))));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
template <class Executor>
|
||||||
|
generic_serial_executor_cont(Executor const& ex
|
||||||
|
, typename boost::disable_if<is_same<Executor, generic_serial_executor_cont>,
|
||||||
|
int* >::type = (int*)0)
|
||||||
|
: pimpl(make_shared<shared_state>(ex))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor destructor.
|
||||||
|
*/
|
||||||
|
~generic_serial_executor_cont()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
generic_executor& underlying_executor() BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
return pimpl->underlying_executor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
|
*/
|
||||||
|
bool try_executing_one()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c serial_executor for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
pimpl->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
return pimpl->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 serial_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)
|
||||||
|
{
|
||||||
|
pimpl->submit(closure);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
pimpl->submit(closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
|
*/
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& pred)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
using executors::generic_serial_executor_cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <boost/config/abi_suffix.hpp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -14,6 +14,9 @@
|
|||||||
#include <boost/thread/detail/move.hpp>
|
#include <boost/thread/detail/move.hpp>
|
||||||
#include <boost/thread/executors/work.hpp>
|
#include <boost/thread/executors/work.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
@@ -25,142 +28,227 @@ namespace executors
|
|||||||
public:
|
public:
|
||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
bool closed_;
|
private:
|
||||||
mutable mutex mtx_;
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
struct shared_state {
|
||||||
|
typedef executors::work work;
|
||||||
|
|
||||||
|
bool closed_;
|
||||||
|
mutable mutex mtx_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// shared_state is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: creates a inline executor that runs closures immediately.
|
||||||
|
*
|
||||||
|
* \b Throws: Nothing.
|
||||||
|
*/
|
||||||
|
shared_state()
|
||||||
|
: 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.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// 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()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
closed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed(lock_guard<mutex>& ) const
|
||||||
|
{
|
||||||
|
return closed_;
|
||||||
|
}
|
||||||
|
bool closed() const
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
return closed(lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
closure();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
closure();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
closure();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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;
|
||||||
|
}
|
||||||
|
};
|
||||||
public:
|
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()
|
||||||
|
: pimpl(make_shared<shared_state>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Effects: creates a inline executor that runs closures immediately.
|
* \b Effects: close the \c inline_executor for submissions.
|
||||||
*
|
* The loop will work until there is no more closures to run.
|
||||||
* \b Throws: Nothing.
|
*/
|
||||||
*/
|
void close()
|
||||||
inline_executor()
|
{
|
||||||
: closed_(false)
|
pimpl->close();
|
||||||
{
|
}
|
||||||
}
|
|
||||||
/**
|
|
||||||
* \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.
|
* \b Returns: whether the executor is closed for submissions.
|
||||||
* The loop will work until there is no more closures to run.
|
*/
|
||||||
*/
|
bool closed() const
|
||||||
void close()
|
{
|
||||||
{
|
return pimpl->closed();
|
||||||
lock_guard<mutex> lk(mtx_);
|
}
|
||||||
closed_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Returns: whether the pool is closed for submissions.
|
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||||
*/
|
*
|
||||||
bool closed(lock_guard<mutex>& )
|
* \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.
|
||||||
return closed_;
|
*
|
||||||
}
|
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||||
bool closed()
|
*
|
||||||
{
|
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||||
lock_guard<mutex> lk(mtx_);
|
* Whatever exception that can be throw while storing the closure.
|
||||||
return closed(lk);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \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)
|
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(Closure & closure)
|
void submit(Closure & closure)
|
||||||
{
|
{
|
||||||
{
|
pimpl->submit(closure);
|
||||||
lock_guard<mutex> lk(mtx_);
|
}
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
closure();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::terminate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
void submit(void (*closure)())
|
||||||
{
|
{
|
||||||
{
|
pimpl->submit(closure);
|
||||||
lock_guard<mutex> lk(mtx_);
|
}
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
closure();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::terminate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
{
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
lock_guard<mutex> lk(mtx_);
|
}
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
closure();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::terminate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Requires: This must be called from an scheduled task.
|
* Effects: try to execute one task.
|
||||||
*
|
* Returns: whether a task has been executed.
|
||||||
* \b Effects: reschedule functions until pred()
|
* Throws: whatever the current task constructor throws or the task() throws.
|
||||||
*/
|
*/
|
||||||
template <typename Pred>
|
bool try_executing_one()
|
||||||
bool reschedule_until(Pred const& )
|
{
|
||||||
{
|
return pimpl->try_executing_one();
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Requires: This must be called from an scheduled task.
|
||||||
|
*
|
||||||
|
* \b Effects: reschedule functions until pred()
|
||||||
|
*/
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& p)
|
||||||
|
{
|
||||||
|
return pimpl->reschedule_until(p);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
using executors::inline_executor;
|
using executors::inline_executor;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
// Copyright (C) 2013-2015 Vicente J. Botet Escriba
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||||
#include <boost/thread/executors/work.hpp>
|
#include <boost/thread/executors/work.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
@@ -30,59 +33,170 @@ namespace executors
|
|||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
private:
|
private:
|
||||||
/// the thread safe work queue
|
|
||||||
concurrent::sync_queue<work > work_queue;
|
|
||||||
|
|
||||||
public:
|
struct shared_state {
|
||||||
/**
|
typedef executors::work work;
|
||||||
* Effects: try to execute one task.
|
/// the thread safe work queue
|
||||||
* Returns: whether a task has been executed.
|
concurrent::sync_queue<work > work_queue;
|
||||||
* Throws: whatever the current task constructor throws or the task() throws.
|
|
||||||
*/
|
/**
|
||||||
bool try_executing_one()
|
* Effects: try to execute one task.
|
||||||
{
|
* Returns: whether a task has been executed.
|
||||||
work task;
|
* Throws: whatever the current task constructor throws or the task() throws.
|
||||||
try
|
*/
|
||||||
|
bool try_executing_one()
|
||||||
{
|
{
|
||||||
if (work_queue.try_pull(task) == queue_op_status::success)
|
work task;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
|
if (work_queue.try_pull(task) == queue_op_status::success)
|
||||||
|
{
|
||||||
|
task();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// loop_executor is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
shared_state()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to all the worker thread that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main loop of the worker thread
|
||||||
|
*/
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
while (!closed())
|
||||||
|
{
|
||||||
|
schedule_one_or_yield();
|
||||||
|
}
|
||||||
|
while (try_executing_one())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
work_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
work_queue.push(work(boost::forward<Closure>(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& 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();
|
||||||
task();
|
task();
|
||||||
return true;
|
q.pop_front();
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::terminate();
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
public:
|
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 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.
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
*/
|
*/
|
||||||
loop_executor()
|
loop_executor()
|
||||||
|
: pimpl(make_shared<shared_state>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -92,22 +206,33 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
~loop_executor()
|
~loop_executor()
|
||||||
{
|
{
|
||||||
// signal to all the worker thread that there will be no more submissions.
|
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 pimpl->try_executing_one();
|
||||||
|
}
|
||||||
|
// /**
|
||||||
|
// * Effects: schedule one task or yields
|
||||||
|
// * Throws: whatever the current task constructor throws or the task() throws.
|
||||||
|
// */
|
||||||
|
// void schedule_one_or_yield()
|
||||||
|
// {
|
||||||
|
// return pimpl->schedule_one_or_yield();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main loop of the worker thread
|
* The main loop of the worker thread
|
||||||
*/
|
*/
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
while (!closed())
|
pimpl->loop();
|
||||||
{
|
|
||||||
schedule_one_or_yield();
|
|
||||||
}
|
|
||||||
while (try_executing_one())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +241,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
work_queue.close();
|
pimpl->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,7 +249,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
bool closed()
|
bool closed()
|
||||||
{
|
{
|
||||||
return work_queue.closed();
|
return pimpl->closed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,18 +268,18 @@ namespace executors
|
|||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(Closure & closure)
|
void submit(Closure & closure)
|
||||||
{
|
{
|
||||||
work_queue.push(work(closure));
|
pimpl->submit(closure);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
void submit(void (*closure)())
|
||||||
{
|
{
|
||||||
work_queue.push(work(closure));
|
pimpl->submit(closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
work_queue.push(work(boost::forward<Closure>(closure)));
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,13 +290,7 @@ namespace executors
|
|||||||
template <typename Pred>
|
template <typename Pred>
|
||||||
bool reschedule_until(Pred const& pred)
|
bool reschedule_until(Pred const& pred)
|
||||||
{
|
{
|
||||||
do {
|
return pimpl->reschedule_until(pred);
|
||||||
if ( ! try_executing_one())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while (! pred());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -179,15 +298,10 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void run_queued_closures()
|
void run_queued_closures()
|
||||||
{
|
{
|
||||||
sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
|
pimpl->run_queued_closures();
|
||||||
while (! q.empty())
|
|
||||||
{
|
|
||||||
work& task = q.front();
|
|
||||||
task();
|
|
||||||
q.pop_front();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
using executors::loop_executor;
|
using executors::loop_executor;
|
||||||
|
|||||||
@@ -9,36 +9,123 @@
|
|||||||
#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
|
#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
|
||||||
|
|
||||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||||
|
#include <boost/thread/executors/work.hpp>
|
||||||
|
#include <boost/thread/detail/move.hpp>
|
||||||
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
|
#include <boost/thread/csbl/vector.hpp>
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace executors
|
namespace executors
|
||||||
{
|
{
|
||||||
|
|
||||||
class scheduled_thread_pool : public detail::scheduled_executor_base<>
|
template <class Clock = chrono::steady_clock>
|
||||||
|
class scheduled_thread_pool
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
thread_group _workers;
|
|
||||||
public:
|
|
||||||
|
|
||||||
scheduled_thread_pool(size_t num_threads) : super()
|
struct shared_state : public detail::scheduled_executor_base<> {
|
||||||
{
|
|
||||||
for(size_t i = 0; i < num_threads; i++)
|
/// basic_thread_pool is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
typedef detail::scheduled_executor_base<> super;
|
||||||
|
typedef typename super::work work;
|
||||||
|
|
||||||
|
typedef scoped_thread<> thread_t;
|
||||||
|
typedef csbl::vector<thread_t> thread_vector;
|
||||||
|
thread_vector threads;
|
||||||
|
|
||||||
|
shared_state(unsigned const thread_count = thread::hardware_concurrency()+1) : super()
|
||||||
{
|
{
|
||||||
_workers.create_thread(bind(&super::loop, this));
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
threads.reserve(thread_count);
|
||||||
|
for (unsigned i = 0; i < thread_count; ++i)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
thread th (&shared_state::loop, this);
|
||||||
|
threads.push_back(thread_t(boost::move(th)));
|
||||||
|
#else
|
||||||
|
threads.push_back(thread_t(&shared_state::loop, this)); // do not compile
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
}; //end class
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename shared_state::work work;
|
||||||
|
typedef Clock clock;
|
||||||
|
typedef typename clock::duration duration;
|
||||||
|
typedef typename clock::time_point time_point;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
scheduled_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
|
||||||
|
: pimpl(make_shared<shared_state>(thread_count))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
~scheduled_thread_pool()
|
~scheduled_thread_pool()
|
||||||
{
|
{
|
||||||
this->close();
|
}
|
||||||
_workers.join_all();
|
/**
|
||||||
|
* \b Effects: close the \c serial_executor for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
pimpl->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/**
|
||||||
typedef detail::scheduled_executor_base<> super;
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
}; //end class
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
return pimpl->closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_at(work w, const time_point& tp)
|
||||||
|
{
|
||||||
|
return pimpl->submit_at(boost::move(w), tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_after(work w, const duration& d)
|
||||||
|
{
|
||||||
|
return pimpl->submit_after(boost::move(w), d);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
|
};
|
||||||
} //end executors namespace
|
} //end executors namespace
|
||||||
|
|
||||||
using executors::scheduled_thread_pool;
|
using executors::scheduled_thread_pool;
|
||||||
|
|||||||
@@ -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
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,6 +13,8 @@
|
|||||||
#include <boost/chrono/time_point.hpp>
|
#include <boost/chrono/time_point.hpp>
|
||||||
#include <boost/chrono/duration.hpp>
|
#include <boost/chrono/duration.hpp>
|
||||||
#include <boost/chrono/system_clocks.hpp>
|
#include <boost/chrono/system_clocks.hpp>
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
@@ -36,7 +38,7 @@ namespace boost
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Executor& ex;
|
Executor ex;
|
||||||
Function funct;
|
Function funct;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -100,8 +102,8 @@ namespace boost
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scheduler& sch;
|
Scheduler sch;
|
||||||
Executor& ex;
|
Executor ex;
|
||||||
typename clock::time_point tp;
|
typename clock::time_point tp;
|
||||||
bool is_closed;
|
bool is_closed;
|
||||||
};
|
};
|
||||||
@@ -150,8 +152,8 @@ namespace boost
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scheduler& sch;
|
Scheduler sch;
|
||||||
Executor& ex;
|
Executor ex;
|
||||||
}; //end class
|
}; //end class
|
||||||
|
|
||||||
/// Wraps a reference to a @c Scheduler providing an @c Executor that
|
/// Wraps a reference to a @c Scheduler providing an @c Executor that
|
||||||
@@ -208,7 +210,7 @@ namespace boost
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scheduler& sch;
|
Scheduler sch;
|
||||||
time_point tp;
|
time_point tp;
|
||||||
bool is_closed;
|
bool is_closed;
|
||||||
}; //end class
|
}; //end class
|
||||||
@@ -217,22 +219,71 @@ namespace boost
|
|||||||
/// It provides factory helper functions such as at/after that convert a @c Scheduler into an @c Executor
|
/// It provides factory helper functions such as at/after that convert a @c Scheduler into an @c Executor
|
||||||
/// that submit the work at/after a specific time/duration respectively.
|
/// that submit the work at/after a specific time/duration respectively.
|
||||||
template <class Clock = chrono::steady_clock>
|
template <class Clock = chrono::steady_clock>
|
||||||
class scheduler : public detail::scheduled_executor_base<Clock>
|
class scheduler
|
||||||
{
|
{
|
||||||
public:
|
private:
|
||||||
typedef typename detail::scheduled_executor_base<Clock>::work work;
|
|
||||||
|
|
||||||
|
struct shared_state : public detail::scheduled_executor_base<Clock> {
|
||||||
|
typedef detail::scheduled_executor_base<Clock> super;
|
||||||
|
typedef typename super::work work;
|
||||||
|
thread thr;
|
||||||
|
|
||||||
|
/// shared_state is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
shared_state()
|
||||||
|
: super(),
|
||||||
|
thr(&super::loop, this) {}
|
||||||
|
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
this->close();
|
||||||
|
thr.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename shared_state::work work;
|
||||||
typedef Clock clock;
|
typedef Clock clock;
|
||||||
|
typedef typename clock::duration duration;
|
||||||
|
typedef typename clock::time_point time_point;
|
||||||
|
|
||||||
scheduler()
|
scheduler()
|
||||||
: super(),
|
: pimpl(make_shared<shared_state>())
|
||||||
thr(&super::loop, this) {}
|
{}
|
||||||
|
|
||||||
~scheduler()
|
~scheduler()
|
||||||
{
|
{
|
||||||
this->close();
|
|
||||||
thr.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c serial_executor for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
pimpl->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
return pimpl->closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_at(work w, const time_point& tp)
|
||||||
|
{
|
||||||
|
return pimpl->submit_at(boost::move(w), tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_after(work w, const duration& d)
|
||||||
|
{
|
||||||
|
return pimpl->submit_after(boost::move(w), d);
|
||||||
|
}
|
||||||
|
|
||||||
template <class Ex>
|
template <class Ex>
|
||||||
scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex)
|
scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex)
|
||||||
{
|
{
|
||||||
@@ -250,13 +301,10 @@ namespace boost
|
|||||||
{
|
{
|
||||||
return at_executor<scheduler>(*this, tp);
|
return at_executor<scheduler>(*this, tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef detail::scheduled_executor_base<Clock> super;
|
shared_ptr<shared_state> pimpl;
|
||||||
thread thr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
using executors::resubmitter;
|
using executors::resubmitter;
|
||||||
using executors::resubmit;
|
using executors::resubmit;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace executors
|
|||||||
class scheduling_adpator : public detail::scheduled_executor_base<>
|
class scheduling_adpator : public detail::scheduled_executor_base<>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Executor& _exec;
|
Executor _exec;
|
||||||
thread _scheduler;
|
thread _scheduler;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
// Copyright (C) 2013,2015 Vicente J. Botet Escriba
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -14,116 +14,168 @@
|
|||||||
#include <boost/thread/detail/move.hpp>
|
#include <boost/thread/detail/move.hpp>
|
||||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||||
#include <boost/thread/executors/work.hpp>
|
#include <boost/thread/executors/work.hpp>
|
||||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
#include <boost/thread/executors/generic_executor.hpp>
|
||||||
#include <boost/thread/future.hpp>
|
#include <boost/thread/future.hpp>
|
||||||
#include <boost/thread/scoped_thread.hpp>
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace executors
|
namespace executors
|
||||||
{
|
{
|
||||||
|
template <class Executor>
|
||||||
class serial_executor
|
class serial_executor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
private:
|
private:
|
||||||
typedef scoped_thread<> thread_t;
|
|
||||||
|
|
||||||
/// the thread safe work queue
|
struct shared_state {
|
||||||
concurrent::sync_queue<work > work_queue;
|
typedef executors::work work;
|
||||||
generic_executor_ref ex;
|
typedef scoped_thread<> thread_t;
|
||||||
thread_t thr;
|
|
||||||
|
|
||||||
struct try_executing_one_task {
|
/// the thread safe work queue
|
||||||
work& task;
|
concurrent::sync_queue<work > work_queue;
|
||||||
boost::promise<void> &p;
|
Executor ex;
|
||||||
try_executing_one_task(work& task, boost::promise<void> &p)
|
thread_t thr;
|
||||||
: task(task), p(p) {}
|
|
||||||
void operator()() {
|
struct try_executing_one_task {
|
||||||
try {
|
work& task;
|
||||||
task();
|
boost::promise<void> &p;
|
||||||
p.set_value();
|
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||||
} catch (...)
|
: task(task), p(p) {}
|
||||||
|
void operator()() {
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
p.set_value();
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
p.set_exception(current_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
Executor& underlying_executor() BOOST_NOEXCEPT { return ex; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main loop of the worker thread
|
||||||
|
*/
|
||||||
|
void worker_thread()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
p.set_exception(current_exception());
|
for(;;)
|
||||||
|
{
|
||||||
|
work task;
|
||||||
|
queue_op_status st = work_queue.wait_pull(task);
|
||||||
|
if (st == queue_op_status::closed) return;
|
||||||
|
|
||||||
|
boost::promise<void> p;
|
||||||
|
try_executing_one_task tmp(task,p);
|
||||||
|
ex.submit(tmp);
|
||||||
|
p.get_future().wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// shared_state is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
shared_state(Executor& ex)
|
||||||
|
: ex(ex), thr(&shared_state::worker_thread, this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c shared_state destructor.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to the worker thread that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c serial_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 serial_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_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
work_queue.push(work(closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
work_queue.push(work(boost::forward<Closure>(closure)));
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* \par Returns
|
|
||||||
* The underlying executor wrapped on a generic executor reference.
|
|
||||||
*/
|
|
||||||
generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(task) == queue_op_status::success)
|
|
||||||
{
|
|
||||||
boost::promise<void> p;
|
|
||||||
try_executing_one_task tmp(task,p);
|
|
||||||
ex.submit(tmp);
|
|
||||||
p.get_future().wait();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::terminate();
|
|
||||||
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:
|
public:
|
||||||
/// serial_executor is not copyable.
|
|
||||||
BOOST_THREAD_NO_COPYABLE(serial_executor)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
* \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.
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
*/
|
*/
|
||||||
template <class Executor>
|
|
||||||
serial_executor(Executor& ex)
|
serial_executor(Executor& ex)
|
||||||
: ex(ex), thr(&serial_executor::worker_thread, this)
|
: pimpl(make_shared<shared_state>(ex))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -133,8 +185,24 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
~serial_executor()
|
~serial_executor()
|
||||||
{
|
{
|
||||||
// signal to the worker thread that there will be no more submissions.
|
}
|
||||||
close();
|
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
Executor& underlying_executor() BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
return pimpl->underlying_executor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
|
*/
|
||||||
|
bool try_executing_one()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,7 +211,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
work_queue.close();
|
pimpl->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,7 +219,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
bool closed()
|
bool closed()
|
||||||
{
|
{
|
||||||
return work_queue.closed();
|
return pimpl->closed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,37 +238,31 @@ namespace executors
|
|||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(Closure & closure)
|
void submit(Closure & closure)
|
||||||
{
|
{
|
||||||
work_queue.push(work(closure));
|
pimpl->submit(closure);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
void submit(void (*closure)())
|
||||||
{
|
{
|
||||||
work_queue.push(work(closure));
|
pimpl->submit(closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
work_queue.push(work(boost::forward<Closure>(closure)));
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Requires: This must be called from an scheduled task.
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
*
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
* \b Effects: reschedule functions until pred()
|
|
||||||
*/
|
*/
|
||||||
template <typename Pred>
|
template <typename Pred>
|
||||||
bool reschedule_until(Pred const& pred)
|
bool reschedule_until(Pred const& pred)
|
||||||
{
|
{
|
||||||
do {
|
return false;
|
||||||
if ( ! try_executing_one())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while (! pred());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
using executors::serial_executor;
|
using executors::serial_executor;
|
||||||
|
|||||||
@@ -12,18 +12,20 @@
|
|||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/detail/config.hpp>
|
||||||
#include <boost/thread/detail/delete.hpp>
|
#include <boost/thread/detail/delete.hpp>
|
||||||
#include <boost/thread/detail/move.hpp>
|
#include <boost/thread/detail/move.hpp>
|
||||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
|
||||||
#include <boost/thread/executors/work.hpp>
|
#include <boost/thread/executors/work.hpp>
|
||||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
|
||||||
#include <boost/thread/future.hpp>
|
#include <boost/thread/future.hpp>
|
||||||
#include <boost/thread/scoped_thread.hpp>
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace executors
|
namespace executors
|
||||||
{
|
{
|
||||||
|
template <class Executor>
|
||||||
class serial_executor_cont
|
class serial_executor_cont
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -31,93 +33,156 @@ namespace executors
|
|||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
generic_executor_ref ex_;
|
struct shared_state {
|
||||||
future<void> fut_; // protected by mtx_
|
typedef executors::work work;
|
||||||
bool closed_; // protected by mtx_
|
|
||||||
mutex mtx_;
|
|
||||||
|
|
||||||
struct continuation {
|
Executor ex_;
|
||||||
work task;
|
future<void> fut_; // protected by mtx_
|
||||||
template <class X>
|
bool closed_; // protected by mtx_
|
||||||
struct result {
|
mutex mtx_;
|
||||||
typedef void type;
|
|
||||||
};
|
struct continuation {
|
||||||
continuation(BOOST_THREAD_RV_REF(work) tsk)
|
work task;
|
||||||
: task(boost::move(tsk)) {}
|
template <class X>
|
||||||
void operator()(future<void> f)
|
struct result {
|
||||||
{
|
typedef void type;
|
||||||
try {
|
};
|
||||||
task();
|
continuation(BOOST_THREAD_RV_REF(work) tsk)
|
||||||
} catch (...) {
|
: task(boost::move(tsk)) {}
|
||||||
std::terminate();
|
void operator()(future<void> f)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
} catch (...) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool closed(lock_guard<mutex>&) const
|
||||||
|
{
|
||||||
|
return closed_;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \par Returns
|
||||||
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
|
*/
|
||||||
|
Executor& underlying_executor() BOOST_NOEXCEPT { return ex_; }
|
||||||
|
|
||||||
|
/// shared_state is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: creates a serial executor that runs closures in fifo order using one the associated executor.
|
||||||
|
*
|
||||||
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
|
*
|
||||||
|
* \b Notes:
|
||||||
|
* * The lifetime of the associated executor must outlive the serial executor.
|
||||||
|
* * The current implementation doesn't support submission from synchronous continuation, that is,
|
||||||
|
* - the executor must execute the continuation asynchronously or
|
||||||
|
* - the continuation can not submit to this serial executor.
|
||||||
|
*/
|
||||||
|
shared_state(Executor& ex)
|
||||||
|
: ex_(ex), fut_(make_ready_future()), closed_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Destroys the thread pool.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor_cont destructor.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to the worker thread that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c serial_executor_cont for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
closed_ = true;;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
return closed(lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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 after the last submitted closure finish.
|
||||||
|
* If the invoked closure throws an exception the \c serial_executor_cont will call \c std::terminate, as is the case with threads.
|
||||||
|
*
|
||||||
|
* \b Throws: \c sync_queue_is_closed if the executor 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)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
fut_ = fut_.then(ex_, continuation(work(closure)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
fut_ = fut_.then(ex_, continuation(work(closure)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
fut_ = fut_.then(ex_, continuation(work(boost::forward<Closure>(closure))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool closed(lock_guard<mutex>&) const
|
|
||||||
{
|
|
||||||
return closed_;
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* \par Returns
|
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
||||||
* The underlying executor wrapped on a generic executor reference.
|
|
||||||
*/
|
|
||||||
generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex_; }
|
|
||||||
|
|
||||||
/// serial_executor_cont is not copyable.
|
|
||||||
BOOST_THREAD_NO_COPYABLE(serial_executor_cont)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \b Effects: creates a serial executor that runs closures in fifo order using one the associated executor.
|
|
||||||
*
|
*
|
||||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
*
|
|
||||||
* \b Notes:
|
|
||||||
* * The lifetime of the associated executor must outlive the serial executor.
|
|
||||||
* * The current implementation doesn't support submission from synchronous continuation, that is,
|
|
||||||
* - the executor must execute the continuation asynchronously or
|
|
||||||
* - the continuation can not submit to this serial executor.
|
|
||||||
*/
|
*/
|
||||||
template <class Executor>
|
|
||||||
serial_executor_cont(Executor& ex)
|
serial_executor_cont(Executor& ex)
|
||||||
: ex_(ex), fut_(make_ready_future()), closed_(false)
|
: pimpl(make_shared<shared_state>(ex))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* \b Effects: Destroys the thread pool.
|
* \b Effects: Destroys the thread pool.
|
||||||
*
|
*
|
||||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor_cont destructor.
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor destructor.
|
||||||
*/
|
*/
|
||||||
~serial_executor_cont()
|
~serial_executor_cont()
|
||||||
{
|
{
|
||||||
// signal to the worker thread that there will be no more submissions.
|
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Effects: close the \c serial_executor_cont for submissions.
|
* \par Returns
|
||||||
* The loop will work until there is no more closures to run.
|
* The underlying executor wrapped on a generic executor reference.
|
||||||
*/
|
*/
|
||||||
void close()
|
Executor& underlying_executor() BOOST_NOEXCEPT
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
return pimpl->underlying_executor();
|
||||||
closed_ = true;;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Returns: whether the pool is closed for submissions.
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
*/
|
|
||||||
bool closed()
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lk(mtx_);
|
|
||||||
return closed(lk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Effects: none.
|
|
||||||
* Returns: always false.
|
|
||||||
* Throws: No.
|
|
||||||
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
*/
|
*/
|
||||||
bool try_executing_one()
|
bool try_executing_one()
|
||||||
@@ -125,41 +190,64 @@ namespace executors
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c serial_executor for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
pimpl->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
return pimpl->closed();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
* \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 after the last submitted closure finish.
|
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||||
* If the invoked closure throws an exception the \c serial_executor_cont will call \c std::terminate, as is the case with threads.
|
* If invoked closure throws an exception the \c serial_executor will call \c std::terminate, as is the case with threads.
|
||||||
*
|
*
|
||||||
* \b Throws: \c sync_queue_is_closed if the executor is closed.
|
* \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.
|
* Whatever exception that can be throw while storing the closure.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(Closure & closure)
|
void submit(Closure & closure)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->submit(closure);
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
fut_ = fut_.then(ex_, continuation(work(closure)));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
void submit(void (*closure)())
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->submit(closure);
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
fut_ = fut_.then(ex_, continuation(work(closure)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
fut_ = fut_.then(ex_, continuation(work(boost::forward<Closure>(closure))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: always false as a serial executor can not re-enter.
|
||||||
|
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||||
|
*/
|
||||||
|
template <typename Pred>
|
||||||
|
bool reschedule_until(Pred const& pred)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
using executors::serial_executor_cont;
|
using executors::serial_executor_cont;
|
||||||
|
|||||||
@@ -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
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
#include <boost/thread/scoped_thread.hpp>
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
#include <boost/thread/csbl/vector.hpp>
|
#include <boost/thread/csbl/vector.hpp>
|
||||||
|
|
||||||
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/make_shared.hpp>
|
||||||
|
|
||||||
#include <boost/config/abi_prefix.hpp>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
@@ -29,33 +32,134 @@ namespace executors
|
|||||||
public:
|
public:
|
||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
bool closed_;
|
private:
|
||||||
typedef scoped_thread<> thread_t;
|
|
||||||
typedef csbl::vector<thread_t> threads_type;
|
|
||||||
threads_type threads_;
|
|
||||||
mutable mutex mtx_;
|
|
||||||
|
|
||||||
/**
|
struct shared_state {
|
||||||
* Effects: try to execute one task.
|
typedef executors::work work;
|
||||||
* Returns: whether a task has been executed.
|
bool closed_;
|
||||||
* Throws: whatever the current task constructor throws or the task() throws.
|
typedef scoped_thread<> thread_t;
|
||||||
*/
|
typedef csbl::vector<thread_t> threads_type;
|
||||||
bool try_executing_one()
|
threads_type threads_;
|
||||||
{
|
mutable mutex mtx_;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// thread_executor is not copyable.
|
||||||
|
BOOST_THREAD_NO_COPYABLE(shared_state)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: creates a inline executor that runs closures immediately.
|
||||||
|
*
|
||||||
|
* \b Throws: Nothing.
|
||||||
|
*/
|
||||||
|
shared_state()
|
||||||
|
: closed_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \b Effects: Waits for closures (if any) to complete, then joins and destroys the threads.
|
||||||
|
*
|
||||||
|
* \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor.
|
||||||
|
*/
|
||||||
|
~shared_state()
|
||||||
|
{
|
||||||
|
// signal to all the worker thread that there will be no more submissions.
|
||||||
|
close();
|
||||||
|
// all the scoped threads will join before destroying
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Effects: close the \c thread_executor for submissions.
|
||||||
|
* The loop will work until there is no more closures to run.
|
||||||
|
*/
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
closed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
|
*/
|
||||||
|
bool closed(lock_guard<mutex>& )
|
||||||
|
{
|
||||||
|
return closed_;
|
||||||
|
}
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
return closed(lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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 thread_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)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
threads_.reserve(threads_.size() + 1);
|
||||||
|
thread th(closure);
|
||||||
|
threads_.push_back(thread_t(boost::move(th)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void submit(void (*closure)())
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
threads_.reserve(threads_.size() + 1);
|
||||||
|
thread th(closure);
|
||||||
|
threads_.push_back(thread_t(boost::move(th)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Closure>
|
||||||
|
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||||
|
threads_.reserve(threads_.size() + 1);
|
||||||
|
thread th(boost::forward<Closure>(closure));
|
||||||
|
threads_.push_back(thread_t(boost::move(th)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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;
|
||||||
|
}
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
/// thread_executor is not copyable.
|
|
||||||
BOOST_THREAD_NO_COPYABLE(thread_executor)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Effects: creates a inline executor that runs closures immediately.
|
* \b Effects: creates a inline executor that runs closures immediately.
|
||||||
*
|
*
|
||||||
* \b Throws: Nothing.
|
* \b Throws: Nothing.
|
||||||
*/
|
*/
|
||||||
thread_executor()
|
thread_executor()
|
||||||
: closed_(false)
|
: pimpl(make_shared<shared_state>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -65,9 +169,16 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
~thread_executor()
|
~thread_executor()
|
||||||
{
|
{
|
||||||
// signal to all the worker thread that there will be no more submissions.
|
}
|
||||||
close();
|
|
||||||
// all the scoped threads will join before destroying
|
/**
|
||||||
|
* 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 pimpl->try_executing_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,21 +187,15 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->close();
|
||||||
closed_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Returns: whether the pool is closed for submissions.
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
*/
|
*/
|
||||||
bool closed(lock_guard<mutex>& )
|
|
||||||
{
|
|
||||||
return closed_;
|
|
||||||
}
|
|
||||||
bool closed()
|
bool closed()
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
return pimpl->closed();
|
||||||
return closed(lk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,30 +214,18 @@ namespace executors
|
|||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(Closure & closure)
|
void submit(Closure & closure)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->submit(closure);
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
threads_.reserve(threads_.size() + 1);
|
|
||||||
thread th(closure);
|
|
||||||
threads_.push_back(thread_t(boost::move(th)));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
void submit(void (*closure)())
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->submit(closure);
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
threads_.reserve(threads_.size() + 1);
|
|
||||||
thread th(closure);
|
|
||||||
threads_.push_back(thread_t(boost::move(th)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(mtx_);
|
pimpl->submit(boost::forward<Closure>(closure));
|
||||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
|
||||||
threads_.reserve(threads_.size() + 1);
|
|
||||||
thread th(boost::forward<Closure>(closure));
|
|
||||||
threads_.push_back(thread_t(boost::move(th)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,12 +234,14 @@ namespace executors
|
|||||||
* \b Effects: reschedule functions until pred()
|
* \b Effects: reschedule functions until pred()
|
||||||
*/
|
*/
|
||||||
template <typename Pred>
|
template <typename Pred>
|
||||||
bool reschedule_until(Pred const&)
|
bool reschedule_until(Pred const& p)
|
||||||
{
|
{
|
||||||
return false;
|
return pimpl->reschedule_until(p);
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
shared_ptr<shared_state> pimpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
using executors::thread_executor;
|
using executors::thread_executor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ BOOST_THREAD_INLINE_NAMESPACE(v2)
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
|
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
|
||||||
template <class Ex, typename F>
|
template <class Ex, typename F>
|
||||||
friend void task_region(Ex&, BOOST_THREAD_FWD_REF(F) f);
|
friend void task_region(Ex const&, BOOST_THREAD_FWD_REF(F) f);
|
||||||
template<class Ex, typename F>
|
template<class Ex, typename F>
|
||||||
friend void task_region_final(Ex&, BOOST_THREAD_FWD_REF(F) f);
|
friend void task_region_final(Ex const&, BOOST_THREAD_FWD_REF(F) f);
|
||||||
|
|
||||||
void wait_all()
|
void wait_all()
|
||||||
{
|
{
|
||||||
@@ -153,21 +153,20 @@ protected:
|
|||||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
task_region_handle_gen()
|
task_region_handle_gen()
|
||||||
: canceled(false)
|
: canceled(false)
|
||||||
, ex(0)
|
|
||||||
{}
|
{}
|
||||||
task_region_handle_gen(Executor& ex)
|
task_region_handle_gen(Executor const& ex)
|
||||||
: canceled(false)
|
: canceled(false)
|
||||||
, ex(&ex)
|
, ex(ex)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
task_region_handle_gen()
|
task_region_handle_gen()
|
||||||
: ex(0)
|
//: ex(0)
|
||||||
{}
|
{}
|
||||||
task_region_handle_gen(Executor& ex)
|
task_region_handle_gen(Executor const& ex)
|
||||||
: ex(&ex)
|
: ex(ex)
|
||||||
{}
|
{}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -188,7 +187,7 @@ protected:
|
|||||||
bool canceled;
|
bool canceled;
|
||||||
#endif
|
#endif
|
||||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
Executor* ex;
|
Executor ex;
|
||||||
#endif
|
#endif
|
||||||
exception_list exs;
|
exception_list exs;
|
||||||
typedef csbl::vector<future<void> > group_type;
|
typedef csbl::vector<future<void> > group_type;
|
||||||
@@ -211,13 +210,13 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
group.push_back(async(ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
||||||
#else
|
#else
|
||||||
group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
group.push_back(async(*ex, forward<F>(f)));
|
group.push_back(async(ex, forward<F>(f)));
|
||||||
#else
|
#else
|
||||||
group.push_back(async(forward<F>(f)));
|
group.push_back(async(forward<F>(f)));
|
||||||
#endif
|
#endif
|
||||||
@@ -245,17 +244,18 @@ protected:
|
|||||||
class task_region_handle :
|
class task_region_handle :
|
||||||
public task_region_handle_gen<default_executor>
|
public task_region_handle_gen<default_executor>
|
||||||
{
|
{
|
||||||
default_executor tp;
|
//default_executor tp;
|
||||||
template <typename F>
|
template <typename F>
|
||||||
friend void task_region(BOOST_THREAD_FWD_REF(F) f);
|
friend void task_region(BOOST_THREAD_FWD_REF(F) f);
|
||||||
template<typename F>
|
template<typename F>
|
||||||
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
|
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
task_region_handle() : task_region_handle_gen<default_executor>()
|
task_region_handle()
|
||||||
|
: task_region_handle_gen<default_executor>()
|
||||||
{
|
{
|
||||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
ex = &tp;
|
//ex = &tp;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
BOOST_DELETED_FUNCTION(task_region_handle(const task_region_handle&))
|
BOOST_DELETED_FUNCTION(task_region_handle(const task_region_handle&))
|
||||||
@@ -265,7 +265,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Executor, typename F>
|
template <typename Executor, typename F>
|
||||||
void task_region_final(Executor& ex, BOOST_THREAD_FWD_REF(F) f)
|
void task_region_final(Executor const& ex, BOOST_THREAD_FWD_REF(F) f)
|
||||||
{
|
{
|
||||||
task_region_handle_gen<Executor> tr(ex);
|
task_region_handle_gen<Executor> tr(ex);
|
||||||
try
|
try
|
||||||
@@ -280,7 +280,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Executor, typename F>
|
template <typename Executor, typename F>
|
||||||
void task_region(Executor& ex, BOOST_THREAD_FWD_REF(F) f)
|
void task_region(Executor const& ex, BOOST_THREAD_FWD_REF(F) f)
|
||||||
{
|
{
|
||||||
task_region_final(ex, forward<F>(f));
|
task_region_final(ex, forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ namespace boost
|
|||||||
continuations_type continuations;
|
continuations_type continuations;
|
||||||
|
|
||||||
// This declaration should be only included conditionally, but is included to maintain the same layout.
|
// This declaration should be only included conditionally, but is included to maintain the same layout.
|
||||||
virtual void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base>)
|
virtual void launch_continuation()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +150,19 @@ namespace boost
|
|||||||
policy_(launch::none),
|
policy_(launch::none),
|
||||||
continuations()
|
continuations()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
shared_state_base(exceptional_ptr const& ex):
|
||||||
|
exception(ex.ptr_),
|
||||||
|
done(true),
|
||||||
|
is_valid_(true),
|
||||||
|
is_deferred_(false),
|
||||||
|
is_constructed(false),
|
||||||
|
cnt_(0),
|
||||||
|
policy_(launch::none),
|
||||||
|
continuations()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
virtual ~shared_state_base()
|
virtual ~shared_state_base()
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(cnt_==0);
|
BOOST_ASSERT(cnt_==0);
|
||||||
@@ -221,8 +234,7 @@ namespace boost
|
|||||||
continuations.clear();
|
continuations.clear();
|
||||||
relocker rlk(lock);
|
relocker rlk(lock);
|
||||||
for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) {
|
for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) {
|
||||||
boost::unique_lock<boost::mutex> cont_lock((*it)->mutex);
|
(*it)->launch_continuation();
|
||||||
(*it)->launch_continuation(cont_lock, *it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,7 +419,7 @@ namespace boost
|
|||||||
return policy_;
|
return policy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
future_state::state get_state(boost::unique_lock<boost::mutex>& lk) const
|
future_state::state get_state(boost::unique_lock<boost::mutex>&) const
|
||||||
{
|
{
|
||||||
if(!done)
|
if(!done)
|
||||||
{
|
{
|
||||||
@@ -483,6 +495,10 @@ namespace boost
|
|||||||
shared_state():
|
shared_state():
|
||||||
result()
|
result()
|
||||||
{}
|
{}
|
||||||
|
shared_state(exceptional_ptr const& ex):
|
||||||
|
detail::shared_state_base(ex), result()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
~shared_state()
|
~shared_state()
|
||||||
{}
|
{}
|
||||||
@@ -624,6 +640,10 @@ namespace boost
|
|||||||
result(0)
|
result(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
shared_state(exceptional_ptr const& ex):
|
||||||
|
detail::shared_state_base(ex), result(0)
|
||||||
|
{}
|
||||||
|
|
||||||
~shared_state()
|
~shared_state()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -687,6 +707,10 @@ namespace boost
|
|||||||
shared_state()
|
shared_state()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
shared_state(exceptional_ptr const& ex):
|
||||||
|
detail::shared_state_base(ex)
|
||||||
|
{}
|
||||||
|
|
||||||
void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock)
|
void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock)
|
||||||
{
|
{
|
||||||
mark_finished_internal(lock);
|
mark_finished_internal(lock);
|
||||||
@@ -1150,16 +1174,7 @@ namespace boost
|
|||||||
|
|
||||||
static //BOOST_CONSTEXPR
|
static //BOOST_CONSTEXPR
|
||||||
future_ptr make_exceptional_future_ptr(exceptional_ptr const& ex) {
|
future_ptr make_exceptional_future_ptr(exceptional_ptr const& ex) {
|
||||||
promise<R> p;
|
return future_ptr(new detail::shared_state<R>(ex));
|
||||||
p.set_exception(ex.ptr_);
|
|
||||||
return p.get_future().future_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_exceptional_if_invalid() {
|
|
||||||
if (valid()) return;
|
|
||||||
promise<R> p;
|
|
||||||
p.set_exception(future_uninitialized());
|
|
||||||
future_ = p.get_future().future_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
future_ptr future_;
|
future_ptr future_;
|
||||||
@@ -1363,6 +1378,28 @@ namespace boost
|
|||||||
template <class F, class Rp, class Fp>
|
template <class F, class Rp, class Fp>
|
||||||
BOOST_THREAD_FUTURE<Rp>
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename F, typename Rp, typename Fp>
|
||||||
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
|
make_shared_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename F, typename Rp, typename Fp>
|
||||||
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
|
make_shared_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
|
template<typename Ex, typename F, typename Rp, typename Fp>
|
||||||
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
|
make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename Ex, typename F, typename Rp, typename Fp>
|
||||||
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
|
make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template <class Rp, class Fp, class Executor>
|
||||||
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
|
make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||||
template<typename F, typename Rp>
|
template<typename F, typename Rp>
|
||||||
@@ -1372,6 +1409,36 @@ namespace boost
|
|||||||
make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f);
|
make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY)
|
||||||
|
template< typename InputIterator>
|
||||||
|
typename boost::disable_if<is_future_type<InputIterator>,
|
||||||
|
BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> >
|
||||||
|
>::type
|
||||||
|
when_all(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_all();
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
template< typename T0, typename ...T>
|
||||||
|
BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> >
|
||||||
|
when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template< typename InputIterator>
|
||||||
|
typename boost::disable_if<is_future_type<InputIterator>,
|
||||||
|
BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> >
|
||||||
|
>::type
|
||||||
|
when_any(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_any();
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
template< typename T0, typename ...T>
|
||||||
|
BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::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 <typename R>
|
template <typename R>
|
||||||
class BOOST_THREAD_FUTURE : public detail::basic_future<R>
|
class BOOST_THREAD_FUTURE : public detail::basic_future<R>
|
||||||
@@ -1395,6 +1462,28 @@ namespace boost
|
|||||||
template <class F, class Rp, class Fp>
|
template <class F, class Rp, class Fp>
|
||||||
friend BOOST_THREAD_FUTURE<Rp>
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_shared_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_shared_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
|
template<typename Ex, typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename Ex, typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template <class Rp, class Fp, class Executor>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||||
template<typename F, typename Rp>
|
template<typename F, typename Rp>
|
||||||
@@ -1403,6 +1492,35 @@ namespace boost
|
|||||||
friend BOOST_THREAD_FUTURE<Rp>
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
detail::make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f);
|
detail::make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY)
|
||||||
|
template< typename InputIterator>
|
||||||
|
friend typename boost::disable_if<is_future_type<InputIterator>,
|
||||||
|
BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> >
|
||||||
|
>::type
|
||||||
|
when_all(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
//friend inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_all();
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
template< typename T0, typename ...T>
|
||||||
|
friend BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> >
|
||||||
|
when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template< typename InputIterator>
|
||||||
|
friend typename boost::disable_if<is_future_type<InputIterator>,
|
||||||
|
BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> >
|
||||||
|
>::type
|
||||||
|
when_any(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
//friend inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_any();
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
template< typename T0, typename ...T>
|
||||||
|
friend BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::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
|
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
|
||||||
template <class> friend class packaged_task; // todo check if this works in windows
|
template <class> friend class packaged_task; // todo check if this works in windows
|
||||||
#else
|
#else
|
||||||
@@ -1418,9 +1536,7 @@ namespace boost
|
|||||||
friend BOOST_THREAD_FUTURE<Rp>
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f);
|
detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f);
|
||||||
|
|
||||||
|
|
||||||
typedef typename base_type::move_dest_type move_dest_type;
|
typedef typename base_type::move_dest_type move_dest_type;
|
||||||
public: // when_all
|
|
||||||
|
|
||||||
BOOST_THREAD_FUTURE(future_ptr a_future):
|
BOOST_THREAD_FUTURE(future_ptr a_future):
|
||||||
base_type(a_future)
|
base_type(a_future)
|
||||||
@@ -1588,7 +1704,7 @@ namespace boost
|
|||||||
|
|
||||||
friend class shared_future<R>;
|
friend class shared_future<R>;
|
||||||
friend class promise<R>;
|
friend class promise<R>;
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||||
template <typename, typename, typename>
|
template <typename, typename, typename>
|
||||||
friend struct detail::future_async_continuation_shared_state;
|
friend struct detail::future_async_continuation_shared_state;
|
||||||
template <typename, typename, typename>
|
template <typename, typename, typename>
|
||||||
@@ -1601,7 +1717,30 @@ namespace boost
|
|||||||
template <class F, class Rp, class Fp>
|
template <class F, class Rp, class Fp>
|
||||||
friend BOOST_THREAD_FUTURE<Rp>
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
#endif
|
|
||||||
|
template<typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_shared_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_shared_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
|
template<typename Ex, typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template<typename Ex, typename F, typename Rp, typename Fp>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock<boost::mutex> &lock, F f, BOOST_THREAD_FWD_REF(Fp) c);
|
||||||
|
|
||||||
|
template <class Rp, class Fp, class Executor>
|
||||||
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
|
detail::make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||||
template<typename F, typename Rp>
|
template<typename F, typename Rp>
|
||||||
friend struct detail::future_unwrap_shared_state;
|
friend struct detail::future_unwrap_shared_state;
|
||||||
@@ -1609,6 +1748,36 @@ namespace boost
|
|||||||
friend BOOST_THREAD_FUTURE<Rp>
|
friend BOOST_THREAD_FUTURE<Rp>
|
||||||
detail::make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f);
|
detail::make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY)
|
||||||
|
template< typename InputIterator>
|
||||||
|
friend typename boost::disable_if<is_future_type<InputIterator>,
|
||||||
|
BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> >
|
||||||
|
>::type
|
||||||
|
when_all(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
friend inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_all();
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
template< typename T0, typename ...T>
|
||||||
|
friend BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> >
|
||||||
|
when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template< typename InputIterator>
|
||||||
|
friend typename boost::disable_if<is_future_type<InputIterator>,
|
||||||
|
BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> >
|
||||||
|
>::type
|
||||||
|
when_any(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
friend inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_any();
|
||||||
|
|
||||||
|
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
template< typename T0, typename ...T>
|
||||||
|
friend BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::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
|
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
|
||||||
template <class> friend class packaged_task; // todo check if this works in windows
|
template <class> friend class packaged_task; // todo check if this works in windows
|
||||||
#else
|
#else
|
||||||
@@ -1630,8 +1799,8 @@ namespace boost
|
|||||||
base_type(a_future)
|
base_type(a_future)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE)
|
BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE)
|
||||||
typedef future_state::state state;
|
typedef future_state::state state;
|
||||||
typedef R value_type; // EXTENSION
|
typedef R value_type; // EXTENSION
|
||||||
@@ -2713,7 +2882,7 @@ namespace boost
|
|||||||
private:
|
private:
|
||||||
task_shared_state(task_shared_state&);
|
task_shared_state(task_shared_state&);
|
||||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||||
typedef R (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes) ... );
|
typedef R (*CallableType)(ArgTypes ... );
|
||||||
#else
|
#else
|
||||||
typedef R (*CallableType)();
|
typedef R (*CallableType)();
|
||||||
#endif
|
#endif
|
||||||
@@ -2944,7 +3113,7 @@ namespace boost
|
|||||||
private:
|
private:
|
||||||
task_shared_state(task_shared_state&);
|
task_shared_state(task_shared_state&);
|
||||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||||
typedef void (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes)...);
|
typedef void (*CallableType)(ArgTypes...);
|
||||||
#else
|
#else
|
||||||
typedef void (*CallableType)();
|
typedef void (*CallableType)();
|
||||||
#endif
|
#endif
|
||||||
@@ -3267,7 +3436,7 @@ namespace boost
|
|||||||
|
|
||||||
// execution
|
// execution
|
||||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||||
void operator()(BOOST_THREAD_RV_REF(ArgTypes)... args) {
|
void operator()(ArgTypes... args) {
|
||||||
if(!task) {
|
if(!task) {
|
||||||
boost::throw_exception(task_moved());
|
boost::throw_exception(task_moved());
|
||||||
}
|
}
|
||||||
@@ -3938,12 +4107,6 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
BOOST_THREAD_FUTURE<T> make_ready_future(exception_ptr ex) {
|
|
||||||
promise<T> p;
|
|
||||||
p.set_exception(ex);
|
|
||||||
return BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BOOST_THREAD_FUTURE<T> make_exceptional_future(exception_ptr ex) {
|
BOOST_THREAD_FUTURE<T> make_exceptional_future(exception_ptr ex) {
|
||||||
@@ -3965,16 +4128,9 @@ namespace detail {
|
|||||||
p.set_exception(boost::current_exception());
|
p.set_exception(boost::current_exception());
|
||||||
return BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
return BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
BOOST_THREAD_FUTURE<T> make_exceptional_future_if_invalid(BOOST_THREAD_FWD_REF(BOOST_THREAD_FUTURE<T>) fut) {
|
BOOST_THREAD_FUTURE<T> make_ready_future(exception_ptr ex) {
|
||||||
fut.set_exceptional_if_invalid();
|
return make_exceptional_future<T>(ex);
|
||||||
return boost::move(fut);
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
shared_future<T> make_exceptional_future_if_invalid(shared_future<T> fut) {
|
|
||||||
fut.set_exceptional_if_invalid();
|
|
||||||
return fut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -4033,8 +4189,9 @@ namespace detail
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) {
|
void launch_continuation() {
|
||||||
this->thr_ = thread(&future_async_continuation_shared_state::run, that);
|
boost::lock_guard<boost::mutex> lk(this->mutex);
|
||||||
|
this->thr_ = thread(&future_async_continuation_shared_state::run, this->shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
||||||
@@ -4064,8 +4221,9 @@ namespace detail
|
|||||||
centinel(parent.future_) {
|
centinel(parent.future_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) {
|
void launch_continuation() {
|
||||||
this->thr_ = thread(&future_async_continuation_shared_state::run, that);
|
boost::lock_guard<boost::mutex> lk(this->mutex);
|
||||||
|
this->thr_ = thread(&future_async_continuation_shared_state::run, this->shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
||||||
@@ -4115,9 +4273,8 @@ namespace detail
|
|||||||
this->set_executor();
|
this->set_executor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that ) {
|
void launch_continuation() {
|
||||||
relocker relock(lck);
|
run_it<future_executor_continuation_shared_state> fct(this->shared_from_this());
|
||||||
run_it<future_executor_continuation_shared_state> fct(that);
|
|
||||||
ex->submit(fct);
|
ex->submit(fct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4154,9 +4311,8 @@ namespace detail
|
|||||||
this->set_executor();
|
this->set_executor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that ) {
|
void launch_continuation() {
|
||||||
relocker relock(lck);
|
run_it<future_executor_continuation_shared_state> fct(this->shared_from_this());
|
||||||
run_it<future_executor_continuation_shared_state> fct(that);
|
|
||||||
ex->submit(fct);
|
ex->submit(fct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4197,8 +4353,9 @@ namespace detail
|
|||||||
centinel(parent.future_) {
|
centinel(parent.future_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) {
|
void launch_continuation() {
|
||||||
this->thr_ = thread(&shared_future_async_continuation_shared_state::run, that);
|
boost::lock_guard<boost::mutex> lk(this->mutex);
|
||||||
|
this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this->shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
||||||
@@ -4227,8 +4384,9 @@ namespace detail
|
|||||||
centinel(parent.future_) {
|
centinel(parent.future_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>&, shared_ptr<shared_state_base> that) {
|
void launch_continuation() {
|
||||||
this->thr_ = thread(&shared_future_async_continuation_shared_state::run, that);
|
boost::lock_guard<boost::mutex> lk(this->mutex);
|
||||||
|
this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this->shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
static void run(shared_ptr<boost::detail::shared_state_base> that_) {
|
||||||
@@ -4265,9 +4423,8 @@ namespace detail
|
|||||||
this->set_executor();
|
this->set_executor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that) {
|
void launch_continuation() {
|
||||||
relocker relock(lck);
|
run_it<shared_future_executor_continuation_shared_state> fct(this->shared_from_this());
|
||||||
run_it<shared_future_executor_continuation_shared_state> fct(that);
|
|
||||||
ex->submit(fct);
|
ex->submit(fct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4303,9 +4460,8 @@ namespace detail
|
|||||||
centinel(parent.future_) {
|
centinel(parent.future_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void launch_continuation(boost::unique_lock<boost::mutex>& lck, shared_ptr<shared_state_base> that) {
|
void launch_continuation() {
|
||||||
relocker relock(lck);
|
run_it<shared_future_executor_continuation_shared_state> fct(this->shared_from_this());
|
||||||
run_it<shared_future_executor_continuation_shared_state> fct(that);
|
|
||||||
ex->submit(fct);
|
ex->submit(fct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4345,7 +4501,8 @@ namespace detail
|
|||||||
this->set_deferred();
|
this->set_deferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void launch_continuation(boost::unique_lock<boost::mutex>&lk, shared_ptr<shared_state_base> ) {
|
virtual void launch_continuation() {
|
||||||
|
boost::unique_lock<boost::mutex> lk(this->mutex);
|
||||||
if (this->is_deferred_) {
|
if (this->is_deferred_) {
|
||||||
this->is_deferred_=false;
|
this->is_deferred_=false;
|
||||||
this->execute(lk);
|
this->execute(lk);
|
||||||
@@ -4383,7 +4540,8 @@ namespace detail
|
|||||||
|
|
||||||
~future_deferred_continuation_shared_state() {
|
~future_deferred_continuation_shared_state() {
|
||||||
}
|
}
|
||||||
virtual void launch_continuation(boost::unique_lock<boost::mutex>& lk, shared_ptr<shared_state_base> ) {
|
virtual void launch_continuation() {
|
||||||
|
boost::unique_lock<boost::mutex> lk(this->mutex);
|
||||||
if (this->is_deferred_) {
|
if (this->is_deferred_) {
|
||||||
this->is_deferred_=false;
|
this->is_deferred_=false;
|
||||||
this->execute(lk);
|
this->execute(lk);
|
||||||
@@ -4422,7 +4580,8 @@ namespace detail
|
|||||||
this->set_deferred();
|
this->set_deferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void launch_continuation(boost::unique_lock<boost::mutex>& lk, shared_ptr<shared_state_base> ) {
|
virtual void launch_continuation() {
|
||||||
|
boost::unique_lock<boost::mutex> lk(this->mutex);
|
||||||
if (this->is_deferred_) {
|
if (this->is_deferred_) {
|
||||||
this->is_deferred_=false;
|
this->is_deferred_=false;
|
||||||
this->execute(lk);
|
this->execute(lk);
|
||||||
@@ -4458,7 +4617,8 @@ namespace detail
|
|||||||
this->set_deferred();
|
this->set_deferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void launch_continuation(boost::unique_lock<boost::mutex>& lk, shared_ptr<shared_state_base> ) {
|
virtual void launch_continuation() {
|
||||||
|
boost::unique_lock<boost::mutex> lk(this->mutex);
|
||||||
if (this->is_deferred_) {
|
if (this->is_deferred_) {
|
||||||
this->is_deferred_=false;
|
this->is_deferred_=false;
|
||||||
this->execute(lk);
|
this->execute(lk);
|
||||||
@@ -4672,14 +4832,17 @@ namespace detail
|
|||||||
|
|
||||||
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
||||||
if (underlying_cast<int>(policy) & int(launch::async)) {
|
if (underlying_cast<int>(policy) & int(launch::async)) {
|
||||||
|
lock.unlock();
|
||||||
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
)));
|
)));
|
||||||
} else if (underlying_cast<int>(policy) & int(launch::deferred)) {
|
} else if (underlying_cast<int>(policy) & int(launch::deferred)) {
|
||||||
|
lock.unlock();
|
||||||
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
)));
|
)));
|
||||||
} else {
|
} else {
|
||||||
|
lock.unlock();
|
||||||
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
)));
|
)));
|
||||||
@@ -4695,6 +4858,7 @@ namespace detail
|
|||||||
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
|
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
|
||||||
|
|
||||||
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
||||||
|
lock.unlock();
|
||||||
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state<Ex, BOOST_THREAD_FUTURE<R>, future_type, F>(ex,
|
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state<Ex, BOOST_THREAD_FUTURE<R>, future_type, F>(ex,
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
)));
|
)));
|
||||||
@@ -4710,15 +4874,18 @@ namespace detail
|
|||||||
|
|
||||||
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
|
||||||
if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) {
|
if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) {
|
||||||
|
lock.unlock();
|
||||||
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
);
|
);
|
||||||
} else if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::deferred)) {
|
} else if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::deferred)) {
|
||||||
this->future_->wait_internal(lock);
|
this->future_->wait_internal(lock);
|
||||||
|
lock.unlock();
|
||||||
return boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
return boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
lock.unlock();
|
||||||
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
|
||||||
lock, boost::move(*this), boost::forward<F>(func)
|
lock, boost::move(*this), boost::forward<F>(func)
|
||||||
);
|
);
|
||||||
@@ -4859,41 +5026,87 @@ namespace detail
|
|||||||
template<typename F, typename Rp>
|
template<typename F, typename Rp>
|
||||||
struct future_unwrap_shared_state: shared_state<Rp>
|
struct future_unwrap_shared_state: shared_state<Rp>
|
||||||
{
|
{
|
||||||
F parent;
|
F wrapped;
|
||||||
|
typename F::value_type unwrapped;
|
||||||
public:
|
public:
|
||||||
explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f)
|
explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f)
|
||||||
: parent(boost::move(f)) {}
|
: wrapped(boost::move(f)) {
|
||||||
|
|
||||||
typename F::value_type parent_value(boost::unique_lock<boost::mutex>& ) {
|
|
||||||
typename F::value_type r = parent.get();
|
|
||||||
r.set_exceptional_if_invalid();
|
|
||||||
return boost::move(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void wait(boost::unique_lock<boost::mutex>& lk, bool ) { // todo see if rethrow must be used
|
void launch_continuation()
|
||||||
parent_value(lk).wait();
|
|
||||||
}
|
|
||||||
virtual Rp get(boost::unique_lock<boost::mutex>& lk) {
|
|
||||||
return parent_value(lk).get();
|
|
||||||
}
|
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
|
||||||
typedef shared_ptr<shared_state_base> continuation_ptr_type;
|
|
||||||
|
|
||||||
virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock)
|
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lk(parent.future_->mutex);
|
boost::unique_lock<boost::mutex> lk(this->mutex);
|
||||||
parent.future_->set_continuation_ptr(continuation, lk);
|
if (! unwrapped.valid() )
|
||||||
|
{
|
||||||
|
if (wrapped.has_exception()) {
|
||||||
|
this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk);
|
||||||
|
} else {
|
||||||
|
unwrapped = wrapped.get();
|
||||||
|
if (unwrapped.valid())
|
||||||
|
{
|
||||||
|
lk.unlock();
|
||||||
|
boost::unique_lock<boost::mutex> lk2(unwrapped.future_->mutex);
|
||||||
|
unwrapped.future_->set_continuation_ptr(this->shared_from_this(), lk2);
|
||||||
|
} else {
|
||||||
|
this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (unwrapped.has_exception()) {
|
||||||
|
this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk);
|
||||||
|
} else {
|
||||||
|
this->mark_finished_with_result_internal(unwrapped.get(), lk);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
struct future_unwrap_shared_state<F,void>: shared_state<void>
|
||||||
|
{
|
||||||
|
F wrapped;
|
||||||
|
typename F::value_type unwrapped;
|
||||||
|
public:
|
||||||
|
explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f)
|
||||||
|
: wrapped(boost::move(f)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void launch_continuation()
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::mutex> lk(this->mutex);
|
||||||
|
if (! unwrapped.valid() )
|
||||||
|
{
|
||||||
|
if (wrapped.has_exception()) {
|
||||||
|
this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk);
|
||||||
|
} else {
|
||||||
|
unwrapped = wrapped.get();
|
||||||
|
if (unwrapped.valid())
|
||||||
|
{
|
||||||
|
lk.unlock();
|
||||||
|
boost::unique_lock<boost::mutex> lk2(unwrapped.future_->mutex);
|
||||||
|
unwrapped.future_->set_continuation_ptr(this->shared_from_this(), lk2);
|
||||||
|
} else {
|
||||||
|
this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (unwrapped.has_exception()) {
|
||||||
|
this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk);
|
||||||
|
} else {
|
||||||
|
this->mark_finished_with_result_internal(lk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template <class F, class Rp>
|
template <class F, class Rp>
|
||||||
BOOST_THREAD_FUTURE<Rp>
|
BOOST_THREAD_FUTURE<Rp>
|
||||||
make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f) {
|
make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f) {
|
||||||
shared_ptr<future_unwrap_shared_state<F, Rp> >
|
shared_ptr<future_unwrap_shared_state<F, Rp> >
|
||||||
h(new future_unwrap_shared_state<F, Rp>(boost::move(f)));
|
h(new future_unwrap_shared_state<F, Rp>(boost::move(f)));
|
||||||
lock.lock();
|
lock.lock();
|
||||||
h->parent.future_->set_continuation_ptr(h, lock);
|
h->wrapped.future_->set_continuation_ptr(h, lock);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
return BOOST_THREAD_FUTURE<Rp>(h);
|
return BOOST_THREAD_FUTURE<Rp>(h);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ namespace boost
|
|||||||
unique_lock<mutex>& m,
|
unique_lock<mutex>& m,
|
||||||
duration_type const& wait_duration)
|
duration_type const& wait_duration)
|
||||||
{
|
{
|
||||||
|
if (wait_duration.is_pos_infinity())
|
||||||
|
{
|
||||||
|
wait(m); // or do_wait(m,detail::timeout::sentinel());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (wait_duration.is_special())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return timed_wait(m,get_system_time()+wait_duration);
|
return timed_wait(m,get_system_time()+wait_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +158,18 @@ namespace boost
|
|||||||
unique_lock<mutex>& m,
|
unique_lock<mutex>& m,
|
||||||
duration_type const& wait_duration,predicate_type pred)
|
duration_type const& wait_duration,predicate_type pred)
|
||||||
{
|
{
|
||||||
|
if (wait_duration.is_pos_infinity())
|
||||||
|
{
|
||||||
|
while (!pred())
|
||||||
|
{
|
||||||
|
wait(m); // or do_wait(m,detail::timeout::sentinel());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (wait_duration.is_special())
|
||||||
|
{
|
||||||
|
return pred();
|
||||||
|
}
|
||||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -339,8 +339,8 @@ namespace boost
|
|||||||
{
|
{
|
||||||
if (wait_duration.is_pos_infinity())
|
if (wait_duration.is_pos_infinity())
|
||||||
{
|
{
|
||||||
wait(m); // or do_wait(m,detail::timeout::sentinel());
|
wait(m); // or do_wait(m,detail::timeout::sentinel());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (wait_duration.is_special())
|
if (wait_duration.is_special())
|
||||||
{
|
{
|
||||||
@@ -362,6 +362,18 @@ namespace boost
|
|||||||
template<typename duration_type,typename predicate_type>
|
template<typename duration_type,typename predicate_type>
|
||||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
||||||
{
|
{
|
||||||
|
if (wait_duration.is_pos_infinity())
|
||||||
|
{
|
||||||
|
while (!pred())
|
||||||
|
{
|
||||||
|
wait(m); // or do_wait(m,detail::timeout::sentinel());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (wait_duration.is_special())
|
||||||
|
{
|
||||||
|
return pred();
|
||||||
|
}
|
||||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace boost
|
|||||||
typedef HANDLE handle;
|
typedef HANDLE handle;
|
||||||
typedef SYSTEM_INFO system_info;
|
typedef SYSTEM_INFO system_info;
|
||||||
typedef unsigned __int64 ticks_type;
|
typedef unsigned __int64 ticks_type;
|
||||||
|
typedef FARPROC farproc_t;
|
||||||
unsigned const infinite=INFINITE;
|
unsigned const infinite=INFINITE;
|
||||||
unsigned const timeout=WAIT_TIMEOUT;
|
unsigned const timeout=WAIT_TIMEOUT;
|
||||||
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
||||||
@@ -58,17 +59,20 @@ namespace boost
|
|||||||
using ::CreateSemaphoreExW;
|
using ::CreateSemaphoreExW;
|
||||||
# endif
|
# endif
|
||||||
using ::OpenEventW;
|
using ::OpenEventW;
|
||||||
|
using ::GetModuleGandleW;
|
||||||
# else
|
# else
|
||||||
using ::CreateMutexA;
|
using ::CreateMutexA;
|
||||||
using ::CreateEventA;
|
using ::CreateEventA;
|
||||||
using ::OpenEventA;
|
using ::OpenEventA;
|
||||||
using ::CreateSemaphoreA;
|
using ::CreateSemaphoreA;
|
||||||
|
using ::GetModuleHandleA;
|
||||||
# endif
|
# endif
|
||||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||||
using ::GetNativeSystemInfo;
|
using ::GetNativeSystemInfo;
|
||||||
using ::GetTickCount64;
|
using ::GetTickCount64;
|
||||||
#else
|
#else
|
||||||
using ::GetSystemInfo;
|
using ::GetSystemInfo;
|
||||||
|
using ::GetTickCount;
|
||||||
#endif
|
#endif
|
||||||
using ::CloseHandle;
|
using ::CloseHandle;
|
||||||
using ::ReleaseMutex;
|
using ::ReleaseMutex;
|
||||||
@@ -86,6 +90,7 @@ namespace boost
|
|||||||
using ::SleepEx;
|
using ::SleepEx;
|
||||||
using ::Sleep;
|
using ::Sleep;
|
||||||
using ::QueueUserAPC;
|
using ::QueueUserAPC;
|
||||||
|
using ::GetProcAddress;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,6 +140,7 @@ namespace boost
|
|||||||
typedef void* handle;
|
typedef void* handle;
|
||||||
typedef _SYSTEM_INFO system_info;
|
typedef _SYSTEM_INFO system_info;
|
||||||
typedef unsigned __int64 ticks_type;
|
typedef unsigned __int64 ticks_type;
|
||||||
|
typedef int (__stdcall *farproc_t)();
|
||||||
unsigned const infinite=~0U;
|
unsigned const infinite=~0U;
|
||||||
unsigned const timeout=258U;
|
unsigned const timeout=258U;
|
||||||
handle const invalid_handle_value=(handle)(-1);
|
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);
|
__declspec(dllimport) void* __stdcall CreateSemaphoreExW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*,unsigned long,unsigned long);
|
||||||
# endif
|
# endif
|
||||||
__declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
|
__declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
|
||||||
|
__declspec(dllimport) void* __stdcall GetModuleHandleW(wchar_t const*);
|
||||||
# else
|
# else
|
||||||
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
|
__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 CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
|
||||||
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,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 OpenEventA(unsigned long,int,char const*);
|
||||||
|
__declspec(dllimport) void* __stdcall GetModuleHandleA(char const*);
|
||||||
# endif
|
# endif
|
||||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||||
__declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*);
|
__declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*);
|
||||||
__declspec(dllimport) ticks_type __stdcall GetTickCount64();
|
__declspec(dllimport) ticks_type __stdcall GetTickCount64();
|
||||||
#else
|
#else
|
||||||
__declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*);
|
__declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*);
|
||||||
|
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||||
#endif
|
#endif
|
||||||
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
||||||
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
||||||
@@ -183,6 +192,7 @@ namespace boost
|
|||||||
__declspec(dllimport) void __stdcall Sleep(unsigned long);
|
__declspec(dllimport) void __stdcall Sleep(unsigned long);
|
||||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
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) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||||
|
__declspec(dllimport) farproc_t __stdcall GetProcAddress(void *, const char *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# ifndef UNDER_CE
|
# ifndef UNDER_CE
|
||||||
@@ -216,17 +226,10 @@ namespace boost
|
|||||||
{
|
{
|
||||||
namespace win32
|
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
|
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||||
extern "C"
|
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
|
#ifdef _MSC_VER
|
||||||
long _InterlockedCompareExchange(long volatile *, long, long);
|
long _InterlockedCompareExchange(long volatile *, long, long);
|
||||||
#pragma intrinsic(_InterlockedCompareExchange)
|
#pragma intrinsic(_InterlockedCompareExchange)
|
||||||
@@ -285,6 +288,7 @@ namespace boost
|
|||||||
// Oops, we weren't called often enough, we're stuck
|
// Oops, we weren't called often enough, we're stuck
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
#endif
|
#endif
|
||||||
inline detail::gettickcount64_t GetTickCount64_()
|
inline detail::gettickcount64_t GetTickCount64_()
|
||||||
{
|
{
|
||||||
@@ -297,7 +301,7 @@ namespace boost
|
|||||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||||
gettickcount64impl = &GetTickCount64;
|
gettickcount64impl = &GetTickCount64;
|
||||||
#else
|
#else
|
||||||
detail::farproc_t addr=GetProcAddress(
|
farproc_t addr=GetProcAddress(
|
||||||
#if !defined(BOOST_NO_ANSI_APIS)
|
#if !defined(BOOST_NO_ANSI_APIS)
|
||||||
GetModuleHandleA("KERNEL32.DLL"),
|
GetModuleHandleA("KERNEL32.DLL"),
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#if defined BOOST_THREAD_PATCH
|
||||||
|
#include <string.h> // memcmp.
|
||||||
|
#endif
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
namespace thread_detail
|
namespace thread_detail
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ namespace boost
|
|||||||
static void tls_destructor(void* data)
|
static void tls_destructor(void* data)
|
||||||
{
|
{
|
||||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||||
|
//boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(data)->shared_from_this();
|
||||||
|
|
||||||
if(thread_info)
|
if(thread_info)
|
||||||
{
|
{
|
||||||
while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
|
while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
|
||||||
@@ -124,7 +126,8 @@ namespace boost
|
|||||||
}
|
}
|
||||||
~delete_current_thread_tls_key_on_dlclose_t()
|
~delete_current_thread_tls_key_on_dlclose_t()
|
||||||
{
|
{
|
||||||
if (current_thread_tls_init_flag.epoch!=BOOST_ONCE_INITIAL_FLAG_VALUE)
|
const boost::once_flag uninitialized = BOOST_ONCE_INIT;
|
||||||
|
if (memcmp(¤t_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag)))
|
||||||
{
|
{
|
||||||
pthread_key_delete(current_thread_tls_key);
|
pthread_key_delete(current_thread_tls_key);
|
||||||
}
|
}
|
||||||
@@ -158,8 +161,9 @@ namespace boost
|
|||||||
{
|
{
|
||||||
static void* thread_proxy(void* param)
|
static void* thread_proxy(void* param)
|
||||||
{
|
{
|
||||||
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
|
//boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
|
||||||
//thread_info->self.reset();
|
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->shared_from_this();
|
||||||
|
thread_info->self.reset();
|
||||||
detail::set_current_thread_data(thread_info.get());
|
detail::set_current_thread_data(thread_info.get());
|
||||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||||
BOOST_TRY
|
BOOST_TRY
|
||||||
@@ -252,7 +256,6 @@ namespace boost
|
|||||||
{
|
{
|
||||||
thread_info->self.reset();
|
thread_info->self.reset();
|
||||||
return false;
|
return false;
|
||||||
// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -266,7 +269,6 @@ namespace boost
|
|||||||
{
|
{
|
||||||
thread_info->self.reset();
|
thread_info->self.reset();
|
||||||
return false;
|
return false;
|
||||||
// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
|
|
||||||
}
|
}
|
||||||
int detached_state;
|
int detached_state;
|
||||||
res = pthread_attr_getdetachstate(h, &detached_state);
|
res = pthread_attr_getdetachstate(h, &detached_state);
|
||||||
@@ -274,7 +276,6 @@ namespace boost
|
|||||||
{
|
{
|
||||||
thread_info->self.reset();
|
thread_info->self.reset();
|
||||||
return false;
|
return false;
|
||||||
// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_attr_getdetachstate"));
|
|
||||||
}
|
}
|
||||||
if (PTHREAD_CREATE_DETACHED==detached_state)
|
if (PTHREAD_CREATE_DETACHED==detached_state)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -298,6 +298,7 @@ rule thread-compile ( sources : reqs * : name )
|
|||||||
[ thread-compile test_10963.cpp : : test_10963_c ]
|
[ thread-compile test_10963.cpp : : test_10963_c ]
|
||||||
[ thread-run test_10964.cpp ]
|
[ thread-run test_10964.cpp ]
|
||||||
[ thread-test test_11053.cpp ]
|
[ thread-test test_11053.cpp ]
|
||||||
|
[ thread-run test_11266.cpp ]
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
@@ -809,7 +810,10 @@ rule thread-compile ( sources : reqs * : name )
|
|||||||
[ thread-run2 ../example/user_scheduler.cpp : ex_user_scheduler ]
|
[ thread-run2 ../example/user_scheduler.cpp : ex_user_scheduler ]
|
||||||
[ thread-run2 ../example/executor.cpp : ex_executor ]
|
[ thread-run2 ../example/executor.cpp : ex_executor ]
|
||||||
[ thread-run2 ../example/generic_executor_ref.cpp : ex_generic_executor_ref ]
|
[ thread-run2 ../example/generic_executor_ref.cpp : ex_generic_executor_ref ]
|
||||||
|
[ thread-run2 ../example/generic_executor.cpp : ex_generic_executor ]
|
||||||
|
[ thread-run2 ../example/generic_serial_executor.cpp : ex_generic_serial_executor ]
|
||||||
[ thread-run2 ../example/serial_executor.cpp : ex_serial_executor ]
|
[ thread-run2 ../example/serial_executor.cpp : ex_serial_executor ]
|
||||||
|
[ thread-run2 ../example/generic_serial_executor_cont.cpp : ex_generic_serial_executor_cont ]
|
||||||
[ thread-run2 ../example/serial_executor_cont.cpp : ex_serial_executor_cont ]
|
[ thread-run2 ../example/serial_executor_cont.cpp : ex_serial_executor_cont ]
|
||||||
[ thread-run2 ../example/future_when_all.cpp : ex_future_when_all ]
|
[ thread-run2 ../example/future_when_all.cpp : ex_future_when_all ]
|
||||||
[ thread-run2 ../example/parallel_accumulate.cpp : ex_parallel_accumulate ]
|
[ thread-run2 ../example/parallel_accumulate.cpp : ex_parallel_accumulate ]
|
||||||
@@ -947,11 +951,18 @@ rule thread-compile ( sources : reqs * : name )
|
|||||||
[ thread-run2-noit ./experimental/parallel/v2/task_region_pass.cpp : task_region_p ]
|
[ thread-run2-noit ./experimental/parallel/v2/task_region_pass.cpp : task_region_p ]
|
||||||
;
|
;
|
||||||
|
|
||||||
explicit ts_ ;
|
explicit ts_other ;
|
||||||
test-suite ts_
|
test-suite ts_other
|
||||||
:
|
:
|
||||||
[ thread-run2 ../example/this_executor.cpp : ex_this_executor ]
|
[ thread-run2 ../example/this_executor.cpp : ex_this_executor ]
|
||||||
[ thread-run2 ../example/default_executor.cpp : ex_default_executor ]
|
[ thread-run2 ../example/default_executor.cpp : ex_default_executor ]
|
||||||
;
|
;
|
||||||
|
|
||||||
|
explicit ts_ ;
|
||||||
|
test-suite ts_
|
||||||
|
:
|
||||||
|
#[ thread-run test_11256.cpp ]
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <boost/thread/future.hpp>
|
#include <boost/thread/future.hpp>
|
||||||
#include <boost/detail/lightweight_test.hpp>
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ int p1()
|
|||||||
|
|
||||||
int p2(boost::future<int> f)
|
int p2(boost::future<int> f)
|
||||||
{
|
{
|
||||||
|
assert(f.is_ready());
|
||||||
|
|
||||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||||
BOOST_TEST(f.valid());
|
BOOST_TEST(f.valid());
|
||||||
int i = f.get();
|
int i = f.get();
|
||||||
@@ -41,6 +44,7 @@ int p2(boost::future<int> f)
|
|||||||
|
|
||||||
void p3(boost::future<int> f)
|
void p3(boost::future<int> f)
|
||||||
{
|
{
|
||||||
|
assert(f.is_ready());
|
||||||
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
||||||
BOOST_TEST(f.valid());
|
BOOST_TEST(f.valid());
|
||||||
int i = f.get();
|
int i = f.get();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
#include <boost/thread/executor.hpp>
|
#include <boost/thread/executor.hpp>
|
||||||
#include <boost/detail/lightweight_test.hpp>
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ int p1()
|
|||||||
|
|
||||||
int p2(boost::future<int> f)
|
int p2(boost::future<int> f)
|
||||||
{
|
{
|
||||||
|
assert(f.is_ready());
|
||||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||||
BOOST_TEST(f.valid());
|
BOOST_TEST(f.valid());
|
||||||
int i = f.get();
|
int i = f.get();
|
||||||
@@ -44,6 +46,7 @@ int p2(boost::future<int> f)
|
|||||||
|
|
||||||
void p3(boost::future<int> f)
|
void p3(boost::future<int> f)
|
||||||
{
|
{
|
||||||
|
assert(f.is_ready());
|
||||||
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
||||||
BOOST_TEST(f.valid());
|
BOOST_TEST(f.valid());
|
||||||
int i = f.get();
|
int i = f.get();
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ int main()
|
|||||||
BOOST_TEST(res[1].is_ready());
|
BOOST_TEST(res[1].is_ready());
|
||||||
BOOST_TEST(res[1].get() == 321);
|
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
|
// fixme darwin-4.8.0_11 terminate called without an active exception
|
||||||
{ // deferred future copy-constructible
|
{ // deferred future copy-constructible
|
||||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ int main()
|
|||||||
BOOST_TEST(boost::csbl::get<0>(res).is_ready());
|
BOOST_TEST(boost::csbl::get<0>(res).is_ready());
|
||||||
BOOST_TEST(boost::csbl::get<0>(res).get() == 123);
|
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
|
// fixme darwin-4.8.0_11 terminate called without an active exception
|
||||||
{ // deferred future copy-constructible
|
{ // deferred future copy-constructible
|
||||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ int main()
|
|||||||
BOOST_TEST(boost::csbl::get<1>(res).is_ready());
|
BOOST_TEST(boost::csbl::get<1>(res).is_ready());
|
||||||
BOOST_TEST(boost::csbl::get<1>(res).get() == 321);
|
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
|
// fixme darwin-4.8.0_11 terminate called without an active exception
|
||||||
{ // deferred future copy-constructible
|
{ // deferred future copy-constructible
|
||||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ int main()
|
|||||||
BOOST_TEST(res[1].is_ready());
|
BOOST_TEST(res[1].is_ready());
|
||||||
BOOST_TEST(res[1].get() == 321);
|
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
|
// fixme darwin-4.8.0_11 terminate called without an active exception
|
||||||
{ // deferred future copy-constructible
|
{ // deferred future copy-constructible
|
||||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ int main()
|
|||||||
BOOST_TEST(boost::csbl::get<0>(res).is_ready());
|
BOOST_TEST(boost::csbl::get<0>(res).is_ready());
|
||||||
BOOST_TEST(boost::csbl::get<0>(res).get() == 123);
|
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
|
// fixme darwin-4.8.0_11 terminate called without an active exception
|
||||||
{ // deferred future copy-constructible
|
{ // deferred future copy-constructible
|
||||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ int main()
|
|||||||
BOOST_TEST(boost::csbl::get<0>(res).get() == 123);
|
BOOST_TEST(boost::csbl::get<0>(res).get() == 123);
|
||||||
BOOST_TEST(boost::csbl::get<1>(res).get() == 321);
|
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
|
// fixme darwin-4.8.0_11 terminate called without an active exception
|
||||||
{ // deferred future copy-constructible
|
{ // deferred future copy-constructible
|
||||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
|
|
||||||
class non_copyable
|
class non_copyable
|
||||||
{
|
{
|
||||||
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
|
||||||
int val;
|
int val;
|
||||||
public:
|
public:
|
||||||
|
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
||||||
non_copyable(int v) : val(v){}
|
non_copyable(int v) : val(v){}
|
||||||
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
|
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; }
|
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
|
|
||||||
class non_copyable
|
class non_copyable
|
||||||
{
|
{
|
||||||
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
|
||||||
int val;
|
int val;
|
||||||
public:
|
public:
|
||||||
|
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
||||||
non_copyable(int v) : val(v){}
|
non_copyable(int v) : val(v){}
|
||||||
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
|
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; }
|
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ int main()
|
|||||||
boost::recursive_mutex::native_handle_type h = m.native_handle();
|
boost::recursive_mutex::native_handle_type h = m.native_handle();
|
||||||
BOOST_TEST(h);
|
BOOST_TEST(h);
|
||||||
#else
|
#else
|
||||||
#error "Test not applicable: BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE not defined for this platform as not supported"
|
#error "Test not applicable: BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE not defined for this platform as not supported"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||||
#endif
|
#endif
|
||||||
|
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
|
|
||||||
#include <boost/thread/future.hpp>
|
#include <boost/thread/future.hpp>
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
|
|
||||||
|
|
||||||
struct TestCallback
|
struct TestCallback
|
||||||
@@ -19,12 +22,14 @@ struct TestCallback
|
|||||||
|
|
||||||
result_type operator()(boost::future<void> future) const
|
result_type operator()(boost::future<void> future) const
|
||||||
{
|
{
|
||||||
|
assert(future.is_ready());
|
||||||
future.get();
|
future.get();
|
||||||
return boost::make_ready_future();
|
return boost::make_ready_future();
|
||||||
}
|
}
|
||||||
|
|
||||||
result_type operator()(boost::future<boost::future<void> > future) const
|
result_type operator()(boost::future<boost::future<void> > future) const
|
||||||
{
|
{
|
||||||
|
assert(future.is_ready());
|
||||||
future.get();
|
future.get();
|
||||||
return boost::make_ready_future();
|
return boost::make_ready_future();
|
||||||
}
|
}
|
||||||
@@ -33,12 +38,24 @@ struct TestCallback
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
#if ! defined BOOST_NO_CXX11_DECLTYPE && ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
#if ! defined BOOST_NO_CXX11_DECLTYPE && ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
||||||
|
{
|
||||||
boost::promise<void> test_promise;
|
boost::promise<void> test_promise;
|
||||||
boost::future<void> test_future(test_promise.get_future());
|
boost::future<void> test_future(test_promise.get_future());
|
||||||
auto f1 = test_future.then(TestCallback());
|
auto f1 = test_future.then(TestCallback());
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
auto f2 = f1.then(TestCallback());
|
auto f2 = f1.then(TestCallback());
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<boost::future<void> > >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<boost::future<void> > >::value);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool executor;
|
||||||
|
boost::promise<void> test_promise;
|
||||||
|
boost::future<void> test_future(test_promise.get_future());
|
||||||
|
auto f1 = test_future.then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
auto f2 = f1.then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<boost::future<void> > >::value);
|
||||||
|
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||||
#endif
|
#endif
|
||||||
|
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||||
|
|
||||||
#include <boost/thread/future.hpp>
|
#include <boost/thread/future.hpp>
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||||
|
|
||||||
struct TestCallback
|
struct TestCallback
|
||||||
{
|
{
|
||||||
@@ -18,13 +21,23 @@ struct TestCallback
|
|||||||
|
|
||||||
result_type operator()(boost::future<void> future) const
|
result_type operator()(boost::future<void> future) const
|
||||||
{
|
{
|
||||||
future.get();
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
assert(future.is_ready());
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
future.wait();
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
return boost::make_ready_future();
|
return boost::make_ready_future();
|
||||||
}
|
}
|
||||||
|
|
||||||
result_type operator()(boost::future<boost::future<void> > future) const
|
result_type operator()(boost::future<boost::future<void> > future) const
|
||||||
{
|
{
|
||||||
future.get();
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
assert(future.is_ready());
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
assert(future.get().is_ready());
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
//boost::future<void> ff = future.get();
|
||||||
|
|
||||||
return boost::make_ready_future();
|
return boost::make_ready_future();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -35,6 +48,8 @@ void p1()
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
const int number_of_tests = 2;
|
||||||
|
|
||||||
#if ! defined BOOST_NO_CXX11_DECLTYPE && ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
#if ! defined BOOST_NO_CXX11_DECLTYPE && ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
|
||||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
{
|
{
|
||||||
@@ -43,34 +58,104 @@ int main()
|
|||||||
f1.wait();
|
f1.wait();
|
||||||
}
|
}
|
||||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
{
|
{
|
||||||
auto f1 = boost::make_ready_future().then(TestCallback());
|
auto f1 = boost::make_ready_future().then(TestCallback());
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
auto f2 = f1.unwrap();
|
auto f2 = f1.unwrap();
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<void> >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<void> >::value);
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
f2.wait();
|
f2.wait();
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
|
{
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
auto f1 = boost::make_ready_future().then(TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
boost::future<void> f2 = f1.get();
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
{
|
{
|
||||||
auto f1 = boost::make_ready_future().then(TestCallback());
|
auto f1 = boost::make_ready_future().then(TestCallback());
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
auto f2 = f1.unwrap();
|
auto f2 = f1.unwrap();
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<void> >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<void> >::value);
|
||||||
auto f3 = f2.then(TestCallback());
|
auto f3 = f2.then(TestCallback());
|
||||||
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f3), boost::future<boost::future<void> > >::value);
|
||||||
f3.wait();
|
f3.wait();
|
||||||
}
|
}
|
||||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
{
|
{
|
||||||
boost::make_ready_future().then(
|
boost::make_ready_future().then(
|
||||||
TestCallback()).unwrap().then(TestCallback()).get();
|
TestCallback()).unwrap().then(TestCallback()).get();
|
||||||
}
|
}
|
||||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
{
|
{
|
||||||
boost::future<void> f = boost::async(p1);
|
boost::future<void> f = boost::async(p1);
|
||||||
f.then(
|
f.then(
|
||||||
TestCallback()).unwrap().then(TestCallback()).get();
|
TestCallback()).unwrap().then(TestCallback()).get();
|
||||||
}
|
}
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
|
{
|
||||||
|
auto f1 = boost::make_ready_future().then(TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
auto f3 = f1.then(TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f3), boost::future<boost::future<void> > >::value);
|
||||||
|
f3.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool executor;
|
||||||
|
auto f1 = boost::make_ready_future().then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
auto f3 = f1.then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f3), boost::future<boost::future<void> > >::value);
|
||||||
|
f3.wait();
|
||||||
|
}
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool executor(1);
|
||||||
|
|
||||||
|
auto f1 = boost::make_ready_future().then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "] " << int(f1.valid()) << std::endl;
|
||||||
|
auto f2 = f1.unwrap();
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "] " << int(f2.valid()) << std::endl;
|
||||||
|
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<void> >::value);
|
||||||
|
auto f3 = f2.then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f3), boost::future<boost::future<void> > >::value);
|
||||||
|
f3.wait();
|
||||||
|
}
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
for (int i=0; i< number_of_tests; i++)
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool executor;
|
||||||
|
|
||||||
|
auto f1 = boost::make_ready_future().then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f1), boost::future<boost::future<void> > >::value);
|
||||||
|
auto f2 = f1.unwrap();
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f2), boost::future<void> >::value);
|
||||||
|
auto f3 = f2.then(executor, TestCallback());
|
||||||
|
BOOST_STATIC_ASSERT(std::is_same<decltype(f3), boost::future<boost::future<void> > >::value);
|
||||||
|
f3.wait();
|
||||||
|
}
|
||||||
|
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
42
test/test_11256.cpp
Normal file
42
test/test_11256.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (C) 2015 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
|
||||||
|
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/thread/thread_pool.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
auto createFuture()
|
||||||
|
{
|
||||||
|
boost::promise<void> promise;
|
||||||
|
promise.set_value();
|
||||||
|
return promise.get_future();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stepOne(boost::basic_thread_pool &executor)
|
||||||
|
{
|
||||||
|
auto sendFuture = createFuture();
|
||||||
|
auto wrappedFuture = sendFuture.then(executor, [](auto f) mutable {
|
||||||
|
return createFuture();
|
||||||
|
});
|
||||||
|
|
||||||
|
return wrappedFuture.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stepTwo(boost::basic_thread_pool &executor)
|
||||||
|
{
|
||||||
|
auto future = stepOne(executor);
|
||||||
|
return future.then(executor, [](auto f) {
|
||||||
|
assert(f.is_ready());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
boost::basic_thread_pool executor{1};
|
||||||
|
stepTwo(executor).get();
|
||||||
|
}
|
||||||
29
test/test_11266.cpp
Normal file
29
test/test_11266.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (C) 2015 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
|
||||||
|
|
||||||
|
#include <boost/thread/future.hpp>
|
||||||
|
|
||||||
|
void func(int) { }
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||||
|
{
|
||||||
|
boost::packaged_task<void(int)> task{func};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::packaged_task<void(int)> task{func};
|
||||||
|
|
||||||
|
task(0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::packaged_task<void(int)> task{func};
|
||||||
|
int x = 0;
|
||||||
|
task(x);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
using namespace boost::chrono;
|
using namespace boost::chrono;
|
||||||
|
|
||||||
typedef boost::scheduled_thread_pool scheduled_tp;
|
typedef boost::scheduled_thread_pool<> scheduled_tp;
|
||||||
|
|
||||||
void fn(int x)
|
void fn(int x)
|
||||||
{
|
{
|
||||||
@@ -46,19 +46,18 @@ void func2(scheduled_tp* tp, steady_clock::duration d)
|
|||||||
void test_timing(const int n)
|
void test_timing(const int n)
|
||||||
{
|
{
|
||||||
//This function should take n seconds to execute.
|
//This function should take n seconds to execute.
|
||||||
boost::scheduled_thread_pool se(4);
|
boost::scheduled_thread_pool<> se(4);
|
||||||
|
|
||||||
for(int i = 1; i <= n; i++)
|
for(int i = 1; i <= n; i++)
|
||||||
{
|
{
|
||||||
se.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
se.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
||||||
}
|
}
|
||||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
|
||||||
//dtor is called here so all task will have to be executed before we return
|
//dtor is called here so all task will have to be executed before we return
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_deque_timing()
|
void test_deque_timing()
|
||||||
{
|
{
|
||||||
boost::scheduled_thread_pool se(4);
|
boost::scheduled_thread_pool<> se(4);
|
||||||
for(int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
steady_clock::duration d = milliseconds(i*100);
|
steady_clock::duration d = milliseconds(i*100);
|
||||||
@@ -85,10 +84,10 @@ void test_deque_multi(const int n)
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
steady_clock::time_point start = steady_clock::now();
|
//steady_clock::time_point start = steady_clock::now();
|
||||||
test_timing(5);
|
test_timing(5);
|
||||||
steady_clock::duration diff = steady_clock::now() - start;
|
//steady_clock::duration diff = steady_clock::now() - start;
|
||||||
BOOST_TEST(diff > milliseconds(500));
|
//BOOST_TEST(diff > milliseconds(500));
|
||||||
test_deque_timing();
|
test_deque_timing();
|
||||||
test_deque_multi(4);
|
test_deque_multi(4);
|
||||||
test_deque_multi(8);
|
test_deque_multi(8);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ typedef boost::executors::basic_thread_pool thread_pool;
|
|||||||
|
|
||||||
void fn(int x)
|
void fn(int x)
|
||||||
{
|
{
|
||||||
//std::cout << "[" << __LINE__ << "] " << steady_clock::now() << std::endl;
|
|
||||||
std::cout << x << std::endl;
|
std::cout << x << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ int main()
|
|||||||
test_after(5, sch);
|
test_after(5, sch);
|
||||||
test_at(5, sch);
|
test_at(5, sch);
|
||||||
test_on(5, sch, tp);
|
test_on(5, sch, tp);
|
||||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
std::cout << "[" << __LINE__ << "] " << std::endl;
|
||||||
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ typedef boost::executors::basic_thread_pool thread_pool;
|
|||||||
|
|
||||||
void fn(int x)
|
void fn(int x)
|
||||||
{
|
{
|
||||||
//std::cout << "[" << __LINE__ << "] " << steady_clock::now() << std::endl;
|
|
||||||
std::cout << x << std::endl;
|
std::cout << x << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,14 +40,10 @@ void test_timing(const int n)
|
|||||||
sa.submit_after(boost::bind(fn,i),seconds(i));
|
sa.submit_after(boost::bind(fn,i),seconds(i));
|
||||||
sa.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
sa.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
||||||
}
|
}
|
||||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
steady_clock::time_point start = steady_clock::now();
|
|
||||||
test_timing(5);
|
test_timing(5);
|
||||||
steady_clock::duration diff = steady_clock::now() - start;
|
|
||||||
BOOST_TEST(diff > seconds(5));
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
unsigned throw_one = 0xFFFF;
|
unsigned throw_one = 0xFFFF;
|
||||||
|
|
||||||
#if defined _GLIBCXX_THROW
|
#if defined _GLIBCXX_THROW
|
||||||
void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
|
inline void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
|
||||||
#elif defined BOOST_MSVC
|
#elif defined BOOST_MSVC
|
||||||
void* operator new(std::size_t s)
|
inline void* operator new(std::size_t s)
|
||||||
#else
|
#else
|
||||||
void* operator new(std::size_t s) throw (std::bad_alloc)
|
void* operator new(std::size_t s) throw (std::bad_alloc)
|
||||||
#endif
|
#endif
|
||||||
@@ -40,9 +40,9 @@ void* operator new(std::size_t s) throw (std::bad_alloc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined BOOST_MSVC
|
#if defined BOOST_MSVC
|
||||||
void operator delete(void* p)
|
inline void operator delete(void* p)
|
||||||
#else
|
#else
|
||||||
void operator delete(void* p) throw ()
|
inline void operator delete(void* p) throw ()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
unsigned throw_one = 0xFFFF;
|
unsigned throw_one = 0xFFFF;
|
||||||
|
|
||||||
#if defined _GLIBCXX_THROW
|
#if defined _GLIBCXX_THROW
|
||||||
void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
|
inline void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
|
||||||
#elif defined BOOST_MSVC
|
#elif defined BOOST_MSVC
|
||||||
void* operator new(std::size_t s)
|
inline void* operator new(std::size_t s)
|
||||||
#else
|
#else
|
||||||
void* operator new(std::size_t s) throw (std::bad_alloc)
|
void* operator new(std::size_t s) throw (std::bad_alloc)
|
||||||
#endif
|
#endif
|
||||||
@@ -41,9 +41,9 @@ void* operator new(std::size_t s) throw (std::bad_alloc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined BOOST_MSVC
|
#if defined BOOST_MSVC
|
||||||
void operator delete(void* p)
|
inline void operator delete(void* p)
|
||||||
#else
|
#else
|
||||||
void operator delete(void* p) throw ()
|
inline void operator delete(void* p) throw ()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
std::free(p);
|
std::free(p);
|
||||||
|
|||||||
Reference in New Issue
Block a user