mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
168 Commits
boost-1.56
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8ad389bdd | ||
|
|
69c1d40750 | ||
|
|
58698f44f1 | ||
|
|
37afdd2e9a | ||
|
|
c87b24923a | ||
|
|
1210fc4859 | ||
|
|
d8b6ae6266 | ||
|
|
04e2223d5e | ||
|
|
579748e7a0 | ||
|
|
41c3914aaf | ||
|
|
8693eec4a4 | ||
|
|
3f699750a8 | ||
|
|
4f8243cf59 | ||
|
|
4f01891da7 | ||
|
|
efab5af918 | ||
|
|
4d03b410a8 | ||
|
|
c1925df81c | ||
|
|
cbf9fe8a5c | ||
|
|
6fd7dc0d94 | ||
|
|
a2f2924298 | ||
|
|
49d485f1aa | ||
|
|
d7251f223e | ||
|
|
20a6ef7de8 | ||
|
|
d5c41e4c4a | ||
|
|
b96b9904b7 | ||
|
|
304240b206 | ||
|
|
c61c139933 | ||
|
|
c3b98129e4 | ||
|
|
3891eeef52 | ||
|
|
f1370b1255 | ||
|
|
69f2a1df72 | ||
|
|
700301e382 | ||
|
|
952aa44a98 | ||
|
|
5fb51a74fe | ||
|
|
02bb6abef4 | ||
|
|
1a4bd71616 | ||
|
|
63dd439992 | ||
|
|
1029fa9c59 | ||
|
|
3e28ea806c | ||
|
|
07dc40a9ff | ||
|
|
6f91af2154 | ||
|
|
c3cff80557 | ||
|
|
729c8b63bb | ||
|
|
6fe7f44ea0 | ||
|
|
8fd4755e79 | ||
|
|
02b007a20e | ||
|
|
c0c78e87fc | ||
|
|
58cde5af05 | ||
|
|
c1f2c8a1f1 | ||
|
|
bacf5b52ec | ||
|
|
3babf7966e | ||
|
|
f3de7bf10f | ||
|
|
90154217cf | ||
|
|
ac0b2f9ba7 | ||
|
|
da739e680a | ||
|
|
b240b097c7 | ||
|
|
debe2fb0d1 | ||
|
|
b264ec8fc0 | ||
|
|
372f8fe10f | ||
|
|
e3c240df0a | ||
|
|
748ea5164e | ||
|
|
b44627f97d | ||
|
|
c8cd7d1d08 | ||
|
|
f0d0c0551b | ||
|
|
bb72eadbd8 | ||
|
|
f52f32afda | ||
|
|
b973e9b32e | ||
|
|
1ffef9ed2d | ||
|
|
f24ea524bd | ||
|
|
4111471ba5 | ||
|
|
5e970b987e | ||
|
|
c7b5729cf3 | ||
|
|
291ebded8e | ||
|
|
0c2c8ed3b8 | ||
|
|
5294dfa149 | ||
|
|
7f5dfb633d | ||
|
|
f381a7d591 | ||
|
|
aceabda609 | ||
|
|
dc4b619b57 | ||
|
|
abb3fc97e0 | ||
|
|
ec6ae7b9b4 | ||
|
|
8c5ba97d39 | ||
|
|
617b979214 | ||
|
|
96667cfcce | ||
|
|
a981650ce9 | ||
|
|
00b25853b2 | ||
|
|
ef04ce8bce | ||
|
|
5091ad705f | ||
|
|
b77f802c47 | ||
|
|
da945436c1 | ||
|
|
27befdf26f | ||
|
|
f73007910a | ||
|
|
8c3cfacf06 | ||
|
|
7d4392e157 | ||
|
|
aff3f424a9 | ||
|
|
546ca909c4 | ||
|
|
7dac51706c | ||
|
|
5ee0e27b5a | ||
|
|
b4fd7fdeb1 | ||
|
|
c75ea7db89 | ||
|
|
19294dc756 | ||
|
|
52a360775e | ||
|
|
c632b75db1 | ||
|
|
11e4c950ac | ||
|
|
8440e9a7d8 | ||
|
|
02bc292c20 | ||
|
|
6d68bac44b | ||
|
|
5d0d128cab | ||
|
|
ec542d3c8b | ||
|
|
6e3216643b | ||
|
|
016f5653cf | ||
|
|
ce46539183 | ||
|
|
e93035ce42 | ||
|
|
53a46593a8 | ||
|
|
c2426b8fad | ||
|
|
7d841f6337 | ||
|
|
556bbde8a7 | ||
|
|
a0c1462a6a | ||
|
|
234df13faf | ||
|
|
24983f0bce | ||
|
|
722997379b | ||
|
|
f36f5d6dbb | ||
|
|
9ee1044f92 | ||
|
|
ebeb36646c | ||
|
|
8ebf0e7f21 | ||
|
|
0dc2f69bc1 | ||
|
|
c3b549d947 | ||
|
|
6552cf64b5 | ||
|
|
d5f335b8a4 | ||
|
|
80591fb64d | ||
|
|
0543b522cb | ||
|
|
3dbc5d0664 | ||
|
|
2d0272345b | ||
|
|
f1a274b51c | ||
|
|
b7f1706ab8 | ||
|
|
f299fb8083 | ||
|
|
074dcbcbf5 | ||
|
|
af6f80a3c7 | ||
|
|
957253401f | ||
|
|
3195253230 | ||
|
|
4336a7bbe3 | ||
|
|
3b75d6dabc | ||
|
|
fc0d7e23b3 | ||
|
|
aeabda8d45 | ||
|
|
3bde7e103c | ||
|
|
ea0889485e | ||
|
|
d4d46c64dd | ||
|
|
f3fa80c866 | ||
|
|
7e21f24991 | ||
|
|
2037a64c51 | ||
|
|
8bfd1cea31 | ||
|
|
a26e7eb8c4 | ||
|
|
e47eba8751 | ||
|
|
8aef8000d9 | ||
|
|
78f1044c68 | ||
|
|
26042ca26a | ||
|
|
74132067ba | ||
|
|
c4d42e6b6c | ||
|
|
59c504d5d8 | ||
|
|
b81a838a43 | ||
|
|
a06dde3794 | ||
|
|
726a3faf19 | ||
|
|
c977c8d420 | ||
|
|
a1faacd7bb | ||
|
|
866b78cbd0 | ||
|
|
0861f81b05 | ||
|
|
6488028a22 | ||
|
|
9ceea9822f |
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#mac
|
||||
.DS_Store
|
||||
|
||||
#projects
|
||||
.project
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
bin/*
|
||||
test/bin/*
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
#doc
|
||||
|
||||
doc/html
|
||||
@@ -78,12 +78,12 @@ project boost/thread
|
||||
<toolset>pathscale:<cxxflags>-pedantic
|
||||
|
||||
<toolset>clang:<cxxflags>-Wextra
|
||||
<toolset>clang:<cxxflags>-pedantic
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
<toolset>clang:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>clang:<warnings>on
|
||||
|
||||
#<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software
|
||||
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
#include "../../../boost/atomic.hpp"
|
||||
#include "../../../boost/static_assert.hpp"
|
||||
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software
|
||||
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
|
||||
return 0;
|
||||
}
|
||||
#include "../../../boost/atomic.hpp"
|
||||
#include "../../../boost/static_assert.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from tis paper to show the differences.]
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from this paper to show the differences.]
|
||||
|
||||
Executors are objects that can execute units of work packaged as function objects. Boost.Thread differs from N3785 mainly in the an Executor doesn't needs to inherit from an abstract class Executor. Static polymorphism is used instead and type erasure is used internally.
|
||||
|
||||
@@ -122,27 +122,26 @@ An Executor is an object that schedules the closures that have been submitted to
|
||||
|
||||
* The choice of which executor to use is explicit. This is important for reasons described in the Motivation section. In particular, consider the common case of an asynchronous operation that itself spawns asynchronous operations. If both operations ran on the same executor, and if that executor had a bounded number of worker threads, then we could get deadlock. Programs often deal with such issues by splitting different kinds of work between different executors.
|
||||
|
||||
* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable a robust way.
|
||||
* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable and robust way.
|
||||
|
||||
* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is suing without making it a template and it possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
|
||||
* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is using without making it a template and is possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
|
||||
|
||||
* Conceptually, an executor puts closures on a queue and at some point executes them. The queue is always unbounded, so adding a closure to an executor never blocks. (Defining “never blocks” formally is challenging, but informally we just mean that submit() is an ordinary function that executes something and returns, rather than waiting for the completion of some potentially long running operation in another thread.)
|
||||
|
||||
[heading Closure]
|
||||
|
||||
One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `voidv.
|
||||
One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `void`.
|
||||
|
||||
N3785 choose the more specific `std::function<void()>` as it provides only dynamic polymorphism and states that in practice the implementation of a template based approach or another approach is impractical. The authors of this library think that the template based approach is compatible with a dynamic based approach. They give some arguments:
|
||||
|
||||
The first one is that a virtual function can not be a template. This is true but it is also true that the executor interface can provide the template functions that call to the virtual public functions. Another reason they give is that "a template parameter would complicate the interface without adding any real generality. In the end an executor class is going to need some kind of type erasure to handle all the different kinds of function objects with `void()` signature, and that’s exactly what std::function already does". We think that it is up to the executor to manage with this implementation details, not to the user.
|
||||
|
||||
We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what is needs.
|
||||
We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what she needs.
|
||||
|
||||
The third one is related to performance. They assert that "any mechanism for storing closures on an executor’s queue will have to use some form of type erasure. There’s no reason to believe that a custom closure mechanism, written just for std::executor and used nowhere else within the standard library, would be better in that respect than `std::function<void()>`". We believe that the implementation can do better that storing the closure on a `std::function<void()>`. e.g. the implementation can use intrusive data to store the closure and the pointers to other nodes needed to store the closures in a given order.
|
||||
|
||||
In addition `std::function<void()>` can not be constructed by moving the closure, so e.g. `std::packaged_task` could not be a Closure.
|
||||
|
||||
[/
|
||||
[heading Scheduled work]
|
||||
|
||||
The approach of this library respect to scheduled work of the N3785 proposal is quite different. Instead of adding the scheduled operations to a specific scheduled_executor polymorphic interface, we opt by adding two member template functions to a class scheduled_executor that wraps an existing executor. This has several advantages:
|
||||
@@ -156,7 +155,6 @@ In order to manage with all the clocks, there are two alternatives:
|
||||
* have a single instance of a `scheduled_executor<Clock>` for each `CLock`.
|
||||
|
||||
The library chose the first of those options, largely for simplicity.
|
||||
]
|
||||
|
||||
[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.
|
||||
@@ -166,7 +164,7 @@ Note that when we combine `boost::async` and `Executors`, the exception will be
|
||||
|
||||
It is common idiom to set some thread local variable at the beginning of a thread. As Executors could instantiate threads internally these Executors shall have the ability to call a user specific function at thread entry on the executor constructor.
|
||||
|
||||
For executors that don't instantiate any thread an that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
|
||||
For executors that don't instantiate any thread and that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
|
||||
|
||||
[heading Cancelation]
|
||||
|
||||
@@ -182,49 +180,108 @@ An alternative is to make async return a cancelable_task but this will need also
|
||||
[/
|
||||
The library would provide in the future a cancelable_task that could support cancelation.
|
||||
|
||||
class cancelation_state {
|
||||
std::atomic<bool> requested; std::atomic<bool> enabled; std::condition_variable* cond; std::mutex cond_mutex;
|
||||
public:
|
||||
cancelation_state(): thread_cond(0) {} void cancel() { requested.store(true,std::memory_order_relaxed); std::lock_guard<std::mutex> lk(cond_mutex); if(cond) { cond->notify_all(); } } bool cancellation_requested() const { return requested.load(std::memory_order_relaxed); }
|
||||
void enable() { enable.store(true,std::memory_order_relaxed); } void disable() { enable.store(false,std::memory_order_relaxed); } bool cancellation_enabled() const { return enabled.load(std::memory_order_relaxed); } void set_condition_variable(std::condition_variable& cv) { std::lock_guard<std::mutex> lk(cond_mutex); cond = &cv; } void clear_condition_variable() { std::lock_guard<std::mutex> lk(cond_mutex); cond = 0; } struct clear_cv_on_destruct { ~clear_cv_on_destruct() { this_thread_interrupt_flag.clear_condition_variable(); } };
|
||||
void cancelation_point();
|
||||
void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { cancelation_point(); this_cancelable_state.set_condition_variable(cv); this_cancelable_state::clear_cv_on_destruct guard; interruption_point();
|
||||
cv.wait_for(lk, std::chrono::milliseconds(1)); this_cancelable_state.clear_condition_variable(); cancelation_point(); }
|
||||
class disable_cancelation
|
||||
{
|
||||
public:
|
||||
disable_cancelation(const disable_cancelation&) = delete;
|
||||
disable_cancelation& operator=(const disable_cancelation&) = delete;
|
||||
disable_cancelation(cancelable_closure& closure) noexcept;
|
||||
~disable_cancelation() noexcept;
|
||||
};
|
||||
class restore_cancelation
|
||||
{
|
||||
public:
|
||||
restore_cancelation(const restore_cancelation&) = delete;
|
||||
restore_cancelation& operator=(const restore_cancelation&) = delete;
|
||||
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
|
||||
~restore_cancelation() noexcept;
|
||||
};
|
||||
};
|
||||
|
||||
template <class Closure>
|
||||
struct cancelable_closure_mixin : cancelable_closure {
|
||||
void operator() {
|
||||
cancel_point();
|
||||
this->Closure::run();
|
||||
}
|
||||
};
|
||||
|
||||
struct my_clousure : cancelable_closure_mixin<my_clousure>
|
||||
class cancelation_state
|
||||
{
|
||||
void run() {
|
||||
while () {
|
||||
cancel_point();
|
||||
}
|
||||
}
|
||||
std::atomic<bool> requested;
|
||||
std::atomic<bool> enabled;
|
||||
std::condition_variable* cond;
|
||||
std::mutex cond_mutex;
|
||||
public:
|
||||
cancelation_state() :
|
||||
thread_cond(0)
|
||||
{
|
||||
}
|
||||
void cancel()
|
||||
{
|
||||
requested.store(true, std::memory_order_relaxed);
|
||||
std::lock_guard < std::mutex > lk(cond_mutex);
|
||||
if (cond)
|
||||
{
|
||||
cond->notify_all();
|
||||
}
|
||||
}
|
||||
bool cancellation_requested() const
|
||||
{
|
||||
return requested.load(std::memory_order_relaxed);
|
||||
}
|
||||
void enable()
|
||||
{
|
||||
enable.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
void disable()
|
||||
{
|
||||
enable.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
bool cancellation_enabled() const
|
||||
{
|
||||
return enabled.load(std::memory_order_relaxed);
|
||||
}
|
||||
void set_condition_variable(std::condition_variable& cv)
|
||||
{
|
||||
std::lock_guard < std::mutex > lk(cond_mutex);
|
||||
cond = &cv;
|
||||
}
|
||||
void clear_condition_variable()
|
||||
{
|
||||
std::lock_guard < std::mutex > lk(cond_mutex);
|
||||
cond = 0;
|
||||
}
|
||||
struct clear_cv_on_destruct
|
||||
{
|
||||
~clear_cv_on_destruct()
|
||||
{
|
||||
this_thread_interrupt_flag.clear_condition_variable();
|
||||
}
|
||||
};
|
||||
void cancelation_point();
|
||||
void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk)
|
||||
{
|
||||
cancelation_point();
|
||||
this_cancelable_state.set_condition_variable(cv);
|
||||
this_cancelable_state::clear_cv_on_destruct guard;
|
||||
interruption_point();
|
||||
cv.wait_for(lk, std::chrono::milliseconds(1));
|
||||
this_cancelable_state.clear_condition_variable();
|
||||
cancelation_point();
|
||||
}
|
||||
class disable_cancelation
|
||||
{
|
||||
public:
|
||||
disable_cancelation(const disable_cancelation&)= delete;
|
||||
disable_cancelation& operator=(const disable_cancelation&)= delete;
|
||||
disable_cancelation(cancelable_closure& closure)
|
||||
noexcept ;
|
||||
~disable_cancelation() noexcept;
|
||||
};
|
||||
class restore_cancelation
|
||||
{
|
||||
public:
|
||||
restore_cancelation(const restore_cancelation&) = delete;
|
||||
restore_cancelation& operator=(const restore_cancelation&) = delete;
|
||||
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
|
||||
~restore_cancelation() noexcept;
|
||||
};
|
||||
};
|
||||
|
||||
template <class Closure>
|
||||
struct cancelable_closure_mixin: cancelable_closure
|
||||
{
|
||||
void operator()
|
||||
{
|
||||
cancel_point();this->Closure::run();
|
||||
}
|
||||
};
|
||||
|
||||
struct my_clousure: cancelable_closure_mixin<my_clousure>
|
||||
{
|
||||
void run()
|
||||
{
|
||||
while ()
|
||||
{
|
||||
cancel_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
[heading Current executor]
|
||||
@@ -287,9 +344,6 @@ The `Executor` concept models the common operations of all the executors.
|
||||
|
||||
A type `E` meets the `Executor` requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `E::work`
|
||||
* `e.submit(lw);`
|
||||
* `e.submit(rw);`
|
||||
* `e.submit(lc);`
|
||||
* `e.submit(rc);`
|
||||
* `e.close();`
|
||||
@@ -300,50 +354,10 @@ A type `E` meets the `Executor` requirements if the following expressions are we
|
||||
where
|
||||
|
||||
* `e` denotes a value of type `E`,
|
||||
* `lw` denotes a lvalue referece of type `E::work`,
|
||||
* `rc` denotes a rvalue referece of type `E::work`
|
||||
* `lc` denotes a lvalue referece of type `Closure`,
|
||||
* `rc` denotes a rvalue referece of type `Closure`
|
||||
* `p` denotes a value of type `Predicate`
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:submitlw `e.submit(lw);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitrw `e.submit(rw);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitlc `e.submit(lc);`]
|
||||
|
||||
@@ -401,15 +415,16 @@ If invoked closure throws an exception the executor will call std::terminate, as
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:close `b = e.close();`]
|
||||
[section:closed `b = e.closed();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [`void`.]]
|
||||
[[Return:] [whether the pool is closed for submissions.]]
|
||||
|
||||
[[Throws:] [Whatever exception that can be throw while ensuring the thread safety.]]
|
||||
|
||||
[[Throws:] [whether the pool is closed for submissions.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -433,7 +448,7 @@ If invoked closure throws an exception the executor will call std::terminate, as
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_executing_one `e.reschedule_until(p);`]
|
||||
[section:reschedule_until `e.reschedule_until(p);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -491,6 +506,7 @@ Executor abstract base class.
|
||||
virtual bool closed() = 0;
|
||||
|
||||
virtual void submit(work&& closure) = 0;
|
||||
virtual void submit(work& closure) = 0;
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
@@ -553,12 +569,13 @@ Polymorphic adaptor of a model of Executor to an executor.
|
||||
template <typename ...Args>
|
||||
executor_adaptor(Args&& ... args);
|
||||
|
||||
Executor& underlying_executor();
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
void submit(work& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
|
||||
@@ -584,7 +601,7 @@ Polymorphic adaptor of a model of Executor to an executor.
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~executor_adaptor()`]
|
||||
|
||||
virtual ~ executor_adaptor();
|
||||
virtual ~executor_adaptor();
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -598,47 +615,78 @@ Polymorphic adaptor of a model of Executor to an executor.
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/
|
||||
|
||||
[/////////////////////////////////]
|
||||
[section:generic_executor_ref Class `generic_executor_ref`]
|
||||
|
||||
Executor abstract base class.
|
||||
|
||||
#include <boost/thread/generic_executor_ref.hpp>
|
||||
namespace boost {
|
||||
class generic_executor_ref
|
||||
{
|
||||
public:
|
||||
generic_executor_ref(generic_executor_ref const&);
|
||||
generic_executor_ref& operator=(generic_executor_ref const&);
|
||||
|
||||
template <class Executor>
|
||||
generic_executor_ref(Executor& ex);
|
||||
generic_executor_ref() {};
|
||||
|
||||
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:scheduled_executor Template Class `scheduled_executor`]
|
||||
[section:scheduled_executor_ref Template Class `scheduled_executor_ref`]
|
||||
|
||||
Executor providing time related functions.
|
||||
|
||||
#include <boost/thread/scheduled_executor.hpp>
|
||||
#include <boost/thread/executors/scheduled_executor_ref.hpp>
|
||||
namespace boost {
|
||||
template <class Executor>
|
||||
class scheduled_executor
|
||||
class scheduled_executor_ref
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
typedef executor::work work;
|
||||
|
||||
scheduled_executor(scheduled_executor const&) = delete;
|
||||
scheduled_executor& operator=(scheduled_executor const&) = delete;
|
||||
scheduled_executor_ref(scheduled_executor_ref const&) = delete;
|
||||
scheduled_executor_ref& operator=(scheduled_executor_ref const&) = delete;
|
||||
|
||||
template <class Rep, class Period>
|
||||
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
scheduled_executor_ref(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
|
||||
Executor& underlying_executor();
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
void submit(work& closure);
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
@@ -658,14 +706,14 @@ Executor providing time related functions.
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `scheduled_executor(Executor&, chrono::duration<Rep, Period>)`]
|
||||
[section:constructor Constructor `scheduled_executor_ref(Executor&, chrono::duration<Rep, Period>)`]
|
||||
|
||||
template <class Rep, class Period>
|
||||
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
scheduled_executor_ref(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a scheduled_executor. ]]
|
||||
[[Effects:] [Constructs a scheduled_executor_ref. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
@@ -674,9 +722,9 @@ Executor providing time related functions.
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~scheduled_executor()`]
|
||||
[section:destructor Destructor `~scheduled_executor_ref()`]
|
||||
|
||||
~scheduled_executor();
|
||||
~scheduled_executor_ref();
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -690,12 +738,29 @@ Executor providing time related functions.
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:submit_at Template Function Member `submit_at()`]
|
||||
|
||||
template <class Clock, class Duration, typename Closure>
|
||||
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
|
||||
template <class Rep, class Period, typename Closure>
|
||||
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
@@ -703,11 +768,12 @@ Executor providing time related functions.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
]
|
||||
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:scheduled_executor Template Class `serial_executor`]
|
||||
[section:serial_executor Template Class `serial_executor`]
|
||||
|
||||
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||
|
||||
@@ -716,21 +782,18 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
template <class Executor>
|
||||
class serial_executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
typedef executors::work work;
|
||||
|
||||
serial_executor(serial_executor const&) = delete;
|
||||
serial_executor& operator=(serial_executor const&) = delete;
|
||||
|
||||
template <class Executor>
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
Executor& underlying_executor();
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
@@ -742,8 +805,9 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `serial_executor(Executor&, chrono::duration<Rep, Period>)`]
|
||||
[section:constructor Constructor `serial_executor(Executor&)`]
|
||||
|
||||
template <class Executor>
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
[variablelist
|
||||
@@ -773,7 +837,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
generic_executor_ref& underlying_executor() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -788,6 +852,145 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
|
||||
[endsect]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:generic_serial_executor Class `generic_serial_executor`]
|
||||
|
||||
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||
|
||||
#include <boost/thread/generic_serial_executor.hpp>
|
||||
namespace boost {
|
||||
class generic_serial_executor
|
||||
{
|
||||
public:
|
||||
generic_serial_executor(generic_serial_executor const&) = delete;
|
||||
generic_serial_executor& operator=(generic_serial_executor const&) = delete;
|
||||
|
||||
template <class Executor>
|
||||
generic_serial_executor(Executor& ex);
|
||||
|
||||
generic_executor_ref& 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_executor(Executor&)`]
|
||||
|
||||
template <class Executor>
|
||||
generic_serial_executor(Executor& ex);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a serial_executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~serial_executor()`]
|
||||
|
||||
~generic_serial_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the serial_executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:inline_executor Class `inline_executor`]
|
||||
|
||||
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||
|
||||
#include <boost/thread/inline_executor.hpp>
|
||||
namespace boost {
|
||||
class inline_executor
|
||||
{
|
||||
public:
|
||||
inline_executor(inline_executor const&) = delete;
|
||||
inline_executor& operator=(inline_executor const&) = delete;
|
||||
|
||||
inline_executor();
|
||||
|
||||
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 `inline_executor()`]
|
||||
|
||||
inline_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a inline_executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~inline_executor()`]
|
||||
|
||||
~inline_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the inline_executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -796,13 +999,12 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
|
||||
A thread pool with up to a fixed number of threads.
|
||||
|
||||
#include <boost/thread/work.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
namespace boost {
|
||||
class basic_thread_pool
|
||||
{
|
||||
public:
|
||||
typedef boost::work work;
|
||||
|
||||
|
||||
basic_thread_pool(basic_thread_pool const&) = delete;
|
||||
basic_thread_pool& operator=(basic_thread_pool const&) = delete;
|
||||
|
||||
@@ -841,7 +1043,7 @@ A thread pool with up to a fixed number of threads.
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~basic_thread_pool()`]
|
||||
|
||||
virtual ~basic_thread_pool();
|
||||
~basic_thread_pool();
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -854,6 +1056,64 @@ A thread pool with up to a fixed number of threads.
|
||||
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////////////]
|
||||
[section:thread_executor Class `thread_executor`]
|
||||
|
||||
A thread_executor with a threads for each task.
|
||||
|
||||
#include <boost/thread/executors/thread_executor.hpp>
|
||||
namespace boost {
|
||||
class thread_executor
|
||||
{
|
||||
public:
|
||||
|
||||
thread_executor(thread_executor const&) = delete;
|
||||
thread_executor& operator=(thread_executor const&) = delete;
|
||||
|
||||
thread_executor();
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
|
||||
~thread_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `thread_executor()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [creates a thread_executor. ]]
|
||||
|
||||
[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~thread_executor()`]
|
||||
|
||||
~thread_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits for closures (if any) to complete, then joins and destroys the threads.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[/////////////////////////////////]
|
||||
[section:loop_executor Class `loop_executor`]
|
||||
|
||||
@@ -864,8 +1124,7 @@ A user scheduled executor.
|
||||
class loop_executor
|
||||
{
|
||||
public:
|
||||
typedef thread_detail::work work;
|
||||
|
||||
|
||||
loop_executor(loop_executor const&) = delete;
|
||||
loop_executor& operator=(loop_executor const&) = delete;
|
||||
|
||||
@@ -909,7 +1168,7 @@ A user scheduled executor.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the thread pool.]]
|
||||
[[Effects:] [Destroys the executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
|
||||
107
doc/changes.qbk
107
doc/changes.qbk
@@ -8,6 +8,101 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[heading Version 4.5.0 - boost 1.58]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10537 #10537] Application crash on throw exception
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries,
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9600 #9600] Async: Add task_region
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10611 #10611] Add emplace promise::set_value and emplace make_ready_future
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
|
||||
[heading Version 4.4.0 - boost 1.57]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10537 #10537] Application crash on throw exception
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries,
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Synchro: Use of variadic templates on Generic Locking Algorithms on compilers providing them
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10298 #10298] Synchro: Added queue views.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10300 #10300] Async: Added generic_executor_ref.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10552 #10552] Add make_valid_future
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6782 #6782] call_once uses incorrect barrier intrinsic on Visual Studio
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7665 #7665] this_thread::sleep_for no longer uses steady_clock in thread
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9307 #9307] future::fallback_to assert with ERRORRRRR boost: mutex lock failed in pthread_mutex_lock: Invalid argument
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9308 #9308] future::async fails with terminate called throwing an exception when called with a lambda - clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9425 #9425] Boost promise & future does not use supplied allocator for value storage
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9558 #9558] future continuations unit test hangs in get()/pthread_cond_wait() on Mac 10.7/32-bit/x86/darwin-4.2.1
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9787 #9787] [windows] Small duration value passed down to basic_timed_mutex::try_lock_until and condition_variable::wait_until can cause infinite or near infinite wait for win32
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9880 #9880] [windows] boost::condition_variable.timed_wait() exception if system time < 1970
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10159 #10159] GCC 4.4 error sorry, unimplemented
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10196 #10196] thread_specific_ptr does not support void*
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10296 #10296] Boost.Thread 1.56 rc1 does not compile on Mingw
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10297 #10297] Boost.Thread 1.56 rc1 hangs when built with clang on armhf
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10340 #10340] No boost::promise<T>::set_value(const T&) overload present in C++03 mode
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10425 #10425] Missing documentation for when_all/when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10426 #10426] Take in account the deferred futures in when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10427 #10427] Take in account the deferred and ready futures in when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10428 #10428] Adapt to new unique_ptr interface in Boost.Move
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10465 #10465] Missing implementation of when_all/when_any when the result is a tuple.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10476 #10476] classes using BOOST_THREAD_MOVABLE_ONLY<T> dont satisfy is_copy_constructible<T>::value == false
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10478 #10478] Data race in boost/thread/future.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10529 #10529] The pthread/condition_variable_any constructor reports incorrect error code for pthread_cond_init
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10563 #10563] shared_future<R>::then should be const
|
||||
|
||||
|
||||
[heading Version 4.3.0 - boost 1.56]
|
||||
|
||||
[*Know Bugs:]
|
||||
@@ -28,7 +123,7 @@
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/release/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
|
||||
[*Sever limitations:]
|
||||
@@ -496,9 +591,6 @@ been moved to __thread_id__.
|
||||
|
||||
The following features will be included in next releases.
|
||||
|
||||
# Complete the C++11 missing features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
|
||||
|
||||
# Add some minor features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
|
||||
@@ -506,13 +598,6 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
|
||||
|
||||
# Add some of the extension proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf A Standardized Representation of Asynchronous Operations] or extension to them, in particular
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
|
||||
|
||||
# And some additional extensions related to futures as:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic shared_future::then.
|
||||
|
||||
@@ -101,7 +101,31 @@
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:cxx1y C++1y TS Concurrency - On going proposals]
|
||||
|
||||
[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]]
|
||||
|
||||
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[2.1] [ - ] [ - ] [ - ]]
|
||||
[[2.2] [Class template future] [Partial] [ - ]]
|
||||
[[2.2] [then] [ Partial ] [ without implicit unwrapping #10550 and blocking #10551 ]]
|
||||
[[2.2] [is_ready] [ Yes ] [ - ]]
|
||||
[[2.3] [Class template shared_future] [Partial] [ - ]]
|
||||
[[2.3] [then] [ Partial ] [ Without implicit unwrapping #10550 and blocking #10551 ]]
|
||||
[[2.3] [is_ready] [ Yes ] [ - ]]
|
||||
[[2.4] [Function template when_all] [Partial] [ interface not complete #10426 and blocking #10551 ]]
|
||||
[[2.5] [Function template when_any] [Partial] [ interface not complete #10427 and blocking #10551 ]]
|
||||
[[2.6] [Function template when_any_back] [No] [ #XXXX ]]
|
||||
[[2.7] [Function template make_ready_future] [Yes] [ - ]]
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:cxx1y C++1z TS Concurrency - On going proposals]
|
||||
|
||||
[section:latch C++ Latches and Barriers]
|
||||
|
||||
@@ -161,8 +185,6 @@
|
||||
[endsect]
|
||||
[section:executors Asynchronous Executors]
|
||||
|
||||
While Boost.Thread implementation of executors would not use dynamic polymorphism, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3785.pdf N3785 Executors and Schedulers]]
|
||||
|
||||
[table Asynchronous Executors
|
||||
@@ -181,30 +203,13 @@ While Boost.Thread implementation of executors would not use dynamic polymorphis
|
||||
[[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor<thread_executor> ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:async 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]]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3857.pdf N3857-Improvements to std::future<T> and Related APIs]]
|
||||
|
||||
[note These functions are based on [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[table `async, future/shared_future::then`and Executors
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.6.6] [Class template future] [Partial] [ - ]]
|
||||
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
|
||||
[[30.6.6] [then] [Yes] [ - ]]
|
||||
[[30.6.6] [unwrap] [Yes] [ - ]]
|
||||
[[30.6.6] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
|
||||
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
|
||||
[[30.6.7] [then] [Yes] [ - ]]
|
||||
[[30.6.7] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_all] [Partial] [ interface not complete #7447 ]]
|
||||
[[30.6.X] [Function template when_any] [Partial] [ interface not complete #7446 ]]
|
||||
[[30.6.X] [Function template when_any_swaped] [No] [ #XXXX ]]
|
||||
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
|
||||
[[30.6.8] [Function template async ] [Yes] [ - ]]
|
||||
[[30.6.6] [`future<T>::then`] [Yes] [ ]]
|
||||
[[30.6.7] [`shared_future<T>::then`] [Yes] [ ]]
|
||||
[[30.6.8] [`async`] [Yes] [ - ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -79,47 +79,54 @@
|
||||
struct uses_allocator<packaged_task <S>, Alloc>;
|
||||
|
||||
template <class F>
|
||||
future<typename result_of<typename decay<F>::type()>::type>
|
||||
async(F f);
|
||||
future<typename result_of<typename decay<F>::type()>::type>
|
||||
async(F f);
|
||||
template <class F>
|
||||
future<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F f);
|
||||
future<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F f);
|
||||
|
||||
template <class F, class... Args>
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(F&& f, Args&&... args);
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(F&& f, Args&&... args);
|
||||
template <class F, class... Args>
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
template <class Executor, class F, class... Args>
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
|
||||
template<typename Iterator>
|
||||
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
|
||||
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
|
||||
template<typename F1,typename... FS>
|
||||
void wait_for_all(F1& f1,Fs&... fs); // EXTENSION
|
||||
void wait_for_all(F1& f1,Fs&... fs); // EXTENSION
|
||||
|
||||
template<typename Iterator>
|
||||
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
|
||||
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
|
||||
template<typename F1,typename... Fs>
|
||||
unsigned wait_for_any(F1& f1,Fs&... fs); // EXTENSION
|
||||
unsigned wait_for_any(F1& f1,Fs&... fs); // EXTENSION
|
||||
|
||||
template <class InputIterator>
|
||||
future<std::vector<typename InputIterator::value_type::value_type>>
|
||||
when_all(InputIterator first, InputIterator last);
|
||||
template <typename... T>
|
||||
future<std::tuple<decay_t<T>...> when_all(T&&... futures);
|
||||
template <class InputIterator>
|
||||
future<std::vector<typename InputIterator::value_type::value_type>>
|
||||
when_any(InputIterator first, InputIterator last); // EXTENSION
|
||||
template <typename... T>
|
||||
future<std::tuple<decay_t<T>...> when_any(T&&... futures);
|
||||
|
||||
template <typename T>
|
||||
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
|
||||
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
|
||||
future<void> make_future(); // DEPRECATED
|
||||
|
||||
template <typename T>
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<void> make_ready_future(); // EXTENSION
|
||||
//template <typename T>
|
||||
//future<T> make_ready_future(exception_ptr ex); // DEPRECATED
|
||||
//template <typename T, typename E>
|
||||
//future<T> make_ready_future(E ex); // DEPRECATED
|
||||
|
||||
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
|
||||
template <typename E>
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(); // EXTENSION
|
||||
|
||||
|
||||
@@ -333,13 +340,13 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
shared_future<R> share();
|
||||
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
|
||||
see below unwrap(); // EXTENSION
|
||||
@@ -438,6 +445,7 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`other.valid()`.]
|
||||
|
||||
[[Effects:] [Constructs a new __unique_future__, and transfers ownership of the shared state associated with `other` and unwrapping the inner future (see `unwrap()`).]]
|
||||
|
||||
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
|
||||
@@ -756,6 +764,8 @@ prior to waiting.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state, `false`
|
||||
otherwise.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable and that the future could become invalid even if the function returned true or vice-versa.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
@@ -771,6 +781,8 @@ otherwise.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state and that result is ready for retrieval, `false`
|
||||
otherwise.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable and that the future could become not ready even if the function returned true or vice-versa.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
@@ -786,6 +798,8 @@ otherwise.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state, that result is ready for retrieval, and the result is a
|
||||
stored value, `false` otherwise.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable and the future could lost its value even if the function returned true or vice-versa.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
@@ -801,6 +815,8 @@ stored value, `false` otherwise.]]
|
||||
[[Returns:] [`true` if `*this` is associated with a shared state, that result is ready for retrieval, and the result is a
|
||||
stored exception, `false` otherwise.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable and the future could lost its exception even if the function returned true or vice-versa.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
@@ -818,6 +834,8 @@ entry, and the result has a ['wait callback] set, that callback is invoked prior
|
||||
|
||||
[[Returns:] [a exception_ptr, storring or not an exception.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable and the future could lost its exception even if the function returned a valid `exception_ptr` or vice-versa.]]
|
||||
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
]
|
||||
@@ -835,6 +853,8 @@ entry, and the result has a ['wait callback] set, that callback is invoked prior
|
||||
[[Returns:] [__uninitialized__ if `*this` is not associated with a shared state. __ready__ if the shared state
|
||||
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
@@ -860,13 +880,13 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
[section:then Member function `then()` - EXTENSION]
|
||||
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
|
||||
[warning These functions are experimental and subject to change in future versions.
|
||||
@@ -883,6 +903,8 @@ second parameter.]]
|
||||
|
||||
[[Effects:] [
|
||||
|
||||
All the functions create a shared state that is associated with the returned future object. The further behavior of the functions is as follows.
|
||||
|
||||
- The continuation is called when the object's shared state is ready (has a value or exception stored).
|
||||
|
||||
- The continuation launches according to the specified policy or scheduler.
|
||||
@@ -890,9 +912,11 @@ second parameter.]]
|
||||
- When the scheduler or launch policy is not provided the continuation inherits the
|
||||
parent's launch policy or scheduler.
|
||||
|
||||
- If the parent was created with `promise<<` or with a `packaged_task<>` (has no associated launch policy), the
|
||||
- Any value returned from the continuation is stored as the result in the shared state of the resulting `future`. Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting `future`.
|
||||
|
||||
- If the parent was created with `promise<>` or with a `packaged_task<>` (has no associated launch policy), the
|
||||
continuation behaves the same as the third overload with a policy argument of `launch::async | launch::deferred` and
|
||||
the same argument for func.
|
||||
the same argument for `func`.
|
||||
|
||||
- If the parent has a policy of `launch::deferred` and the continuation does not have a specified launch policy or
|
||||
scheduler, then the parent is filled by immediately calling `.wait()`, and the policy of the antecedent is
|
||||
@@ -902,11 +926,20 @@ scheduler, then the parent is filled by immediately calling `.wait()`, and the p
|
||||
|
||||
[[Returns:] [An object of type `__unique_future__<typename boost::result_of<F(__unique_future__)>` that refers to the shared state created by the continuation.]]
|
||||
|
||||
[[Notes:] [
|
||||
|
||||
- Note that nested futures are not implicitly unwrapped yet. This could be subject to change in future versions.
|
||||
|
||||
- The returned futures behave as the ones returned from boost::async, the destructor of the future object returned from then will block. This could be subject to change in future versions.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [
|
||||
|
||||
- The `__unique_future__` object passed to the parameter of the continuation function is a copy of the original `__unique_future__`.
|
||||
|
||||
- `valid() == false` on original future object immediately after it returns.
|
||||
- `valid() == false` on original future; `valid() == true` on the `future` returned from then.
|
||||
|
||||
[/ In case of implicit unwrapping, the validity of the `future` returned from `then` cannot be established until after the completion of the functor passed into `then`. In such case, the resulting `future` becomes ready with an exception of type `future_error`, with an error code of `future_errc::broken_promise`. ]
|
||||
|
||||
]]
|
||||
|
||||
@@ -928,19 +961,19 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Notes:] [Removes the outermost future and returns a future with the associated state been a proxy of inner future.]]
|
||||
[[Notes:] [Removes the outermost future and returns a future with the associated state been a proxy of the outer future.]]
|
||||
|
||||
[[Effects:] [
|
||||
|
||||
- Returns a future that becomes ready when the shared state of the inner future is ready.
|
||||
- Returns a future that becomes ready when the shared state of the outer and inner future is ready. The validity of the future returned from `get()` applied on the outer future cannot be established a priori. If it is not valid, this future is forced to be valid and becomes ready with an exception of type `future_error`, with an error code of `future_errc::broken_promise`.
|
||||
|
||||
]]
|
||||
|
||||
[[Returns:] [An object of type future with the associated state been a proxy of inner future.]]
|
||||
[[Returns:] [An object of type future with the associated state been a proxy of outer future.]]
|
||||
|
||||
[[Postconditions:] [
|
||||
|
||||
- The returned future has `valid() == true` regardless of the validity of the inner future.
|
||||
- The returned future has `valid() == true`.
|
||||
|
||||
]]
|
||||
|
||||
@@ -975,14 +1008,14 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
|
||||
// factories
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
|
||||
then(F&& func); // EXTENSION
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(F&& func) const; // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(S& scheduler, F&& func) const; // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(launch policy, F&& func) const; // EXTENSION
|
||||
|
||||
void swap(shared_future& other);
|
||||
|
||||
@@ -1324,14 +1357,14 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
[section:then Member function `then()` EXTENSION]
|
||||
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
|
||||
then(F&& func); // EXTENSION
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(F&& func) const; // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(S& scheduler, F&& func) const; // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(launch policy, F&& func) const; // EXTENSION
|
||||
|
||||
|
||||
[warning These functions are experimental and subject to change in future versions.
|
||||
@@ -1367,11 +1400,22 @@ scheduler, then the parent is filled by immediately calling `.wait()`, and the p
|
||||
|
||||
[[Returns:] [An object of type `__unique_future__<typename boost::result_of<F(shared_future)>` that refers to the shared state created by the continuation.]]
|
||||
|
||||
|
||||
[[Notes:] [
|
||||
|
||||
- Note that nested futures are not implicitly unwrapped yet. This could be subject to change in future versions.
|
||||
|
||||
- The returned futures behave as the ones returned from boost::async, the destructor of the future object returned from then will block. This could be subject to change in future versions.
|
||||
]]
|
||||
|
||||
|
||||
[[Postconditions:] [
|
||||
|
||||
- The future object is moved to the parameter of the continuation function .
|
||||
|
||||
- `valid() == false` on original future object immediately after it returns.
|
||||
- `valid() == true` on original `shared_future`; `valid() == true` on the `future` returned from then.
|
||||
|
||||
[/- In case of implicit unwrapping, the validity of the `future` returned from `then` cannot be established until after the completion of the functor passed into `then`. In such case, the resulting `future` becomes ready with an exception of type `future_error`, with an error code of `future_errc::broken_promise`. ]
|
||||
|
||||
]]
|
||||
|
||||
@@ -1927,19 +1971,17 @@ __packaged_task__.]]
|
||||
The function template async provides a mechanism to launch a function potentially in a new thread and
|
||||
provides the result of the function in a future object with which it shares a shared state.
|
||||
|
||||
[warning `async(launch::deferred, F)` is NOT YET IMPLEMENTED!]
|
||||
|
||||
[heading Non-Variadic variant]
|
||||
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(F&& f);
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(F&& f);
|
||||
template <class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F&& f);
|
||||
__unique_future__<typename result_of<typename decay<F>::type()>::type>
|
||||
async(launch policy, F&& f);
|
||||
template <class Executor, class F>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [
|
||||
@@ -1955,7 +1997,7 @@ shall be a valid expression.
|
||||
The first function behaves the same as a call to the second function with a policy argument of
|
||||
`launch::async | launch::deferred` and the same arguments for `F`.
|
||||
|
||||
The second function creates a shared state that is associated with the returned future object.
|
||||
The second and third functions create a shared state that is associated with the returned future object.
|
||||
|
||||
The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
|
||||
|
||||
@@ -1963,7 +2005,14 @@ The further behavior of the second function depends on the policy argument as fo
|
||||
|
||||
- if `policy & launch::deferred` is non-zero - Stores `decay_copy(boost::forward<F>(f))` in the shared state. This copy of `f` constitute a deferred function. Invocation of the deferred function evaluates `boost::move(g)()` where `g` is the stored value of `decay_copy(boost::forward<F>(f))`. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of `boost::move(g)()` begins, the function is no longer considered deferred. (Note: If this policy is specified together with other policies, such as when using a policy value of `launch::async | launch::deferred`, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.)
|
||||
|
||||
- if no valid launch policy is provided the behaviour is undefined.
|
||||
- if no valid launch policy is provided the behavior is undefined.
|
||||
|
||||
|
||||
The further behavior of the third function is as follows:
|
||||
|
||||
- The Executor::submit() function is given a function<void ()> which calls `INVOKE (DECAY_COPY
|
||||
(std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...). The implementation of the executor
|
||||
is decided by the programmer.
|
||||
|
||||
]]
|
||||
|
||||
@@ -1991,22 +2040,22 @@ If the implementation chooses the `launch::async` policy,
|
||||
|
||||
]]
|
||||
|
||||
[[Remarks:] [The first signature shall not participate in overload resolution if decay<F>::type is boost::launch.
|
||||
]]
|
||||
[[Remarks::] [The first signature shall not participate in overload resolution if `decay_t<F> is `boost::
|
||||
launch` or `boost::is_executor<F>` is `true_type`.]]
|
||||
|
||||
]
|
||||
|
||||
[heading Variadic variant]
|
||||
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(F&& f, Args&&... args);
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(F&& f, Args&&... args);
|
||||
template <class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(launch policy, F&& f, Args&&... args);
|
||||
template <class Executor, class F, class... Args>
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
|
||||
async(Executor &ex, F&& f, Args&&... args);
|
||||
|
||||
[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple> (waiting for a boost::tuple that is move aware), and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.]
|
||||
|
||||
@@ -2087,19 +2136,19 @@ with the return from the last function that releases the shared state, whichever
|
||||
[section:wait_for_any Non-member function `wait_for_any()` - EXTENSION]
|
||||
|
||||
template<typename Iterator>
|
||||
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
|
||||
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2>
|
||||
unsigned wait_for_any(F1& f1,F2& f2); // EXTENSION
|
||||
unsigned wait_for_any(F1& f1,F2& f2); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2,typename F3>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3); // EXTENSION
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4,typename F5>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -2127,19 +2176,19 @@ with any of the futures being waited for. `std::bad_alloc` if memory could not
|
||||
[section:wait_for_all Non-member function `wait_for_all()` - EXTENSION]
|
||||
|
||||
template<typename Iterator>
|
||||
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
|
||||
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2>
|
||||
void wait_for_all(F1& f1,F2& f2); // EXTENSION
|
||||
void wait_for_all(F1& f1,F2& f2); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2,typename F3>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3); // EXTENSION
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4,typename F5>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -2158,16 +2207,167 @@ __unique_future__ or __shared_future__.]]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////////////////////////////////////]
|
||||
[section:when_all Non-member function `when_all()` - EXTENSION]
|
||||
|
||||
|
||||
template <class InputIterator>
|
||||
future<std::vector<typename InputIterator::value_type::value_type>>
|
||||
when_all(InputIterator first, InputIterator last);
|
||||
|
||||
template <typename... FutTypes>
|
||||
future<std::tuple<decay_t<FutTypes>...> when_all(FutTypes&&... futures);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [
|
||||
|
||||
- For the first overload, `InputIterator`'s value type shall be convertible to `future<R>` or `shared_future<R>`.
|
||||
All `R` types must be the same. If any of the `future<R>` or `shared_future<R>` objects are in invalid state (i.e. `valid() == false`), the behavior is undefined.
|
||||
- For the second overload, `FutTypes` is of type `future<R>` or `shared_future<R>`. The effect of calling `when_all` on a `future` or a `shared_future` object for which `valid() == false` is undefined.
|
||||
|
||||
]]
|
||||
|
||||
[[Notes:] [
|
||||
|
||||
- There are two variations of `when_all`. The first version takes a pair of `InputIterators`. The second takes any arbitrary number of `future<R0>` and `shared_future<R1>` objects, where `R0` and `R1` need not be the same type.
|
||||
|
||||
- Calling the first signature of `when_all` where `InputIterator` first equals last, returns a future with an empty `vector` that is immediately ready.
|
||||
|
||||
- Calling the second signature of `when_all` with no arguments returns a future<tuple<>> that is immediately ready.
|
||||
|
||||
]]
|
||||
|
||||
[[Effects:] [
|
||||
|
||||
- If any of the futures supplied to a call to `when_all` refer to deferred tasks that have not started execution, those tasks are executed before the call to `when_all` returns. Once all such tasks have been executed, the call to `when_all` returns immediately.
|
||||
|
||||
- The call to `when_all` does not wait for non-deferred tasks, or deferred tasks that have already started executing elsewhere, to complete before returning.
|
||||
|
||||
- Once all the `future`s/`shared_future`s supplied to the call to `when_all` are ready, the `future`s/`shared_future`s are moved/copied into the associated state of the future returned from the call to `when_all`, preserving the order of the futures supplied to `when_all`.
|
||||
|
||||
- The collection is then stored as the result in a newly created shared state.
|
||||
|
||||
- A new future object that refers to the shared state is created. The exact type of the future is further described below.
|
||||
|
||||
- The `future` returned by `when_all` will not throw an exception when calling `wait()` or `get()`, but the futures held in the output collection may.
|
||||
]]
|
||||
|
||||
[[Returns:] [
|
||||
|
||||
- `future<tuple<>>` if `when_all` is called with zero arguments.
|
||||
|
||||
- `future<vector<future<R>>>` if the input cardinality is unknown at compile and the iterator pair yields `future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
|
||||
|
||||
- `future<vector<shared_future<R>>>` if the input cardinality is unknown at compile time and the iterator pair yields `shared_future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
|
||||
|
||||
- `future<tuple<decay_t<FutTypes>...>>` if inputs are fixed in number.
|
||||
|
||||
]]
|
||||
|
||||
[[Postconditions:] [
|
||||
|
||||
- All input futures valid() == false.
|
||||
|
||||
- All input shared future valid() == true.
|
||||
|
||||
- valid() == true.
|
||||
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////////////////////////////////////]
|
||||
[section:when_any Non-member function `when_any()` - EXTENSION]
|
||||
|
||||
|
||||
template <class InputIterator>
|
||||
future<std::vector<typename InputIterator::value_type::value_type>>
|
||||
when_any(InputIterator first, InputIterator last);
|
||||
|
||||
template <typename... FutTypes>
|
||||
future<std::tuple<decay_t<FutTypes>...>
|
||||
when_any(FutTypes&&... futures);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [
|
||||
|
||||
|
||||
|
||||
- For the first overload, `InputIterator`'s value type shall be convertible to `future<R>` or `shared_future<R>`. All `R` types must be the same. If any of the `future<R>` or `shared_future<R>` objects are in invalid state (i.e. `valid() == false`), the behavior is undefined.
|
||||
- For the second overload, `FutTypes` is of type `future<R>` or `shared_future<R>`. The effect of calling `when_any` on a `future` or a `shared_future` object for which `valid() == false is undefined`.
|
||||
|
||||
]]
|
||||
|
||||
[[Notes:] [
|
||||
|
||||
- There are two variations of `when_any `. The first version takes a pair of `InputIterators`. The second takes any arbitrary number of `future<R0>` and `shared_future<R1>` objects, where `R0` and `R1` need not be the same type.
|
||||
|
||||
- Calling the first signature of `when_any ` where `InputIterator` first equals last, returns a future with an empty `vector` that is immediately ready.
|
||||
|
||||
- Calling the second signature of `when_any` with no arguments returns a future<tuple<>> that is immediately ready.
|
||||
|
||||
]]
|
||||
|
||||
[[Effects:] [
|
||||
|
||||
- Each of the futures supplied to `when_any` is checked in the order supplied. If a given future is ready, then no further futures are checked, and the call to `when_any` returns immediately. If a given future refers to a deferred task that has not yet started execution, then no further futures are checked, that task is executed, and the call to `when_any` then returns immediately.
|
||||
|
||||
- The call to `when_any` does not wait for non-deferred tasks, or deferred tasks that have already started executing elsewhere, to complete before returning.
|
||||
|
||||
- Once at least one of the futures supplied to the call to `when_any` are ready, the futures are moved into the associated state of the future returned from the call to `when_any`, preserving the order of the futures supplied to `when_any`. That future is then ready.
|
||||
|
||||
- The collection is then stored as the result in a newly created shared state.
|
||||
|
||||
- A new future object that refers to the shared state is created. The exact type of the future is further described below.
|
||||
|
||||
- The future returned by `when_any` will not throw an exception when calling `wait()` or `get()`, but the futures held in the output collection may.
|
||||
|
||||
]]
|
||||
|
||||
[[Returns:] [
|
||||
|
||||
- `future<tuple<>>` if `when_any ` is called with zero arguments.
|
||||
|
||||
- `future<vector<future<R>>>` if the input cardinality is unknown at compile and the iterator pair yields `future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
|
||||
|
||||
- `future<vector<shared_future<R>>>` if the input cardinality is unknown at compile time and the iterator pair yields `shared_future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
|
||||
|
||||
- `future<tuple<decat_t<FutTypes>...>>` if inputs are fixed in number.
|
||||
|
||||
]]
|
||||
|
||||
[[Postconditions:] [
|
||||
|
||||
- All input futures valid() == false.
|
||||
|
||||
- All input shared_futures valid() == true.
|
||||
|
||||
- valid() == true.
|
||||
|
||||
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[/////////////////////////////////////////////////////////////////////////////]
|
||||
[section:make_ready_future Non-member function `make_ready_future()` EXTENSION]
|
||||
|
||||
template <typename T>
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<void> make_ready_future(); // EXTENSION
|
||||
template <typename T>
|
||||
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
|
||||
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
|
||||
template <typename T, typename E>
|
||||
future<T> make_ready_future(E ex); // DEPRECATED
|
||||
future<T> make_ready_future(E ex); // DEPRECATED
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -2207,7 +2407,7 @@ Otherwise the value is copied to the shared state of the returned function.
|
||||
|
||||
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
|
||||
template <typename E>
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(); // EXTENSION
|
||||
|
||||
[variablelist
|
||||
@@ -2228,7 +2428,7 @@ An exceptional_ptr instance implicitly convertible to a future<T>
|
||||
[section:make_future Non-member function `make_future()` DEPRECATED]
|
||||
|
||||
template <typename T>
|
||||
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
|
||||
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
|
||||
future<void> make_future(); // DEPRECATED
|
||||
|
||||
|
||||
@@ -2264,7 +2464,7 @@ Otherwise the value is copied to the shared state of the returned function.
|
||||
[section:make_shared_future Non-member function `make_shared_future()` DEPRECATED]
|
||||
|
||||
template <typename T>
|
||||
shared_future<typename decay<T>::type> make_shared_future(T&& value); // DEPRECATED
|
||||
shared_future<typename decay<T>::type> make_shared_future(T&& value); // DEPRECATED
|
||||
shared_future<void> make_shared_future(); // DEPRECATED
|
||||
|
||||
[variablelist
|
||||
|
||||
482
doc/parallel.qbk
Normal file
482
doc/parallel.qbk
Normal file
@@ -0,0 +1,482 @@
|
||||
[/
|
||||
/ Copyright (c) 2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:parallel Parallel - Fork-Join -- EXPERIMENTAL]
|
||||
|
||||
[section:fork_join Fork-Join]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4088.pdf [* n4088 - Task Region R3]] C++1y proposal from P. Halpern, A. Robison, A. Laksberg, H. Sutter, et al. The text that follows has been adapted from this paper to show the differences.]
|
||||
|
||||
The major difference respect to the standard proposal is that we are able to use a common executor for several task regions.
|
||||
|
||||
[note
|
||||
Up to now, Boost.Thread doesn't implement the parallel algorithms as defined in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4105.pdf [* n4105 - Information technology – Programming languages, their environments and system software interfaces – Technical Specification for C++ Extensions for Parallelism]].
|
||||
]
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
|
||||
This module introduces a C++11/c++14 library function template `task_region` and a library class `task_region_handle`
|
||||
with member functions `run` and `wait` that together enable developers to write expressive and portable fork-join
|
||||
parallel code.
|
||||
|
||||
The working draft for the Parallelism TS [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4105.pdf [*N4105]] augments the STL algorithms with the inclusion of parallel execution policies. Programmers use these as a basis to write additional high-level algorithms that can be implemented in terms of the provided parallel algorithms. However, the scope of n4105 does not include lower-level mechanisms to express arbitrary fork-join parallelism
|
||||
|
||||
The `task_region`, `run` and the `wait` functions provided by this library are based on the `task_group` concept that is a part of the common subset of the PPL and the TBB libraries.
|
||||
|
||||
[endsect] [/ Introduction]
|
||||
|
||||
|
||||
[/////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Consider an example of a parallel traversal of a tree, where a user-provided function compute is applied to each node of the tree, returning the sum of the results:
|
||||
|
||||
template<typename Func>
|
||||
int traverse(node *n, Func&& compute)
|
||||
{
|
||||
int left = 0, right = 0;
|
||||
task_region([&](task_region_handle& tr) {
|
||||
if (n->left)
|
||||
tr.run([&] { left = traverse(n->left, compute); });
|
||||
if (n->right)
|
||||
tr.run([&] { right = traverse(n->right, compute); });
|
||||
});
|
||||
return compute(n) + left + right;
|
||||
}
|
||||
|
||||
The example above demonstrates the use of two of the functions proposed in this paper, `task_region` and
|
||||
`task_region_handle::run`.
|
||||
The `task_region` function delineates a region in a program code potentially containing invocations of tasks
|
||||
spawned by the `run` member function of the `task_region_handle` class.
|
||||
|
||||
The run function spawns a task, a unit of work that is allowed to execute in parallel with respect to the caller.
|
||||
Any parallel tasks spawned by `run` within the `task_region` are joined back to a single thread of execution at
|
||||
the end of the `task_region`.
|
||||
|
||||
`run` takes a user-provided function object `f` and starts it asynchronously - i.e. it may return before the
|
||||
execution of `f` completes. The implementation's scheduler may choose to run `f` immediately or delay running
|
||||
`f` until compute resources become available.
|
||||
|
||||
A `task_region_handle` can be constructed only by `task_region` because it has no public constructors.
|
||||
Thus, `run` can be invoked (directly or indirectly) only from a user-provided function passed to `task_region`:
|
||||
|
||||
void g();
|
||||
void f(task_region_handle& tr)
|
||||
{
|
||||
tr.run(g); // OK, invoked from within task_region in h
|
||||
}
|
||||
void h()
|
||||
{
|
||||
task_region(f);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
task_region_handle tr; // Error: no public constructor
|
||||
tr.run(g); // No way to call run outside of a task_region
|
||||
return 0;
|
||||
}
|
||||
|
||||
[endsect] [/ Tutorial]
|
||||
|
||||
[////////////////]
|
||||
[section:examples Examples]
|
||||
|
||||
[section:fib Parallel Fibonacci]
|
||||
|
||||
|
||||
This is surely the worst implementation of the Fibonacci function. Anyway, here it is, as it is simple and shows the fork-join structure clearly. `Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)`, so the task decomposition is trivial.
|
||||
|
||||
int fib_task_region(int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region(i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
[endsect] [/ Fib]
|
||||
[section:fibex Parallel Fibonacci - Specific executor]
|
||||
|
||||
The previous example make use of an implementation defined way to spawn the tasks. Often the user wants to master how the task must be spawned. There is an overload of `task_region` that accept an additional `Executor` parameter and a function that takes as parameter a `task_region_handle_gen<Executor>`. `task_region_handle_gen<Executor>` run uses this executor to spawn the tasks.
|
||||
|
||||
template <class Ex>
|
||||
int fib_task_region_gen( Ex& ex, int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle_gen;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region(ex, [&](task_region_handle_gen<Ex>& trh) // (2)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::basic_thread_pool tp; // (1)
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region_gen(tp,i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
The specific executor is declared in line (1) and it is used in line (2).
|
||||
|
||||
[endsect] [/ Fib ex]
|
||||
|
||||
|
||||
|
||||
|
||||
[section:quick_sort Parallel Accumulate]
|
||||
|
||||
|
||||
[endsect] [/ Accumulate]
|
||||
|
||||
[section:quick_sort Parallel Quick Sort]
|
||||
|
||||
|
||||
|
||||
[endsect] [/ QuickSort]
|
||||
[endsect] [/ Examples]
|
||||
|
||||
|
||||
[////////////////////////]
|
||||
[section:rationale Design Rationale]
|
||||
|
||||
|
||||
[endsect] [/ Design Rationale]
|
||||
[endsect] [/ Fork-Join]
|
||||
|
||||
[/////////////////////]
|
||||
[section:ref Reference -- EXPERIMENTAL]
|
||||
|
||||
[/////////////////////////]
|
||||
[section:v1 Parallel V1]
|
||||
|
||||
[section:exception_list Header `<experimental/exception_list.hpp>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
|
||||
class exception_list;
|
||||
|
||||
} // v1
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[/////////////////////////]
|
||||
[section:exception_list Class `exception_list`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
|
||||
class exception_list: public std::exception
|
||||
{
|
||||
public:
|
||||
typedef 'implementation defined' const_iterator;
|
||||
|
||||
~exception_list() noexcept {}
|
||||
|
||||
void add(exception_ptr const& e);
|
||||
size_t size() const noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const char* what() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // v1
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[endsect] [/ exception_list]
|
||||
|
||||
[endsect] [/ exception_list.hpp]
|
||||
|
||||
[endsect] [/ Parallel V1]
|
||||
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:v2 Parallel V2]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:concepts Concepts]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:regionCallable Concept `Region_Callable`]
|
||||
|
||||
[endsect] [/ Region_Callable]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:taskCallable Concept `Task_Callable`]
|
||||
|
||||
|
||||
[endsect] [/ Task_Callable]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[endsect] [/ Concepts]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region Header `<experimental/task_region.hpp>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_canceled_exception;
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen;
|
||||
|
||||
using default_executor = 'implementation defined';
|
||||
|
||||
class task_region_handle;
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region_final(F&& f);
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_canceled_exception Class `task_canceled_exception `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_canceled_exception: public std::exception
|
||||
{
|
||||
public:
|
||||
task_canceled_exception() noexcept;
|
||||
task_canceled_exception(const task_canceled_exception&) noexcept;
|
||||
task_canceled_exception& operator=(const task_canceled_exception&) noexcept;
|
||||
virtual const char* what() const noexcept;
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_canceled_exception]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_handle_gen Template Class `task_region_handle_gen<>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen
|
||||
{
|
||||
protected:
|
||||
task_region_handle_gen(Executor& ex);
|
||||
|
||||
~task_region_handle_gen();
|
||||
|
||||
public:
|
||||
task_region_handle_gen(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen& operator=(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen* operator&() const = delete;
|
||||
|
||||
template<typename F>
|
||||
void run(F&& f);
|
||||
|
||||
void wait();
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_handle_gen]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:default_executor Class `default_executor `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
using default_executor = 'implementation defined';
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ default_executor]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_handle Class `task_region_handle `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_region_handle :
|
||||
public task_region_handle_gen<default_executor>
|
||||
{
|
||||
protected:
|
||||
task_region_handle();
|
||||
task_region_handle(const task_region_handle&) = delete;
|
||||
task_region_handle& operator=(const task_region_handle&) = delete;
|
||||
task_region_handle* operator&() const = delete;
|
||||
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_handle]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_final Template Function `task_region_final `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region_final(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_final]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region Template Function `task_region `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region]
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect] [/ task_region.hpp]
|
||||
[endsect] [/ Parallel V2]
|
||||
[endsect] [/ Reference]
|
||||
|
||||
[endsect] [/ Parallel]
|
||||
@@ -229,12 +229,12 @@ where
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:non_waaiting Non-waiting Concurrent Queue Operations]
|
||||
[section:non_waiting Non-waiting Concurrent Queue Operations]
|
||||
|
||||
The ConcurrentQueue concept models a queue with .
|
||||
The ConcurrentQueue concept models a queue with Non-waiting operations.
|
||||
|
||||
|
||||
A type `Q` meets the ConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
|
||||
A type `Q` meets the ConcurrentQueue requirements if is a model of a BasicConcurrentQueue and the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `s = q.try_push_back(e);`
|
||||
* `s = q.try_push_back(rve);`
|
||||
@@ -281,7 +281,7 @@ where
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_push_back_m `s = q.try_push_back(rve());`]
|
||||
[section:try_push_back_m `s = q.try_push_back(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -345,7 +345,7 @@ For cases when blocking for mutual exclusion is undesirable, we have non-blockin
|
||||
The interface is the same as the try operations but is allowed to also return queue_op_status::busy
|
||||
in case the operation is unable to complete without blocking.
|
||||
|
||||
Non-blocking operations are provided only for BlockingQueues
|
||||
Non-blocking operations are provided only for lock based queues
|
||||
|
||||
* `s = q.nonblocking_push_back(nb, e);`
|
||||
* `s = q.nonblocking_push_back(nb, rve);`
|
||||
@@ -616,6 +616,226 @@ Closed queues add the following valid expressions
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:queue_op_status Queue Operation Status]
|
||||
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
enum class queue_op_status { success = 0, empty, full, closed, busy }
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:queue_base Queue Base]
|
||||
|
||||
#include <boost/thread/concurrent_queues/queue_base.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
class queue_base
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:queue_adaptor Queue Adaptor]
|
||||
|
||||
#include <boost/thread/concurrent_queues/queue_adaptor.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename Queue>
|
||||
class queue_adaptor : public queue_base<typename Queue::value_type>
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
queue_adaptor();
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void close();
|
||||
|
||||
void push_back(const value_type& x);
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
void pull_front(value_type& x);
|
||||
value_type pull_front();
|
||||
|
||||
queue_op_status try_push_back(const value_type& x);
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status try_pull_front(value_type& x);
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x);
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status nonblocking_pull_front(value_type& x);
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x);
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status wait_pull_front(value_type& x);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:queue_views Queue Views]
|
||||
|
||||
#include <boost/thread/concurrent_queues/queue_views.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename Queue>
|
||||
class queue_back_view;
|
||||
template <typename Queue>
|
||||
class queue_front_view
|
||||
|
||||
template <class T>
|
||||
using queue_back = queue_back_view<queue_base<T>>;
|
||||
template <class T>
|
||||
using queue_front = queue_front_view<queue_base<T>>;
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:queue_back_view Class template `queue_back_view<>`]
|
||||
|
||||
template <typename Queue>
|
||||
class queue_back_view
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_back_view(Queue& q) noexcept;
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void close();
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
void pull(value_type& x);
|
||||
value_type pull();
|
||||
|
||||
queue_op_status try_push(const value_type& x);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status try_pull(value_type& x);
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x);
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x);
|
||||
|
||||
queue_op_status wait_push(const value_type& x);
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status wait_pull_front(value_type& x);
|
||||
|
||||
};
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:queue_front_view Class template `queue_front_view<>`]
|
||||
|
||||
|
||||
template <typename Queue>
|
||||
class queue_front_view
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_front_view(Queue& q) BOOST_NOEXCEPT;
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void close();
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
void pull(value_type& x);
|
||||
value_type pull();
|
||||
|
||||
queue_op_status try_push(const value_type& x);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status try_pull(value_type& x);
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x);
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x);
|
||||
|
||||
queue_op_status wait_push(const value_type& x);
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status wait_pull(value_type& x);
|
||||
|
||||
};
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_bounded_queue_ref Synchronized Bounded Queue]
|
||||
@@ -830,7 +1050,7 @@ Closed queues add the following valid expressions
|
||||
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `sync_bounded_queue(size_type)`]
|
||||
[section:constructor Constructor `sync_queue(size_type)`]
|
||||
|
||||
explicit sync_queue();
|
||||
|
||||
@@ -843,21 +1063,6 @@ Closed queues add the following valid expressions
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructort Template Constructor `sync_bounded_queue(size_type, Range)`]
|
||||
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an sync_queue with all the elements of the range. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:full Member Function `full()`]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 4.3.0]
|
||||
[version 4.4.0]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-14 Vicente J. Botet Escriba]
|
||||
@@ -244,7 +244,6 @@
|
||||
[include futures.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
[include tss.qbk]
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
@@ -253,6 +252,8 @@
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
[include parallel.qbk]
|
||||
|
||||
[include time.qbk]
|
||||
|
||||
[include emulations.qbk]
|
||||
|
||||
@@ -26,7 +26,13 @@
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
namespace no_interruption_point // EXTENSION
|
||||
{
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
}
|
||||
template<typename Callable>
|
||||
void at_thread_exit(Callable func); // EXTENSION
|
||||
|
||||
@@ -752,7 +758,7 @@ corresponding successful `join()` return. ]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or `this->get_id() == boost::this_thread::get_id()`.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED` is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED` is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -801,7 +807,7 @@ unchanged.]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -841,7 +847,7 @@ unchanged.]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -881,7 +887,7 @@ unchanged.]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -917,7 +923,7 @@ unchanged.]]
|
||||
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
]]
|
||||
|
||||
@@ -1489,6 +1495,11 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
{
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
namespace no_interruption_point
|
||||
{
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
}
|
||||
}
|
||||
|
||||
[variablelist
|
||||
@@ -1500,6 +1511,7 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted. ]]
|
||||
|
||||
[[Notes:] [`sleep_until()` is one of the predefined __interruption_points__.]]
|
||||
[[Notes:] [`no_interruption_point::sleep_until()` is NOT one of the __interruption_points__.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1513,6 +1525,11 @@ do not throw exceptions. __thread_interrupted__ if the current thread of executi
|
||||
{
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
namespace no_interruption_point
|
||||
{
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
}
|
||||
}
|
||||
|
||||
[variablelist
|
||||
@@ -1523,6 +1540,7 @@ by `rel_time` has elapsed.]]
|
||||
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted.]]
|
||||
|
||||
[[Notes:] [`sleep_for()` is one of the predefined __interruption_points__.]]
|
||||
[[Notes:] [`no_interruption_point:: sleep_for()` is NOT one of the __interruption_points__.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
@@ -67,12 +64,13 @@ void submit_some(boost::executor& tp)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void at_th_entry(boost::basic_thread_pool& )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
int test_executor_adaptor()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
@@ -144,3 +142,9 @@ int main()
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
return test_executor_adaptor();
|
||||
}
|
||||
|
||||
91
example/fib_task_region.cpp
Normal file
91
example/fib_task_region.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#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
|
||||
|
||||
#include <boost/thread/experimental/task_region.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR && ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
|
||||
int fib_task_region(int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
template <class Ex>
|
||||
int fib_task_region_gen( Ex& ex, int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle_gen;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region(ex, [&](task_region_handle_gen<Ex>& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region(i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
boost::basic_thread_pool tp;
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region_gen(tp,i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -4,9 +4,6 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
//&& ! defined BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
@@ -48,6 +44,7 @@ int p2(boost::future<int> f)
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
int p2s(boost::shared_future<int> f)
|
||||
{
|
||||
@@ -68,6 +65,7 @@ int p2s(boost::shared_future<int> f)
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2S>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
@@ -5,16 +5,13 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
@@ -93,16 +90,80 @@ int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<std::tuple<> > all0 = boost::when_all();
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::tuple<> > all0 = boost::when_all();
|
||||
BOOST_THREAD_LOG
|
||||
<< BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_all(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_all(boost::move(f1));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::make_ready_future(1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_all(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<std::string> f2 = boost::make_ready_future(std::string("nnnnnnn"));;
|
||||
boost::future<boost::csbl::tuple<boost::future<int>, boost::future<std::string> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::tuple<boost::future<int>, boost::future<std::string> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::vector<boost::future<int> > v;
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1b));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_all(v.begin(), v.end());
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
@@ -120,16 +181,113 @@ int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<std::tuple<> > all0 = boost::when_any();
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::tuple<> > all0 = boost::when_any();
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_any(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_any(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::make_ready_future(1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<std::string> f1 = boost::make_ready_future(std::string("aaaa"));
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<std::string>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<std::string>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = boost::make_ready_future(1);
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::deferred, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::vector<boost::future<int> > v;
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1b));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_any(v.begin(), v.end());
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
@@ -155,7 +313,6 @@ using namespace boost;
|
||||
void f( boost::csbl::vector<future<int> > &//vec
|
||||
, BOOST_THREAD_RV_REF(future<int>) //f
|
||||
) {
|
||||
//vec.push_back(boost::forward<future<int> >(f));
|
||||
}
|
||||
int main()
|
||||
{
|
||||
|
||||
153
example/generic_executor_ref.cpp
Normal file
153
example/generic_executor_ref.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
// 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/serial_executor.hpp>
|
||||
#include <boost/thread/executors/inline_executor.hpp>
|
||||
#include <boost/thread/executors/thread_executor.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
#include <boost/thread/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <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_ref 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_ref()
|
||||
{
|
||||
// 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::serial_executor ea2(ea1);
|
||||
submit_some(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_ref();
|
||||
|
||||
|
||||
}
|
||||
@@ -8,9 +8,6 @@
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
//#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
// 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>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
//#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
//#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
//#endif
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#ifdef XXXX
|
||||
@@ -87,25 +91,24 @@ void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
// try {
|
||||
// for(int i=0; ;++i)
|
||||
// {
|
||||
// int r;
|
||||
// queue_op_status res = sbq.wait_and_pull(r);
|
||||
// if (res==queue_op_status::closed) break;
|
||||
// mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// this_thread::sleep_for(chrono::milliseconds(250));
|
||||
// }
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// mos << "exception !!!\n";
|
||||
// }
|
||||
//}
|
||||
void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status res = sbq.wait_pull_front(r);
|
||||
if (res==queue_op_status::closed) break;
|
||||
mos << i << " wait_pull_front(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
150
example/producer_consumer2.cpp
Normal file
150
example/producer_consumer2.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// (C) Copyright 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)
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#ifdef XXXX
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
typedef boost::externally_locked_stream<std::ostream> the_ostream;
|
||||
#else
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_adaptor.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_views.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
void producer(the_ostream &mos, boost::queue_back<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
sbq.push(i);
|
||||
//sbq << i;
|
||||
mos << "push(" << i << ") " << sbq.size() <<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(
|
||||
the_ostream &mos,
|
||||
boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r);
|
||||
//sbq >> r;
|
||||
mos << i << " pull(" << r << ") " << sbq.size() <<"\n";
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status st = sbq.try_pull(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
mos << i << " try_pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer3(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status res = sbq.wait_pull(r);
|
||||
if (res==queue_op_status::closed) break;
|
||||
mos << i << " wait_pull(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#ifdef XXXX
|
||||
recursive_mutex terminal_mutex;
|
||||
|
||||
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
#else
|
||||
the_ostream &mcerr = std::cout;
|
||||
the_ostream &mcout = std::cerr;
|
||||
//the_istream &mcin = std::cin;
|
||||
#endif
|
||||
|
||||
queue_adaptor<sync_queue<int> > sbq;
|
||||
|
||||
{
|
||||
mcout << "begin of main" << std::endl;
|
||||
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), concurrent::queue_back<int>(sbq)));
|
||||
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), concurrent::queue_back<int>(sbq)));
|
||||
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), concurrent::queue_front<int>(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
mcout << "closed()" << std::endl;
|
||||
sbq.close();
|
||||
mcout << "closed()" << std::endl;
|
||||
|
||||
} // all threads joined here.
|
||||
mcout << "end of main" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
//#define XXXX
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
// 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>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
|
||||
@@ -3,13 +3,18 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/loop_executor.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <string>
|
||||
|
||||
void p1()
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE(default_barrier_reseter)
|
||||
//BOOST_THREAD_COPYABLE_AND_MOVABLE(default_barrier_reseter)
|
||||
|
||||
default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_)
|
||||
@@ -71,6 +72,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_THREAD_MOVABLE(void_functor_barrier_reseter)
|
||||
//BOOST_THREAD_COPYABLE_AND_MOVABLE(void_functor_barrier_reseter)
|
||||
|
||||
void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_), fct_(other.fct_)
|
||||
@@ -78,6 +80,7 @@ namespace boost
|
||||
}
|
||||
void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
|
||||
//size_(BOOST_THREAD_RV(other).size_), fct_(boost::move(BOOST_THREAD_RV(other).fct_))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -96,6 +99,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter)
|
||||
//BOOST_THREAD_COPYABLE_AND_MOVABLE(void_fct_ptr_barrier_reseter)
|
||||
|
||||
void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_), fct_(other.fct_)
|
||||
@@ -112,6 +116,10 @@ namespace boost
|
||||
}
|
||||
};
|
||||
}
|
||||
//BOOST_THREAD_DCL_MOVABLE(thread_detail::default_barrier_reseter)
|
||||
//BOOST_THREAD_DCL_MOVABLE(thread_detail::void_functor_barrier_reseter)
|
||||
//BOOST_THREAD_DCL_MOVABLE(thread_detail::void_fct_ptr_barrier_reseter)
|
||||
|
||||
class barrier
|
||||
{
|
||||
static inline unsigned int check_counter(unsigned int count)
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
class sync_queue_base
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef Queue underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef queue_op_status op_status;
|
||||
|
||||
typedef typename chrono::steady_clock clock;
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue_base)
|
||||
inline sync_queue_base();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue_base();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
inline underlying_queue_type underlying_queue() {
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return boost::move(data_);
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
underlying_queue_type data_;
|
||||
bool closed_;
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
inline bool closed(unique_lock<mutex>& lk) const;
|
||||
inline bool closed(lock_guard<mutex>& lk) const;
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline void throw_if_closed(lock_guard<mutex>&);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&);
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
inline void notify_not_empty_if_needed(lock_guard<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_queue_base<ValueType, Queue>::sync_queue_base() :
|
||||
data_(), closed_(false)
|
||||
{
|
||||
BOOST_ASSERT(data_.empty());
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_queue_base<ValueType, Queue>::~sync_queue_base()
|
||||
{
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed(unique_lock<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed(lock_guard<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::full() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
typename sync_queue_base<ValueType, Queue>::size_type sync_queue_base<ValueType, Queue>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::throw_if_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::throw_if_closed(lock_guard<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
throw_if_closed(lk);
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
if (closed(lk)) return true;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&tp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) return queue_op_status::success;
|
||||
throw_if_closed(lk);
|
||||
if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // detail
|
||||
} // concurrent
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
209
include/boost/thread/concurrent_queues/queue_adaptor.hpp
Normal file
209
include/boost/thread/concurrent_queues/queue_adaptor.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_QUEUE_ADAPTOR_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_base.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor_copyable_only :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_adaptor_copyable_only() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
};
|
||||
template <typename Queue>
|
||||
class queue_adaptor_movable_only :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
queue_adaptor_movable_only() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor_copyable_and_movable :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
queue_adaptor_copyable_and_movable() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
|
||||
template <class Q, class T,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // __GNUC__
|
||||
#elif defined _MSC_VER
|
||||
#if _MSC_VER < 1700
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif
|
||||
#else
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = has_move_emulation_enabled<T>::value
|
||||
#endif
|
||||
>
|
||||
struct queue_adaptor;
|
||||
|
||||
template <class Q, class T>
|
||||
struct queue_adaptor<Q, T, true, true> {
|
||||
typedef queue_adaptor_copyable_and_movable<Q> type;
|
||||
};
|
||||
template <class Q, class T>
|
||||
struct queue_adaptor<Q, T, true, false> {
|
||||
typedef queue_adaptor_copyable_only<Q> type;
|
||||
};
|
||||
template <class Q, class T>
|
||||
struct queue_adaptor<Q, T, false, true> {
|
||||
typedef queue_adaptor_movable_only<Q> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor :
|
||||
public detail::queue_adaptor<Queue, typename Queue::value_type>::type
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_adaptor() {};
|
||||
};
|
||||
}
|
||||
using concurrent::queue_adaptor;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
202
include/boost/thread/concurrent_queues/queue_base.hpp
Executable file
202
include/boost/thread/concurrent_queues/queue_base.hpp
Executable file
@@ -0,0 +1,202 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_BASE_HPP
|
||||
#define BOOST_THREAD_QUEUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/is_copy_constructible.hpp>
|
||||
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base_copyable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_copyable_only() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base_movable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_movable_only() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base_copyable_and_movable
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_copyable_and_movable() {};
|
||||
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
template <class T,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // __GNUC__
|
||||
#elif defined _MSC_VER
|
||||
#if _MSC_VER < 1700
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif
|
||||
#else
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = has_move_emulation_enabled<T>::value
|
||||
#endif
|
||||
>
|
||||
struct queue_base;
|
||||
|
||||
template <class T>
|
||||
struct queue_base<T, true, true> {
|
||||
typedef queue_base_copyable_and_movable<T> type;
|
||||
};
|
||||
template <class T>
|
||||
struct queue_base<T, true, false> {
|
||||
typedef queue_base_copyable_only<T> type;
|
||||
};
|
||||
template <class T>
|
||||
struct queue_base<T, false, true> {
|
||||
typedef queue_base_movable_only<T> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base :
|
||||
public detail::queue_base<ValueType>::type
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base() {};
|
||||
};
|
||||
|
||||
}
|
||||
using concurrent::queue_base;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
46
include/boost/thread/concurrent_queues/queue_op_status.hpp
Normal file
46
include/boost/thread/concurrent_queues/queue_op_status.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_OP_STATUS_HPP
|
||||
#define BOOST_THREAD_QUEUE_OP_STATUS_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
|
||||
{ success = 0, empty, full, closed, busy, timeout, not_ready }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
struct sync_queue_is_closed : std::exception
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
#endif
|
||||
|
||||
using concurrent::queue_op_status;
|
||||
using concurrent::sync_queue_is_closed;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
165
include/boost/thread/concurrent_queues/queue_views.hpp
Normal file
165
include/boost/thread/concurrent_queues/queue_views.hpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_VIEWS_HPP
|
||||
#define BOOST_THREAD_QUEUE_VIEWS_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_base.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
|
||||
template <typename Queue>
|
||||
class queue_back_view
|
||||
{
|
||||
Queue* queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_back_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue->empty(); }
|
||||
bool full() const { return queue->full(); }
|
||||
size_type size() const { return queue->size(); }
|
||||
bool closed() const { return queue->closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_back(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_back(x); }
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_back(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); }
|
||||
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class queue_front_view
|
||||
{
|
||||
Queue* queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_front_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue->empty(); }
|
||||
bool full() const { return queue->full(); }
|
||||
size_type size() const { return queue->size(); }
|
||||
bool closed() const { return queue->closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_front(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_front(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_front(forward<value_type>(x)); }
|
||||
|
||||
};
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_TEMPLATE_ALIASES
|
||||
|
||||
template <class T>
|
||||
using queue_back = queue_back_view<queue_base<T> > ;
|
||||
template <class T>
|
||||
using queue_front = queue_front_view<queue_base<T> > ;
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
struct queue_back : queue_back_view<queue_base<T> >
|
||||
{
|
||||
typedef queue_back_view<queue_base<T> > base_type;
|
||||
queue_back(queue_base<T>& q) BOOST_NOEXCEPT : base_type(q) {}
|
||||
};
|
||||
template <class T>
|
||||
struct queue_front : queue_front_view<queue_base<T> >
|
||||
{
|
||||
typedef queue_front_view<queue_base<T> > base_type;
|
||||
queue_front(queue_base<T>& q) BOOST_NOEXCEPT : base_type(q) {}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// template <class Queue>
|
||||
// queue_back_view<Queue> back(Queue & q) { return queue_back_view<Queue>(q); }
|
||||
// template <class Queue>
|
||||
// queue_front_view<Queue> front(Queue & q) { return queue_front_view<Queue>(q); }
|
||||
//#if 0
|
||||
// template <class T>
|
||||
// queue_back<T> back(queue_base<T> & q) { return queue_back<T>(q); }
|
||||
// template <class T>
|
||||
// queue_front<T> front(queue_base<T> & q) { return queue_front<T>(q); }
|
||||
//#else
|
||||
// template <class T>
|
||||
// typename queue_back<T>::type back(queue_base<T> & q) { return typename queue_back<T>::type(q); }
|
||||
// template <class T>
|
||||
// typename queue_front<T>::type front(queue_base<T> & q) { return typename queue_front<T>::type(q); }
|
||||
//#endif
|
||||
}
|
||||
|
||||
using concurrent::queue_back_view;
|
||||
using concurrent::queue_front_view;
|
||||
using concurrent::queue_back;
|
||||
using concurrent::queue_front;
|
||||
//using concurrent::back;
|
||||
//using concurrent::front;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
725
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
725
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
@@ -0,0 +1,725 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_bounded_queue)
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type capacity() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
condition_variable not_full_;
|
||||
size_type waiting_full_;
|
||||
size_type waiting_empty_;
|
||||
value_type* data_;
|
||||
size_type in_;
|
||||
size_type out_;
|
||||
size_type capacity_;
|
||||
bool closed_;
|
||||
|
||||
inline size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (idx + 1) % capacity_;
|
||||
}
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity_-1;
|
||||
}
|
||||
inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT
|
||||
{
|
||||
if (full(lk)) return capacity(lk);
|
||||
return ((out_+capacity(lk)-in_) % capacity(lk));
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>&) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
inline void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_full_ > 0)
|
||||
{
|
||||
--waiting_full_;
|
||||
lk.unlock();
|
||||
not_full_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
|
||||
inline void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
in_ = in;
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = elem;
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = boost::move(elem);
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) :
|
||||
waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
closed_(false)
|
||||
{
|
||||
BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) :
|
||||
// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
// closed_(false)
|
||||
// {
|
||||
// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size");
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// size_type in = 0;
|
||||
// for (iterator_t cur = first; cur != end; ++cur, ++in)
|
||||
// {
|
||||
// data_[in] = *cur;
|
||||
// }
|
||||
// set_in(in);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::~sync_bounded_queue()
|
||||
{
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
not_full_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::full() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return full(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return capacity(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
// template <typename ValueType>
|
||||
// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
// {
|
||||
// unique_lock<mutex> lk(mtx_);
|
||||
// wait_until_not_empty(lk, closed);
|
||||
// if (closed) {return;}
|
||||
// pull(elem, lk);
|
||||
// }
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 != out_) // ! full()
|
||||
{
|
||||
return in_p_1;
|
||||
}
|
||||
++waiting_full_;
|
||||
not_full_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
}
|
||||
using concurrent::sync_bounded_queue;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
362
include/boost/thread/concurrent_queues/sync_priority_queue.hpp
Normal file
362
include/boost/thread/concurrent_queues/sync_priority_queue.hpp
Normal file
@@ -0,0 +1,362 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_SYNC_PRIORITY_QUEUE
|
||||
#define BOOST_THREAD_SYNC_PRIORITY_QUEUE
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
template <
|
||||
class Type,
|
||||
class Container = csbl::vector<Type>,
|
||||
class Compare = std::less<Type>
|
||||
>
|
||||
class priority_queue
|
||||
{
|
||||
private:
|
||||
std::vector<Type> _elements;
|
||||
Compare _compare;
|
||||
public:
|
||||
explicit priority_queue(const Compare& compare = Compare())
|
||||
: _elements(), _compare(compare)
|
||||
{ }
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return _elements.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return _elements.empty();
|
||||
}
|
||||
|
||||
void push(Type const& element)
|
||||
{
|
||||
_elements.push_back(element);
|
||||
std::push_heap(_elements.begin(), _elements.end(), _compare);
|
||||
}
|
||||
void push(BOOST_RV_REF(Type) element)
|
||||
{
|
||||
_elements.push_back(boost::move(element));
|
||||
std::push_heap(_elements.begin(), _elements.end(), _compare);
|
||||
}
|
||||
|
||||
Type pull()
|
||||
{
|
||||
std::pop_heap(_elements.begin(), _elements.end(), _compare);
|
||||
Type result = boost::move(_elements.back());
|
||||
_elements.pop_back();
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
Type const& top()
|
||||
{
|
||||
return _elements.back();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace concurrent
|
||||
{
|
||||
template <class ValueType,
|
||||
class Container = csbl::vector<ValueType>,
|
||||
class Compare = std::less<typename Container::value_type> >
|
||||
class sync_priority_queue
|
||||
: public detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
typedef chrono::steady_clock clock;
|
||||
protected:
|
||||
|
||||
public:
|
||||
sync_priority_queue() {}
|
||||
|
||||
~sync_priority_queue()
|
||||
{
|
||||
if(!super::closed())
|
||||
{
|
||||
super::close();
|
||||
}
|
||||
}
|
||||
|
||||
void push(const ValueType& elem);
|
||||
void push(BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
queue_op_status try_push(const ValueType& elem);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
ValueType pull();
|
||||
|
||||
void pull(ValueType&);
|
||||
|
||||
queue_op_status pull_until(const clock::time_point&, ValueType&);
|
||||
queue_op_status pull_for(const clock::duration&, ValueType&);
|
||||
|
||||
queue_op_status try_pull(ValueType& elem);
|
||||
queue_op_status wait_pull(ValueType& elem);
|
||||
queue_op_status nonblocking_pull(ValueType&);
|
||||
|
||||
private:
|
||||
void push(unique_lock<mutex>&, const ValueType& elem);
|
||||
void push(lock_guard<mutex>&, const ValueType& elem);
|
||||
void push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
void push(lock_guard<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
queue_op_status try_push(unique_lock<mutex>&, const ValueType& elem);
|
||||
queue_op_status try_push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
ValueType pull(unique_lock<mutex>&);
|
||||
ValueType pull(lock_guard<mutex>&);
|
||||
|
||||
void pull(unique_lock<mutex>&, ValueType&);
|
||||
void pull(lock_guard<mutex>&, ValueType&);
|
||||
|
||||
queue_op_status try_pull(lock_guard<mutex>& lk, ValueType& elem);
|
||||
queue_op_status try_pull(unique_lock<mutex>& lk, ValueType& elem);
|
||||
|
||||
queue_op_status wait_pull(unique_lock<mutex>& lk, ValueType& elem);
|
||||
|
||||
queue_op_status nonblocking_pull(unique_lock<mutex>& lk, ValueType&);
|
||||
|
||||
sync_priority_queue(const sync_priority_queue&);
|
||||
sync_priority_queue& operator= (const sync_priority_queue&);
|
||||
sync_priority_queue(BOOST_THREAD_RV_REF(sync_priority_queue));
|
||||
sync_priority_queue& operator= (BOOST_THREAD_RV_REF(sync_priority_queue));
|
||||
}; //end class
|
||||
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, const T& elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, const T& elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(const T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
push(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
push(lk, boost::move(elem));
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(const T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(lk, boost::move(elem));
|
||||
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&)
|
||||
{
|
||||
return super::data_.pull();
|
||||
}
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&)
|
||||
{
|
||||
return super::data_.pull();
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&, T& elem)
|
||||
{
|
||||
elem = super::data_.pull();
|
||||
}
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&, T& elem)
|
||||
{
|
||||
elem = super::data_.pull();
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_until(const clock::time_point& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
|
||||
return queue_op_status::timeout;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_for(const clock::duration& dura, T& elem)
|
||||
{
|
||||
return pull_until(clock::now() + dura, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::nonblocking_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} //end concurrent namespace
|
||||
|
||||
using concurrent::sync_priority_queue;
|
||||
|
||||
} //end boost namespace
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
544
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
544
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
@@ -0,0 +1,544 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/deque.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_queue
|
||||
: public detail::sync_queue_base<ValueType, csbl::deque<ValueType> >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, csbl::deque<ValueType> > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue)
|
||||
inline sync_queue();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue();
|
||||
|
||||
// Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
inline void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(super::data_.front()));
|
||||
super::data_.pop_front();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
#endif
|
||||
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::sync_queue() :
|
||||
super()
|
||||
{
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// explicit sync_queue<ValueType>::sync_queue(Range range) :
|
||||
// data_(), closed_(false)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// for (iterator_t cur = first; cur != end; ++cur)
|
||||
// {
|
||||
// data_.push(boost::move(*cur));;
|
||||
// }
|
||||
// notify_not_empty_if_needed(lk);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::~sync_queue()
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem, bool & has_been_closed)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
using concurrent::sync_queue;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
431
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
431
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
@@ -0,0 +1,431 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_SYNC_TIMED_QUEUE_HPP
|
||||
#define BOOST_THREAD_SYNC_TIMED_QUEUE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/concurrent_queues/sync_priority_queue.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class T>
|
||||
struct scheduled_type
|
||||
{
|
||||
typedef typename chrono::steady_clock clock;
|
||||
typedef chrono::steady_clock::time_point time_point;
|
||||
T data;
|
||||
time_point time;
|
||||
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(scheduled_type)
|
||||
|
||||
scheduled_type(T const& pdata, time_point tp) : data(pdata), time(tp) {}
|
||||
scheduled_type(BOOST_THREAD_RV_REF(T) pdata, time_point tp) : data(boost::move(pdata)), time(tp) {}
|
||||
|
||||
scheduled_type(scheduled_type const& other) : data(other.data), time(other.time) {}
|
||||
scheduled_type& operator=(BOOST_THREAD_COPY_ASSIGN_REF(scheduled_type) other) {
|
||||
data = other.data;
|
||||
time = other.time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scheduled_type(BOOST_THREAD_RV_REF(scheduled_type) other) : data(boost::move(other.data)), time(other.time) {}
|
||||
scheduled_type& operator=(BOOST_THREAD_RV_REF(scheduled_type) other) {
|
||||
data = boost::move(other.data);
|
||||
time = other.time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool time_not_reached() const
|
||||
{
|
||||
return time > clock::now();
|
||||
}
|
||||
|
||||
bool operator <(const scheduled_type<T> other) const
|
||||
{
|
||||
return this->time > other.time;
|
||||
}
|
||||
}; //end struct
|
||||
|
||||
} //end detail namespace
|
||||
|
||||
template <class T>
|
||||
class sync_timed_queue
|
||||
: private sync_priority_queue<detail::scheduled_type<T> >
|
||||
{
|
||||
typedef detail::scheduled_type<T> stype;
|
||||
typedef sync_priority_queue<stype> super;
|
||||
public:
|
||||
//typedef typename stype::clock clock; // fixme
|
||||
typedef typename chrono::steady_clock clock;
|
||||
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
typedef T value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
sync_timed_queue() : super() {};
|
||||
~sync_timed_queue() {}
|
||||
|
||||
using super::size;
|
||||
using super::empty;
|
||||
using super::full;
|
||||
using super::close;
|
||||
using super::closed;
|
||||
|
||||
T pull();
|
||||
void pull(T& elem);
|
||||
|
||||
queue_op_status pull_until(const clock::time_point& tp, T& elem);
|
||||
queue_op_status pull_for(const clock::duration& dura, T& elem);
|
||||
|
||||
queue_op_status try_pull(T& elem);
|
||||
queue_op_status wait_pull(T& elem);
|
||||
queue_op_status nonblocking_pull(T& elem);
|
||||
|
||||
void push(const T& elem, const time_point& tp);
|
||||
void push(const T& elem, const duration& dura);
|
||||
|
||||
queue_op_status try_push(const T& elem, const time_point& tp);
|
||||
queue_op_status try_push(const T& elem, const duration& dura);
|
||||
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, const time_point& tp);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, const duration& dura);
|
||||
|
||||
private:
|
||||
T pull(unique_lock<mutex>&);
|
||||
T pull(lock_guard<mutex>&);
|
||||
|
||||
void pull(unique_lock<mutex>&, T& elem);
|
||||
void pull(lock_guard<mutex>&, T& elem);
|
||||
|
||||
queue_op_status try_pull(unique_lock<mutex>&, T& elem);
|
||||
queue_op_status try_pull(lock_guard<mutex>&, T& elem);
|
||||
|
||||
queue_op_status wait_pull(unique_lock<mutex>& lk, T& elem);
|
||||
|
||||
//queue_op_status nonblocking_pull(unique_lock<mutex>& lk, T& elem);
|
||||
|
||||
bool wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>&);
|
||||
T pull_when_time_reached(unique_lock<mutex>&);
|
||||
queue_op_status pull_when_time_reached_until(unique_lock<mutex>&, const clock::time_point& tp, T& elem);
|
||||
bool time_not_reached(unique_lock<mutex>&);
|
||||
bool time_not_reached(lock_guard<mutex>&);
|
||||
bool empty_or_time_not_reached(unique_lock<mutex>&);
|
||||
bool empty_or_time_not_reached(lock_guard<mutex>&);
|
||||
|
||||
sync_timed_queue(const sync_timed_queue&);
|
||||
sync_timed_queue& operator=(const sync_timed_queue&);
|
||||
sync_timed_queue(BOOST_THREAD_RV_REF(sync_timed_queue));
|
||||
sync_timed_queue& operator=(BOOST_THREAD_RV_REF(sync_timed_queue));
|
||||
}; //end class
|
||||
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::push(const T& elem, const time_point& tp)
|
||||
{
|
||||
super::push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::push(const T& elem, const duration& dura)
|
||||
{
|
||||
push(elem, clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(const T& elem, const time_point& tp)
|
||||
{
|
||||
return super::try_push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(const T& elem, const duration& dura)
|
||||
{
|
||||
return try_push(elem,clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(BOOST_THREAD_RV_REF(T) elem, const time_point& tp)
|
||||
{
|
||||
return super::try_push(stype(boost::move(elem), tp));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(BOOST_THREAD_RV_REF(T) elem, const duration& dura)
|
||||
{
|
||||
return try_push(boost::move(elem), clock::now() + dura);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::time_not_reached(unique_lock<mutex>&)
|
||||
{
|
||||
return super::data_.top().time_not_reached();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::time_not_reached(lock_guard<mutex>&)
|
||||
{
|
||||
return super::data_.top().time_not_reached();
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (super::closed(lk)) return true;
|
||||
while (! super::empty(lk)) {
|
||||
if (! time_not_reached(lk)) return false;
|
||||
super::not_empty_.wait_until(lk, super::data_.top().time);
|
||||
if (super::closed(lk)) return true;
|
||||
}
|
||||
if (super::closed(lk)) return true;
|
||||
super::not_empty_.wait(lk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull_when_time_reached(unique_lock<mutex>& lk)
|
||||
{
|
||||
while (time_not_reached(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::not_empty_.wait_until(lk,super::data_.top().time);
|
||||
super::wait_until_not_empty(lk);
|
||||
}
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status
|
||||
sync_timed_queue<T>::pull_when_time_reached_until(unique_lock<mutex>& lk, const clock::time_point& tp, T& elem)
|
||||
{
|
||||
clock::time_point tpmin = (tp < super::data_.top().time) ? tp : super::data_.top().time;
|
||||
while (time_not_reached(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
if (queue_op_status::timeout == super::not_empty_.wait_until(lk, tpmin)) {
|
||||
if (time_not_reached(lk)) return queue_op_status::not_ready;
|
||||
return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::empty_or_time_not_reached(unique_lock<mutex>& lk)
|
||||
{
|
||||
if ( super::empty(lk) ) return true;
|
||||
if ( time_not_reached(lk) ) return true;
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::empty_or_time_not_reached(lock_guard<mutex>& lk)
|
||||
{
|
||||
if ( super::empty(lk) ) return true;
|
||||
if ( time_not_reached(lk) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull(unique_lock<mutex>&)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
return boost::move(super::data_.pull().data);
|
||||
#else
|
||||
return super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull(lock_guard<mutex>&)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
return boost::move(super::data_.pull().data);
|
||||
#else
|
||||
return super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull_when_time_reached(lk);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::pull(unique_lock<mutex>&, T& elem)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
elem = boost::move(super::data_.pull().data);
|
||||
#else
|
||||
elem = super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::pull(lock_guard<mutex>&, T& elem)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
elem = boost::move(super::data_.pull().data);
|
||||
#else
|
||||
elem = super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
elem = pull_when_time_reached(lk);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T>
|
||||
queue_op_status
|
||||
sync_timed_queue<T>::pull_until(const clock::time_point& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
|
||||
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
|
||||
return queue_op_status::timeout;
|
||||
return pull_when_time_reached_until(lk, tp, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T>
|
||||
queue_op_status
|
||||
sync_timed_queue<T>::pull_for(const clock::duration& dura, T& elem)
|
||||
{
|
||||
return pull_until(clock::now() + dura, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if ( super::empty(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
if ( time_not_reached(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if ( super::empty(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
if ( time_not_reached(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = wait_until_not_empty_time_reached_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
// ///////////////////////////
|
||||
// template <class T>
|
||||
// queue_op_status sync_timed_queue<T>::wait_pull(unique_lock<mutex> &lk, T& elem)
|
||||
// {
|
||||
// if (super::empty(lk))
|
||||
// {
|
||||
// if (super::closed(lk)) return queue_op_status::closed;
|
||||
// }
|
||||
// bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
// if (has_been_closed) return queue_op_status::closed;
|
||||
// pull(lk, elem);
|
||||
// return queue_op_status::success;
|
||||
// }
|
||||
// template <class T>
|
||||
// queue_op_status sync_timed_queue<T>::wait_pull(T& elem)
|
||||
// {
|
||||
// unique_lock<mutex> lk(super::mtx_);
|
||||
// return wait_pull(lk, elem);
|
||||
// }
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::nonblocking_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (! lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
} //end concurrent namespace
|
||||
|
||||
using concurrent::sync_timed_queue;
|
||||
|
||||
} //end boost namespace
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -10,8 +10,16 @@
|
||||
#define BOOST_CSBL_DEQUE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
// MSVC has some trouble instantiating a non_copyable type
|
||||
//C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(606) : error C2248: 'non_copyable::non_copyable' : cannot access private member declared in class 'non_copyable'
|
||||
// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(24) : see declaration of 'non_copyable::non_copyable'
|
||||
// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(23) : see declaration of 'non_copyable'
|
||||
// C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
|
||||
// with
|
||||
// [
|
||||
// _Ty=non_copyable
|
||||
// ]
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827)
|
||||
#ifndef BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#define BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#endif
|
||||
|
||||
@@ -15,97 +15,13 @@
|
||||
// default_delete
|
||||
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/move/unique_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class _Ptr1, class _Ptr2,
|
||||
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
|
||||
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
|
||||
>::value
|
||||
>
|
||||
struct same_or_less_cv_qualified_imp
|
||||
: is_convertible<_Ptr1, _Ptr2>
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
|
||||
: false_type
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
|
||||
!is_pointer<_Ptr1>::value>
|
||||
struct same_or_less_cv_qualified
|
||||
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2>
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
|
||||
: false_type
|
||||
{};
|
||||
|
||||
}
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
|
||||
{}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U>&,
|
||||
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT
|
||||
{}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (T* ptr) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
|
||||
{}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U[]>&,
|
||||
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT
|
||||
{}
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (U* ptr,
|
||||
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete [] ptr;
|
||||
}
|
||||
};
|
||||
using ::boost::movelib::default_delete;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
42
include/boost/thread/csbl/memory/shared_ptr.hpp
Normal file
42
include/boost/thread/csbl/memory/shared_ptr.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2014/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_SHARED_PTR_HPP
|
||||
#define BOOST_CSBL_MEMORY_SHARED_PTR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::shared_ptr;
|
||||
using ::boost::make_shared;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // header
|
||||
@@ -1,106 +1,28 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
// Copyright (C) 2013-2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
// Creation using interprocess::unique_ptr.
|
||||
// 2014/09 Vicente J. Botet Escriba
|
||||
// Adaptation to movelib::unique_ptr
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
#define BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
#include <boost/thread/csbl/memory/default_delete.hpp>
|
||||
|
||||
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
|
||||
#include <boost/move/unique_ptr.hpp>
|
||||
#include <boost/move/make_unique.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
template <class T, class D = default_delete<T> > class unique_ptr :
|
||||
public ::boost::interprocess::unique_ptr<T,D>
|
||||
{
|
||||
typedef ::boost::interprocess::unique_ptr<T,D> base_type;
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr)
|
||||
protected:
|
||||
//typedef typename base_type::nat nat;
|
||||
//typedef typename base_type::nullptr_t nullptr_t;
|
||||
struct nat {int for_bool;};
|
||||
struct nat2 {int for_nullptr;};
|
||||
typedef int nat2::*nullptr_t;
|
||||
using ::boost::movelib::unique_ptr;
|
||||
using ::boost::movelib::make_unique;
|
||||
|
||||
public:
|
||||
typedef typename base_type::element_type element_type;
|
||||
typedef typename base_type::deleter_type deleter_type;
|
||||
typedef typename base_type::pointer pointer;
|
||||
|
||||
unique_ptr() : base_type()
|
||||
{}
|
||||
explicit unique_ptr(pointer p): base_type(p)
|
||||
{}
|
||||
unique_ptr(pointer p
|
||||
,typename interprocess::ipcdetail::if_<interprocess::ipcdetail::is_reference<D>
|
||||
,D
|
||||
,typename interprocess::ipcdetail::add_reference<const D>::type>::type d)
|
||||
: base_type(p, d)
|
||||
{}
|
||||
unique_ptr(BOOST_RV_REF(unique_ptr) u)
|
||||
: base_type(boost::move(static_cast<base_type&>(u)))
|
||||
{}
|
||||
template <class U, class E>
|
||||
unique_ptr(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u,
|
||||
typename interprocess::ipcdetail::enable_if_c<
|
||||
interprocess::ipcdetail::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
|
||||
interprocess::ipcdetail::is_convertible<E, D>::value &&
|
||||
(
|
||||
!interprocess::ipcdetail::is_reference<D>::value ||
|
||||
interprocess::ipcdetail::is_same<D, E>::value
|
||||
)
|
||||
,
|
||||
nat
|
||||
>::type = nat())
|
||||
: base_type(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)))
|
||||
{}
|
||||
unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u)
|
||||
{
|
||||
this->base_type::operator=(boost::move(static_cast<base_type&>(u)));
|
||||
return *this;
|
||||
}
|
||||
template <class U, class E>
|
||||
unique_ptr& operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u)
|
||||
{
|
||||
this->base_type::template operator=<U,E>(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)));
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(nullptr_t t)
|
||||
{
|
||||
this->base_type::operator=(t);
|
||||
return *this;
|
||||
}
|
||||
void swap(unique_ptr& u)
|
||||
{
|
||||
this->base_type::swap(u);
|
||||
}
|
||||
};
|
||||
template <class T, class D>
|
||||
class unique_ptr<T[], D> :
|
||||
public ::boost::interprocess::unique_ptr<T[],D>
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::unique_ptr;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_SMART_PTR
|
||||
#endif // header
|
||||
|
||||
@@ -28,10 +28,14 @@ namespace boost
|
||||
#if defined BOOST_THREAD_USES_BOOST_TUPLE
|
||||
using ::boost::tuple;
|
||||
using ::boost::get;
|
||||
using ::boost::make_tuple;
|
||||
//using ::boost::tuple_size;
|
||||
#else
|
||||
// 20.4.2, class template tuple:
|
||||
using ::std::tuple;
|
||||
using ::std::get;
|
||||
using ::std::make_tuple;
|
||||
using ::std::tuple_size;
|
||||
// 20.4.2.4, tuple creation functions:
|
||||
// 20.4.2.5, tuple helper classes:
|
||||
// 20.4.2.6, element access:
|
||||
|
||||
@@ -239,7 +239,6 @@
|
||||
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
@@ -354,6 +353,12 @@
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_THREAD_USES_MOVE
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#define BOOST_THREAD_FUTURE_USES_OPTIONAL
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
# pragma warn -8008 // Condition always true/false
|
||||
# pragma warn -8080 // Identifier declared but never used
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* makes it private.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#if ! defined BOOST_NO_CXX11_DELETED_FUNCTIONS && ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
CLASS(CLASS const&) = delete; \
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace boost
|
||||
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
if (impl) f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
|
||||
@@ -47,7 +47,6 @@ namespace boost
|
||||
#if ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_INVOKE
|
||||
@@ -339,7 +338,6 @@ namespace boost
|
||||
! defined BOOST_NO_CXX11_HDR_FUNCTIONAL && \
|
||||
defined BOOST_MSVC
|
||||
|
||||
//#error
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
Ret invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
// The invoker code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
#define BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
#ifndef BOOST_THREAD_DETAIL_INVOKER_HPP
|
||||
#define BOOST_THREAD_DETAIL_INVOKER_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace boost
|
||||
csbl::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker)
|
||||
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
|
||||
typedef typename result_of<Fp(Args...)>::type result_type;
|
||||
|
||||
@@ -65,6 +65,22 @@ namespace boost
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f) : f_(boost::move(BOOST_THREAD_RV(f).f_))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker( const invoker& f) : f_(f.f_)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker& operator=(BOOST_THREAD_RV_REF(invoker) f)
|
||||
{
|
||||
f_ = boost::move(BOOST_THREAD_RV(f).f_);
|
||||
}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker& operator=( BOOST_THREAD_COPY_ASSIGN_REF(invoker) f)
|
||||
{
|
||||
f_ = f.f_;
|
||||
}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index;
|
||||
@@ -89,7 +105,7 @@ namespace boost
|
||||
csbl::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( invoker_ret)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker_ret)
|
||||
typedef R result_type;
|
||||
|
||||
template <class F, class ... As>
|
||||
@@ -147,7 +163,7 @@ namespace boost
|
||||
Fp fp_; \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
|
||||
public: \
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker) \
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) \
|
||||
typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \
|
||||
\
|
||||
template <class F BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \
|
||||
@@ -160,7 +176,7 @@ namespace boost
|
||||
{} \
|
||||
\
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) x) \
|
||||
: fp_(boost::move(x.fp_)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
|
||||
{} \
|
||||
@@ -179,7 +195,7 @@ namespace boost
|
||||
Fp fp_; \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
|
||||
public: \
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker) \
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) \
|
||||
typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \
|
||||
\
|
||||
template <class R2 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \
|
||||
@@ -192,7 +208,7 @@ namespace boost
|
||||
{} \
|
||||
\
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) x) \
|
||||
: fp_(x.fp_) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
|
||||
{} \
|
||||
@@ -248,7 +264,7 @@ namespace boost
|
||||
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -276,7 +292,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -317,7 +333,7 @@ namespace boost
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -343,7 +359,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -381,7 +397,7 @@ namespace boost
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -405,7 +421,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -440,7 +456,7 @@ namespace boost
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -462,7 +478,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -494,7 +510,7 @@ namespace boost
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -514,7 +530,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -543,7 +559,7 @@ namespace boost
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -561,7 +577,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -587,7 +603,7 @@ namespace boost
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -603,7 +619,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -626,7 +642,7 @@ namespace boost
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -640,7 +656,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
@@ -660,7 +676,7 @@ namespace boost
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
@@ -672,7 +688,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
{}
|
||||
@@ -697,7 +713,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(f.fp_))
|
||||
{}
|
||||
result_type operator()()
|
||||
@@ -719,7 +735,7 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(f.fp_)
|
||||
{}
|
||||
result_type operator()()
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace boost
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
@@ -100,6 +101,7 @@ namespace boost
|
||||
|
||||
#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_MSVC
|
||||
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
@@ -121,6 +123,7 @@ namespace boost
|
||||
#else
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
@@ -140,6 +143,7 @@ namespace boost
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) const TYPE&
|
||||
#define BOOST_THREAD_RV_REF(TYPE) boost::detail::thread_move_t< TYPE >
|
||||
#define BOOST_THREAD_RV_REF_BEG boost::detail::thread_move_t<
|
||||
#define BOOST_THREAD_RV_REF_END >
|
||||
@@ -198,6 +202,8 @@ namespace detail
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE)
|
||||
|
||||
#define BOOST_THREAD_COPYABLE(TYPE)
|
||||
|
||||
#else
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
@@ -220,6 +226,11 @@ namespace detail
|
||||
return *static_cast<const ::boost::rv<TYPE>* >(this); \
|
||||
}\
|
||||
|
||||
#define BOOST_THREAD_COPYABLE(TYPE) \
|
||||
TYPE& operator=(TYPE &t)\
|
||||
{ this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE) \
|
||||
@@ -233,15 +244,20 @@ namespace detail
|
||||
return x; \
|
||||
} \
|
||||
|
||||
#define BOOST_THREAD_COPYABLE(TYPE)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_MOVABLE_ONLY(TYPE) \
|
||||
BOOST_THREAD_NO_COPYABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
typedef int boost_move_no_copy_constructor_or_assign; \
|
||||
|
||||
|
||||
#define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
BOOST_THREAD_COPYABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
|
||||
|
||||
|
||||
@@ -249,6 +265,31 @@ namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#elif defined BOOST_THREAD_USES_MOVE
|
||||
template <class T>
|
||||
struct is_rv
|
||||
: ::boost::move_detail::is_rv<T>
|
||||
{};
|
||||
|
||||
#else
|
||||
template <class T>
|
||||
struct is_rv
|
||||
: ::boost::integral_constant<bool, false>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct is_rv< ::boost::detail::thread_move_t<T> >
|
||||
: ::boost::integral_constant<bool, true>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct is_rv< const ::boost::detail::thread_move_t<T> >
|
||||
: ::boost::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class Tp>
|
||||
struct remove_reference : boost::remove_reference<Tp> {};
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/thread/csbl/memory/shared_ptr.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -33,7 +33,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
};
|
||||
shared_ptr<impl_base> impl;
|
||||
csbl::shared_ptr<impl_base> impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE(nullary_function)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function)
|
||||
|
||||
explicit nullary_function(void (*f)()):
|
||||
impl(new impl_type_ptr(f))
|
||||
@@ -90,29 +90,39 @@ namespace boost
|
||||
{
|
||||
}
|
||||
nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT :
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
#else
|
||||
impl(boost::move(other.impl))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
|
||||
nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
#else
|
||||
impl = boost::move(other.impl);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{ impl->call();}
|
||||
{ if (impl) impl->call();}
|
||||
|
||||
};
|
||||
|
||||
@@ -126,7 +136,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
};
|
||||
shared_ptr<impl_base> impl;
|
||||
csbl::shared_ptr<impl_base> impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
@@ -158,7 +168,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE(nullary_function)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function)
|
||||
|
||||
nullary_function(R (*f)()):
|
||||
impl(new impl_type_ptr(f))
|
||||
@@ -179,10 +189,16 @@ namespace boost
|
||||
{
|
||||
}
|
||||
nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT :
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
#else
|
||||
impl(boost::move(other.impl))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
nullary_function()
|
||||
: impl()
|
||||
{
|
||||
@@ -191,23 +207,28 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
|
||||
nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
#else
|
||||
impl = boost::move(other.impl);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
R operator()()
|
||||
{ return impl->call();}
|
||||
{ if (impl) return impl->call(); else return R();}
|
||||
|
||||
};
|
||||
}
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::nullary_function<F> BOOST_THREAD_DCL_MOVABLE_END
|
||||
}
|
||||
|
||||
#endif // header
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/predef/platform.h>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
@@ -291,7 +292,8 @@ namespace boost
|
||||
template <class F>
|
||||
explicit thread(F f
|
||||
, typename disable_if_c<
|
||||
boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
|
||||
boost::thread_detail::is_rv<F>::value // todo ass a thread_detail::is_rv
|
||||
//boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
|
||||
//|| is_same<typename decay<F>::type, thread>::value
|
||||
, dummy* >::type=0
|
||||
):
|
||||
@@ -301,7 +303,8 @@ namespace boost
|
||||
}
|
||||
template <class F>
|
||||
thread(attributes const& attrs, F f
|
||||
, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
|
||||
, typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0
|
||||
//, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
|
||||
):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
// Copyright (C) 2013-2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -36,7 +36,7 @@ namespace executors
|
||||
typedef csbl::vector<thread_t> thread_vector;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
/// A move aware vector
|
||||
thread_vector threads;
|
||||
|
||||
@@ -48,9 +48,9 @@ namespace executors
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
work task;
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
@@ -58,12 +58,9 @@ namespace executors
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -85,12 +82,20 @@ namespace executors
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
try
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = work_queue.wait_pull_front(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
}
|
||||
while (try_executing_one())
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
@@ -98,37 +103,19 @@ namespace executors
|
||||
void worker_thread1(AtThreadEntry& at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
worker_thread();
|
||||
}
|
||||
#endif
|
||||
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
worker_thread();
|
||||
}
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
worker_thread();
|
||||
}
|
||||
static void do_nothing_at_thread_entry(basic_thread_pool&) {}
|
||||
|
||||
@@ -141,7 +128,7 @@ namespace executors
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -238,6 +225,17 @@ namespace executors
|
||||
// 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)
|
||||
{
|
||||
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.
|
||||
@@ -271,33 +269,20 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
//work w ((closure));
|
||||
//work_queue.push_back(boost::move(w));
|
||||
work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
//work w ((closure));
|
||||
//work_queue.push_back(boost::move(w));
|
||||
work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
#else
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef SCHEDULED_EXECUTOR_HPP
|
||||
#define SCHEDULED_EXECUTOR_HPP
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_timed_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class scheduled_executor_base
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void()> work;
|
||||
//typedef executors::work work;
|
||||
typedef chrono::steady_clock clock;
|
||||
typedef clock::duration duration;
|
||||
typedef clock::time_point time_point;
|
||||
protected:
|
||||
concurrent::sync_timed_queue<work> _workq;
|
||||
|
||||
scheduled_executor_base() {}
|
||||
public:
|
||||
|
||||
~scheduled_executor_base()
|
||||
{
|
||||
if(!closed())
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
_workq.close();
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return _workq.closed();
|
||||
}
|
||||
|
||||
void submit(work w)
|
||||
{
|
||||
_workq.push(w, clock::now());
|
||||
}
|
||||
|
||||
void submit_at(work w, const time_point& tp)
|
||||
{
|
||||
_workq.push(w, tp);
|
||||
}
|
||||
|
||||
void submit_after(work w, const duration& dura)
|
||||
{
|
||||
_workq.push(w, dura);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = _workq.wait_pull(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}; //end class
|
||||
|
||||
} //end detail namespace
|
||||
} //end executors namespace
|
||||
} //end boost namespace
|
||||
#endif
|
||||
@@ -32,43 +32,55 @@ namespace boost
|
||||
executor() {}
|
||||
|
||||
/**
|
||||
* \b Effects: Destroys the executor.
|
||||
* \par Effects
|
||||
* Destroys the executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the executor destructor.
|
||||
* \par Synchronization
|
||||
* The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
virtual ~executor() {};
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c executor for submissions.
|
||||
* \par Effects
|
||||
* Close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
* \par Returns
|
||||
* Whether the pool is closed for submissions.
|
||||
*/
|
||||
virtual bool closed() = 0;
|
||||
|
||||
/**
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* \par Effects
|
||||
* The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
* \par Synchronization
|
||||
* Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* \par Throws
|
||||
* \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0;
|
||||
// virtual void submit(work& closure) = 0;
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
* \par Requires
|
||||
* \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* \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.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
* \par Synchronization
|
||||
* Completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* \par Throws
|
||||
* \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
@@ -94,16 +106,23 @@ namespace boost
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
* \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.
|
||||
*/
|
||||
virtual bool try_executing_one() = 0;
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
* \par Requires
|
||||
* This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
* \par Effects
|
||||
* Reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
@@ -119,7 +138,6 @@ namespace boost
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
using executors::executor;
|
||||
}
|
||||
|
||||
@@ -97,39 +97,28 @@ namespace executors
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
return ex.submit(boost::move(closure));
|
||||
//return ex.submit(boost::forward<work>(closure));
|
||||
}
|
||||
// void submit(work & closure) {
|
||||
// return ex.submit(closure);
|
||||
// }
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
submit(boost::move(w));
|
||||
}
|
||||
#else
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
submit(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
|
||||
211
include/boost/thread/executors/generic_executor_ref.hpp
Normal file
211
include/boost/thread/executors/generic_executor_ref.hpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
template <class Executor>
|
||||
class executor_ref : public executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor_ref)
|
||||
executor_ref(Executor& ex) : ex(ex) {}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Destroys the executor.
|
||||
*
|
||||
* \par Synchronization
|
||||
* The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
~executor_ref() {};
|
||||
|
||||
/**
|
||||
* \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(); }
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \par Synchronization
|
||||
* Ccompletion 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.
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
ex.submit(boost::move(closure));
|
||||
}
|
||||
// void submit(work& closure) {
|
||||
// ex.submit(closure);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* \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(); }
|
||||
|
||||
};
|
||||
|
||||
class generic_executor_ref
|
||||
{
|
||||
shared_ptr<executor> ex;
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
|
||||
template<typename Executor>
|
||||
generic_executor_ref(Executor& ex)
|
||||
//: ex(make_shared<executor_ref<Executor> >(ex)) // todo check why this doesn't works with C++03
|
||||
: ex( new executor_ref<Executor>(ex) )
|
||||
{
|
||||
}
|
||||
|
||||
//generic_executor_ref(generic_executor_ref const& other) noexcept {}
|
||||
//generic_executor_ref& operator=(generic_executor_ref 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::executor_ref;
|
||||
using executors::generic_executor_ref;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@ namespace executors
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
mutable mutex mtx_;
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
@@ -66,16 +67,22 @@ namespace executors
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
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.
|
||||
@@ -93,21 +100,54 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
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)())
|
||||
{
|
||||
if (closed()) return;
|
||||
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)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace executors
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -51,12 +51,9 @@ namespace executors
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -74,19 +71,7 @@ namespace executors
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/// loop_executor is not copyable.
|
||||
@@ -112,9 +97,19 @@ namespace executors
|
||||
}
|
||||
|
||||
/**
|
||||
* loop
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void loop() { 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.
|
||||
@@ -148,24 +143,18 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,17 +173,18 @@ namespace executors
|
||||
} 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())
|
||||
while (! q.empty())
|
||||
{
|
||||
work task = q.front();
|
||||
q.pop_front();
|
||||
work& task = q.front();
|
||||
task();
|
||||
q.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
include/boost/thread/executors/scheduled_thread_pool.hpp
Normal file
68
include/boost/thread/executors/scheduled_thread_pool.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
class scheduled_thread_pool : public detail::scheduled_executor_base
|
||||
{
|
||||
private:
|
||||
thread_group _workers;
|
||||
public:
|
||||
|
||||
scheduled_thread_pool(size_t num_threads) : super()
|
||||
{
|
||||
for(size_t i = 0; i < num_threads; i++)
|
||||
{
|
||||
_workers.create_thread(bind(&super::loop, this));
|
||||
}
|
||||
}
|
||||
|
||||
~scheduled_thread_pool()
|
||||
{
|
||||
this->close();
|
||||
_workers.join_all();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef detail::scheduled_executor_base super;
|
||||
inline void loop();
|
||||
}; //end class
|
||||
|
||||
void scheduled_thread_pool::loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
super::work task;
|
||||
queue_op_status st = super::_workq.wait_pull(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} //end executors namespace
|
||||
|
||||
using executors::scheduled_thread_pool;
|
||||
|
||||
} //end boost
|
||||
#endif
|
||||
|
||||
259
include/boost/thread/executors/scheduler.hpp
Normal file
259
include/boost/thread/executors/scheduler.hpp
Normal file
@@ -0,0 +1,259 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
/// Wraps the reference to an executor and a function to make a work that submit the function using the executor.
|
||||
template <class Executor, class Function>
|
||||
class resubmitter
|
||||
{
|
||||
public:
|
||||
resubmitter(Executor& ex, Function funct) :
|
||||
ex(ex),
|
||||
funct(boost::move(funct))
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
ex.submit(funct);
|
||||
}
|
||||
|
||||
private:
|
||||
Executor& ex;
|
||||
Function funct;
|
||||
};
|
||||
|
||||
/// resubmitter factory
|
||||
template <class Executor, class Function>
|
||||
resubmitter<Executor, typename decay<Function>::type>
|
||||
resubmit(Executor& ex, BOOST_THREAD_FWD_REF(Function) funct) {
|
||||
return resubmitter<Executor, typename decay<Function>::type >(ex, boost::move(funct));
|
||||
}
|
||||
|
||||
/// Wraps references to a @c Scheduler and an @c Executor providing an @c Executor that
|
||||
/// resubmit the function using the referenced Executor at a given @c time_point known at construction.
|
||||
template <class Scheduler, class Executor>
|
||||
class resubmit_at_executor
|
||||
{
|
||||
public:
|
||||
typedef chrono::steady_clock clock;
|
||||
|
||||
resubmit_at_executor(Scheduler& sch, Executor& ex, clock::time_point const& tp) :
|
||||
sch(sch),
|
||||
ex(ex),
|
||||
tp(tp),
|
||||
is_closed(false)
|
||||
{
|
||||
}
|
||||
|
||||
~resubmit_at_executor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
template <class Work>
|
||||
void submit(BOOST_THREAD_FWD_REF(Work) w)
|
||||
{
|
||||
if (closed())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
sch.submit_at(resubmit(ex,boost::forward<Work>(w)), tp);
|
||||
}
|
||||
|
||||
Executor& underlying_executor()
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
Scheduler& underlying_scheduler()
|
||||
{
|
||||
return sch;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
is_closed = true;
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return is_closed || sch.closed() || ex.closed();
|
||||
}
|
||||
|
||||
private:
|
||||
Scheduler& sch;
|
||||
Executor& ex;
|
||||
clock::time_point tp;
|
||||
bool is_closed;
|
||||
};
|
||||
|
||||
|
||||
/// Expression template helper storing a pair of references to an @c Scheduler and an @c Executor
|
||||
/// It provides factory helper functions such as at/after that convert these a pair of @c Scheduler @c Executor
|
||||
/// into an new @c Executor that submit the work using the referenced @c Executor at/after a specific time/duration
|
||||
/// respectively, using the referenced @Scheduler.
|
||||
template <class Scheduler, class Executor>
|
||||
class scheduler_executor_wrapper
|
||||
{
|
||||
public:
|
||||
typedef chrono::steady_clock clock;
|
||||
typedef resubmit_at_executor<Scheduler, Executor> the_executor;
|
||||
|
||||
scheduler_executor_wrapper(Scheduler& sch, Executor& ex) :
|
||||
sch(sch),
|
||||
ex(ex)
|
||||
{}
|
||||
|
||||
~scheduler_executor_wrapper()
|
||||
{
|
||||
}
|
||||
|
||||
Executor& underlying_executor()
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
Scheduler& underlying_scheduler()
|
||||
{
|
||||
return sch;
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
the_executor after(Duration const& rel_time)
|
||||
{
|
||||
return at(clock::now() + rel_time );
|
||||
}
|
||||
|
||||
the_executor at(clock::time_point const& abs_time)
|
||||
{
|
||||
return the_executor(sch, ex, abs_time);
|
||||
}
|
||||
|
||||
private:
|
||||
Scheduler& sch;
|
||||
Executor& ex;
|
||||
}; //end class
|
||||
|
||||
/// Wraps a reference to a @c Scheduler providing an @c Executor that
|
||||
/// run the function at a given @c time_point known at construction.
|
||||
template <class Scheduler>
|
||||
class at_executor
|
||||
{
|
||||
public:
|
||||
typedef chrono::steady_clock clock;
|
||||
|
||||
at_executor(Scheduler& sch, clock::time_point const& tp) :
|
||||
sch(sch),
|
||||
tp(tp),
|
||||
is_closed(false)
|
||||
{}
|
||||
|
||||
~at_executor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
Scheduler& underlying_scheduler()
|
||||
{
|
||||
return sch;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
is_closed = true;
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return is_closed || sch.closed();
|
||||
}
|
||||
|
||||
template <class Work>
|
||||
void submit(BOOST_THREAD_FWD_REF(Work) w)
|
||||
{
|
||||
if (closed())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
sch.submit_at(boost::forward<Work>(w), tp);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
resubmit_at_executor<Scheduler, Executor> on(Executor& ex)
|
||||
{
|
||||
return resubmit_at_executor<Scheduler, Executor>(sch, ex, tp);
|
||||
}
|
||||
|
||||
private:
|
||||
Scheduler& sch;
|
||||
clock::time_point tp;
|
||||
bool is_closed;
|
||||
}; //end class
|
||||
|
||||
/// A @c Scheduler using a specific thread. Note that a Scheduler is not an 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.
|
||||
class scheduler : public detail::scheduled_executor_base
|
||||
{
|
||||
public:
|
||||
typedef chrono::steady_clock clock;
|
||||
typedef clock::time_point time_point;
|
||||
|
||||
scheduler()
|
||||
: super(),
|
||||
thr(&super::loop, this) {}
|
||||
|
||||
~scheduler()
|
||||
{
|
||||
this->close();
|
||||
thr.join();
|
||||
}
|
||||
template <class Ex>
|
||||
scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex)
|
||||
{
|
||||
return scheduler_executor_wrapper<scheduler, Ex>(*this, ex);
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
at_executor<scheduler> after(Duration const& rel_time)
|
||||
{
|
||||
return at(rel_time + clock::now());
|
||||
}
|
||||
|
||||
at_executor<scheduler> at(time_point const& tp)
|
||||
{
|
||||
return at_executor<scheduler>(*this, tp);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef detail::scheduled_executor_base super;
|
||||
thread thr;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
using executors::resubmitter;
|
||||
using executors::resubmit;
|
||||
using executors::resubmit_at_executor;
|
||||
using executors::scheduler_executor_wrapper;
|
||||
using executors::at_executor;
|
||||
using executors::scheduler;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
72
include/boost/thread/executors/scheduling_adaptor.hpp
Normal file
72
include/boost/thread/executors/scheduling_adaptor.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
|
||||
|
||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
template <typename Executor>
|
||||
class scheduling_adpator : public detail::scheduled_executor_base
|
||||
{
|
||||
private:
|
||||
Executor& _exec;
|
||||
thread _scheduler;
|
||||
public:
|
||||
|
||||
scheduling_adpator(Executor& ex)
|
||||
: super(),
|
||||
_exec(ex),
|
||||
_scheduler(&scheduling_adpator::loop, this) {}
|
||||
|
||||
~scheduling_adpator()
|
||||
{
|
||||
this->close();
|
||||
_scheduler.join();
|
||||
}
|
||||
|
||||
Executor& underlying_executor()
|
||||
{
|
||||
return _exec;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef detail::scheduled_executor_base super;
|
||||
void loop();
|
||||
}; //end class
|
||||
|
||||
template<typename Executor>
|
||||
void scheduling_adpator<Executor>::loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
super::work task;
|
||||
queue_op_status st = super::_workq.wait_pull(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
_exec.submit(task);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} //end executors
|
||||
|
||||
using executors::scheduling_adpator;
|
||||
|
||||
} //end boost
|
||||
#endif
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace executors
|
||||
typedef scoped_thread<> thread_t;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
executor& ex;
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
generic_executor_ref ex;
|
||||
thread_t thr;
|
||||
|
||||
struct try_executing_one_task {
|
||||
@@ -43,11 +43,17 @@ namespace executors
|
||||
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||
: task(task), p(p) {}
|
||||
void operator()() {
|
||||
task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
task();
|
||||
p.set_value();
|
||||
}
|
||||
};
|
||||
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.
|
||||
@@ -63,22 +69,14 @@ namespace executors
|
||||
boost::promise<void> p;
|
||||
try_executing_one_task tmp(task,p);
|
||||
ex.submit(tmp);
|
||||
// ex.submit([&task, &p]()
|
||||
// {
|
||||
// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
// p.set_value();
|
||||
// });
|
||||
p.get_future().wait();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +116,8 @@ namespace executors
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
serial_executor(executor& ex)
|
||||
template <class Executor>
|
||||
serial_executor(Executor& ex)
|
||||
: ex(ex), thr(&serial_executor::worker_thread, this)
|
||||
{
|
||||
}
|
||||
@@ -129,7 +128,7 @@ namespace executors
|
||||
*/
|
||||
~serial_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
// signal to the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -166,24 +165,18 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -28,6 +30,11 @@ namespace executors
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
typedef scoped_thread<> thread_t;
|
||||
typedef csbl::vector<thread_t> threads_type;
|
||||
threads_type threads_;
|
||||
mutable mutex mtx_;
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
@@ -52,7 +59,7 @@ namespace executors
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the inline executor.
|
||||
* \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.
|
||||
*/
|
||||
@@ -60,6 +67,7 @@ namespace executors
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
// all the scoped threads will join before destroying
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,16 +76,22 @@ namespace executors
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
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.
|
||||
@@ -95,24 +109,30 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
threads_.reserve(threads_.size() + 1);
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
threads_.push_back(thread_t(boost::move(th)));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
threads_.reserve(threads_.size() + 1);
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
threads_.push_back(thread_t(boost::move(th)));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
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));
|
||||
th.detach();
|
||||
threads_.push_back(thread_t(boost::move(th)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,15 @@
|
||||
#ifndef BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if ! defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE \
|
||||
&& ! defined BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE
|
||||
#define BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE
|
||||
//#define BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
@@ -18,4 +27,17 @@ namespace boost
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#else
|
||||
#include <boost/thread/csbl/functional.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
typedef csbl::function<void()> work;
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
|
||||
# define BOOST_THREAD_INLINE_NAMESPACE(name) inline namespace name
|
||||
#else
|
||||
# define BOOST_THREAD_INLINE_NAMESPACE(name) namespace name
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
16
include/boost/thread/experimental/exception_list.hpp
Normal file
16
include/boost/thread/experimental/exception_list.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/parallel/v1/exception_list.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/experimental/parallel/v1/inline_namespace.hpp>
|
||||
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <exception>
|
||||
#include <list>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v1)
|
||||
{
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE exception_list: public std::exception
|
||||
{
|
||||
typedef std::list<exception_ptr> exception_ptr_list;
|
||||
exception_ptr_list list_;
|
||||
public:
|
||||
typedef exception_ptr_list::const_iterator const_iterator;
|
||||
|
||||
~exception_list() BOOST_NOEXCEPT_OR_NOTHROW {}
|
||||
|
||||
void add(exception_ptr const& e)
|
||||
{
|
||||
list_.push_back(e);
|
||||
}
|
||||
size_t size() const BOOST_NOEXCEPT
|
||||
{
|
||||
return list_.size();
|
||||
}
|
||||
const_iterator begin() const BOOST_NOEXCEPT
|
||||
{
|
||||
return list_.begin();
|
||||
}
|
||||
const_iterator end() const BOOST_NOEXCEPT
|
||||
{
|
||||
return list_.end();
|
||||
}
|
||||
const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
return "exception_list";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/config/inline_namespace.hpp>
|
||||
namespace boost {
|
||||
namespace experimental {
|
||||
namespace parallel {
|
||||
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v1) {}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
|
||||
using namespace v1;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/config/inline_namespace.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace experimental {
|
||||
namespace parallel {
|
||||
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v2) {}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
|
||||
using namespace v2;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
316
include/boost/thread/experimental/parallel/v2/task_region.hpp
Executable file
316
include/boost/thread/experimental/parallel/v2/task_region.hpp
Executable file
@@ -0,0 +1,316 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#endif
|
||||
#include <boost/thread/experimental/exception_list.hpp>
|
||||
#include <boost/thread/experimental/parallel/v2/inline_namespace.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#define BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v2)
|
||||
{
|
||||
class BOOST_SYMBOL_VISIBLE task_canceled_exception: public std::exception
|
||||
{
|
||||
public:
|
||||
//task_canceled_exception() BOOST_NOEXCEPT {}
|
||||
//task_canceled_exception(const task_canceled_exception&) BOOST_NOEXCEPT {}
|
||||
//task_canceled_exception& operator=(const task_canceled_exception&) BOOST_NOEXCEPT {}
|
||||
virtual const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return "task_canceled_exception";}
|
||||
};
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void handle_task_region_exceptions(exception_list& errors)
|
||||
{
|
||||
try {
|
||||
boost::rethrow_exception(boost::current_exception());
|
||||
//throw boost::current_exception();
|
||||
}
|
||||
catch (task_canceled_exception& ex)
|
||||
{
|
||||
}
|
||||
catch (exception_list const& el)
|
||||
{
|
||||
for (boost::exception_ptr const& e: el)
|
||||
{
|
||||
try {
|
||||
rethrow_exception(e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
handle_task_region_exceptions(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
errors.add(boost::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
template <class TRH, class F>
|
||||
struct wrapped
|
||||
{
|
||||
TRH& tr;
|
||||
F f;
|
||||
wrapped(TRH& tr, F&& f) : tr(tr), f(move(f))
|
||||
{}
|
||||
void operator()()
|
||||
{
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
lock_guard<mutex> lk(tr.mtx);
|
||||
tr.canceled = true;
|
||||
handle_task_region_exceptions(tr.exs);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen
|
||||
{
|
||||
private:
|
||||
// Private members and friends
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
template <class TRH, class F>
|
||||
friend struct detail::wrapped;
|
||||
#endif
|
||||
template <typename F>
|
||||
friend void task_region(F&& f);
|
||||
template<typename F>
|
||||
friend void task_region_final(F&& f);
|
||||
template <class Ex, typename F>
|
||||
friend void task_region(Ex&, F&& f);
|
||||
template<class Ex, typename F>
|
||||
friend void task_region_final(Ex&, F&& f);
|
||||
|
||||
void wait_all()
|
||||
{
|
||||
wait_for_all(group.begin(), group.end());
|
||||
|
||||
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
|
||||
for (future<void>& f: group)
|
||||
{
|
||||
if (f.has_exception())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::rethrow_exception(f.get_exception_ptr());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
detail::handle_task_region_exceptions(exs);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (exs.size() != 0)
|
||||
{
|
||||
boost::throw_exception(exs);
|
||||
//throw exs;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
: canceled(false)
|
||||
, ex(0)
|
||||
{}
|
||||
task_region_handle_gen(Executor& ex)
|
||||
: canceled(false)
|
||||
, ex(&ex)
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
: ex(0)
|
||||
{}
|
||||
task_region_handle_gen(Executor& ex)
|
||||
: ex(&ex)
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
: canceled(false)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
~task_region_handle_gen()
|
||||
{
|
||||
//wait_all();
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
bool canceled;
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
Executor* ex;
|
||||
#endif
|
||||
exception_list exs;
|
||||
csbl::vector<future<void>> group;
|
||||
mutable mutex mtx;
|
||||
|
||||
|
||||
public:
|
||||
task_region_handle_gen(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen& operator=(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen* operator&() const = delete;
|
||||
|
||||
template<typename F>
|
||||
void run(F&& f)
|
||||
{
|
||||
lock_guard<mutex> lk(mtx);
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
if (canceled) {
|
||||
boost::throw_exception(task_canceled_exception());
|
||||
//throw task_canceled_exception();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
||||
#else
|
||||
group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
||||
#endif
|
||||
#else
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
group.push_back(async(*ex, forward<F>(f)));
|
||||
#else
|
||||
group.push_back(async(forward<F>(f)));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx);
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
if (canceled) {
|
||||
boost::throw_exception(task_canceled_exception());
|
||||
//throw task_canceled_exception{};
|
||||
}
|
||||
#endif
|
||||
wait_all();
|
||||
}
|
||||
};
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
typedef basic_thread_pool default_executor;
|
||||
#else
|
||||
typedef int default_executor;
|
||||
#endif
|
||||
class task_region_handle :
|
||||
public task_region_handle_gen<default_executor>
|
||||
{
|
||||
default_executor tp;
|
||||
template <typename F>
|
||||
friend void task_region(F&& f);
|
||||
template<typename F>
|
||||
friend void task_region_final(F&& f);
|
||||
|
||||
protected:
|
||||
task_region_handle() : task_region_handle_gen<default_executor>()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
ex = &tp;
|
||||
#endif
|
||||
}
|
||||
task_region_handle(const task_region_handle&) = delete;
|
||||
task_region_handle& operator=(const task_region_handle&) = delete;
|
||||
task_region_handle* operator&() const = delete;
|
||||
|
||||
};
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f)
|
||||
{
|
||||
task_region_handle_gen<Executor> tr(ex);
|
||||
try
|
||||
{
|
||||
f(tr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
lock_guard<mutex> lk(tr.mtx);
|
||||
detail::handle_task_region_exceptions(tr.exs);
|
||||
}
|
||||
tr.wait_all();
|
||||
}
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f)
|
||||
{
|
||||
task_region_final(ex, forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void task_region_final(F&& f)
|
||||
{
|
||||
task_region_handle tr;
|
||||
try
|
||||
{
|
||||
f(tr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
lock_guard<mutex> lk(tr.mtx);
|
||||
detail::handle_task_region_exceptions(tr.exs);
|
||||
}
|
||||
tr.wait_all();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void task_region(F&& f)
|
||||
{
|
||||
task_region_final(forward<F>(f));
|
||||
}
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
16
include/boost/thread/experimental/task_region.hpp
Normal file
16
include/boost/thread/experimental/task_region.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/parallel/v2/task_region.hpp>
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,14 +27,14 @@ namespace boost
|
||||
/// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero.
|
||||
/// Returns: true if count_ reached the value 0.
|
||||
/// @ThreadSafe ensured by the @c lk parameter
|
||||
bool count_down(unique_lock<mutex> &lk)
|
||||
bool count_down(unique_lock<mutex> &)
|
||||
/// pre_condition (count_ > 0)
|
||||
{
|
||||
BOOST_ASSERT(count_ > 0);
|
||||
if (--count_ == 0)
|
||||
{
|
||||
++generation_;
|
||||
lk.unlock();
|
||||
//lk.unlock();
|
||||
cond_.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace boost
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013. Distributed under the Boost
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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)
|
||||
//
|
||||
@@ -11,723 +11,6 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
|
||||
{ success = 0, empty, full, closed, busy }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
#endif
|
||||
|
||||
struct sync_queue_is_closed : std::exception
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_bounded_queue)
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type capacity() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
condition_variable not_full_;
|
||||
size_type waiting_full_;
|
||||
size_type waiting_empty_;
|
||||
value_type* data_;
|
||||
size_type in_;
|
||||
size_type out_;
|
||||
size_type capacity_;
|
||||
bool closed_;
|
||||
|
||||
inline size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (idx + 1) % capacity_;
|
||||
}
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity_-1;
|
||||
}
|
||||
inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT
|
||||
{
|
||||
if (full(lk)) return capacity(lk);
|
||||
return ((out_+capacity(lk)-in_) % capacity(lk));
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>&) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
inline void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_full_ > 0)
|
||||
{
|
||||
--waiting_full_;
|
||||
lk.unlock();
|
||||
not_full_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
|
||||
inline void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
in_ = in;
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = elem;
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = boost::move(elem);
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) :
|
||||
waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
closed_(false)
|
||||
{
|
||||
BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) :
|
||||
// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
// closed_(false)
|
||||
// {
|
||||
// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size");
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// size_type in = 0;
|
||||
// for (iterator_t cur = first; cur != end; ++cur, ++in)
|
||||
// {
|
||||
// data_[in] = *cur;
|
||||
// }
|
||||
// set_in(in);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::~sync_bounded_queue()
|
||||
{
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
not_full_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::full() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return full(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return capacity(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
// template <typename ValueType>
|
||||
// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
// {
|
||||
// unique_lock<mutex> lk(mtx_);
|
||||
// wait_until_not_empty(lk, closed);
|
||||
// if (closed) {return;}
|
||||
// pull(elem, lk);
|
||||
// }
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 != out_) // ! full()
|
||||
{
|
||||
return in_p_1;
|
||||
}
|
||||
++waiting_full_;
|
||||
not_full_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_bounded_queue.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013. Distributed under the Boost
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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)
|
||||
//
|
||||
@@ -11,651 +11,6 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
#include <boost/thread/csbl/deque.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef csbl::deque<ValueType> underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef queue_op_status op_status;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue)
|
||||
inline sync_queue();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
inline void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
inline underlying_queue_type underlying_queue() {
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return boost::move(data_);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
size_type waiting_empty_;
|
||||
underlying_queue_type data_;
|
||||
bool closed_;
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>& lk) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front()));
|
||||
data_.pop_front();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(data_.front());
|
||||
data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(elem);
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(boost::move(elem));
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
#endif
|
||||
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(elem);
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_.push_back(boost::move(elem));
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::sync_queue() :
|
||||
waiting_empty_(0), data_(), closed_(false)
|
||||
{
|
||||
BOOST_ASSERT(data_.empty());
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// explicit sync_queue<ValueType>::sync_queue(Range range) :
|
||||
// waiting_empty_(0), data_(), closed_(false)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// for (iterator_t cur = first; cur != end; ++cur)
|
||||
// {
|
||||
// data_.push(boost::move(*cur));;
|
||||
// }
|
||||
// notify_not_empty_if_needed(lk);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::~sync_queue()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::closed(unique_lock<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::full() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_queue<ValueType>::size_type sync_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = false;
|
||||
wait_until_not_empty(lk, has_been_closed);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
closed=false;
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk, closed);
|
||||
if (closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
throw_if_closed(lk);
|
||||
push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,10 +19,10 @@ namespace boost
|
||||
{
|
||||
virtual ~tss_cleanup_function()
|
||||
{}
|
||||
|
||||
|
||||
virtual void operator()(void* data)=0;
|
||||
};
|
||||
|
||||
|
||||
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
|
||||
BOOST_THREAD_DECL void* get_tss_data(void const* key);
|
||||
}
|
||||
@@ -42,16 +42,16 @@ namespace boost
|
||||
delete static_cast<T*>(data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct run_custom_cleanup_function:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void (*cleanup_function)(T*);
|
||||
|
||||
|
||||
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
|
||||
cleanup_function(cleanup_function_)
|
||||
{}
|
||||
|
||||
|
||||
void operator()(void* data)
|
||||
{
|
||||
cleanup_function(static_cast<T*>(data));
|
||||
@@ -60,10 +60,10 @@ namespace boost
|
||||
|
||||
|
||||
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
|
||||
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
|
||||
thread_specific_ptr():
|
||||
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
|
||||
{}
|
||||
@@ -87,7 +87,7 @@ namespace boost
|
||||
{
|
||||
return get();
|
||||
}
|
||||
T& operator*() const
|
||||
typename boost::detail::sp_dereference< T >::type operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace boost
|
||||
|
||||
do
|
||||
{
|
||||
unsigned const retval(win32::WaitForSingleObject(sem, ::boost::detail::win32::infinite));
|
||||
unsigned const retval(win32::WaitForSingleObjectEx(sem, ::boost::detail::win32::infinite,0));
|
||||
BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval);
|
||||
// BOOST_VERIFY(win32::WaitForSingleObject(
|
||||
// sem,::boost::detail::win32::infinite)==0);
|
||||
@@ -142,7 +142,7 @@ namespace boost
|
||||
|
||||
do
|
||||
{
|
||||
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
|
||||
if(win32::WaitForSingleObjectEx(sem,::boost::detail::get_milliseconds_until(wait_until),0)!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
@@ -203,9 +203,14 @@ namespace boost
|
||||
|
||||
do
|
||||
{
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
chrono::time_point<chrono::system_clock, chrono::system_clock::duration> now = chrono::system_clock::now();
|
||||
if (tp<=now) {
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-now);
|
||||
|
||||
if(win32::WaitForSingleObject(sem,static_cast<unsigned long>(rel_time.count()))!=0)
|
||||
if(win32::WaitForSingleObjectEx(sem,static_cast<unsigned long>(rel_time.count()),0)!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace boost
|
||||
|
||||
bool woken()
|
||||
{
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0);
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0);
|
||||
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
|
||||
return woken_result==0;
|
||||
}
|
||||
|
||||
@@ -17,34 +17,29 @@
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
extern "C" void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// Since VS2005 volatile reads always acquire
|
||||
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
|
||||
{
|
||||
long const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
|
||||
{
|
||||
void* const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
// Since VS2005 volatile writes always release
|
||||
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,14 +152,11 @@ namespace boost
|
||||
{
|
||||
name_once_mutex(mutex_name,flag_address);
|
||||
}
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
return ::boost::detail::win32::CreateEventW(
|
||||
#else
|
||||
return ::boost::detail::win32::CreateEventA(
|
||||
#endif
|
||||
0,::boost::detail::win32::manual_reset_event,
|
||||
::boost::detail::win32::event_initially_reset,
|
||||
mutex_name);
|
||||
|
||||
return ::boost::detail::win32::create_event(
|
||||
mutex_name,
|
||||
::boost::detail::win32::manual_reset_event,
|
||||
::boost::detail::win32::event_initially_reset);
|
||||
}
|
||||
|
||||
struct once_context {
|
||||
@@ -267,8 +264,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite, 0));
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
@@ -311,8 +308,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, class A, class ...ArgTypes>
|
||||
@@ -358,8 +355,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -403,8 +400,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1>
|
||||
@@ -446,8 +443,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
@@ -489,8 +486,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
@@ -532,8 +529,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
#elif defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
@@ -577,8 +574,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1>
|
||||
@@ -620,8 +617,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
@@ -663,8 +660,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
@@ -706,8 +703,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -751,8 +748,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename T1>
|
||||
@@ -796,8 +793,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
@@ -842,8 +839,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
@@ -889,8 +886,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -933,8 +930,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,8 +977,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2>
|
||||
@@ -1027,8 +1024,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
template<typename Function, typename T1, typename T2, typename T3>
|
||||
@@ -1076,8 +1073,8 @@ namespace boost
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
ctx.event_handle,::boost::detail::win32::infinite));
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
|
||||
ctx.event_handle,::boost::detail::win32::infinite,0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,13 @@ namespace boost
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
void release_shared_waiters(state_data old_state)
|
||||
{
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(shared_mutex)
|
||||
@@ -184,7 +190,7 @@ namespace boost
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
|
||||
unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
@@ -289,8 +295,8 @@ namespace boost
|
||||
unsigned long res;
|
||||
if (tp>n) {
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
|
||||
res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],
|
||||
static_cast<unsigned long>(rel_time.count()));
|
||||
res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],
|
||||
static_cast<unsigned long>(rel_time.count()), 0);
|
||||
} else {
|
||||
res=detail::win32::timeout;
|
||||
}
|
||||
@@ -466,7 +472,7 @@ namespace boost
|
||||
#else
|
||||
const bool wait_all = false;
|
||||
#endif
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until));
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
@@ -578,8 +584,8 @@ namespace boost
|
||||
unsigned long wait_res;
|
||||
if (tp>n) {
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,
|
||||
static_cast<unsigned long>(rel_time.count()));
|
||||
wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,
|
||||
static_cast<unsigned long>(rel_time.count()), 0);
|
||||
} else {
|
||||
wait_res=detail::win32::timeout;
|
||||
}
|
||||
@@ -690,7 +696,7 @@ namespace boost
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,6 +756,9 @@ namespace boost
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
else {
|
||||
release_shared_waiters(old_state);
|
||||
}
|
||||
// #7720
|
||||
//else {
|
||||
// release_waiters(old_state);
|
||||
@@ -779,7 +788,7 @@ namespace boost
|
||||
{
|
||||
if(!last_reader)
|
||||
{
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/thread_heap_alloc.hpp>
|
||||
|
||||
#include <boost/predef/platform.h>
|
||||
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
@@ -93,10 +95,18 @@ namespace boost
|
||||
struct BOOST_THREAD_DECL thread_data_base
|
||||
{
|
||||
long count;
|
||||
|
||||
// Win32 threading APIs are not available in store apps so
|
||||
// use abstraction on top of Windows::System::Threading.
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
detail::win32::scoped_winrt_thread thread_handle;
|
||||
#else
|
||||
detail::win32::handle_manager thread_handle;
|
||||
#endif
|
||||
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
std::map<void const*,boost::detail::tss_data_node> tss_data;
|
||||
unsigned id;
|
||||
std::map<void const*,boost::detail::tss_data_node> tss_data;
|
||||
typedef std::vector<std::pair<condition_variable*, mutex*>
|
||||
//, hidden_allocator<std::pair<condition_variable*, mutex*> >
|
||||
> notify_list_t;
|
||||
@@ -113,9 +123,11 @@ namespace boost
|
||||
//#endif
|
||||
|
||||
thread_data_base():
|
||||
count(0),thread_handle(detail::win32::invalid_handle_value),
|
||||
thread_exit_callbacks(0),tss_data(),
|
||||
count(0),
|
||||
thread_handle(),
|
||||
thread_exit_callbacks(0),
|
||||
id(0),
|
||||
tss_data(),
|
||||
notify(),
|
||||
async_states_()
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
@@ -173,14 +185,15 @@ namespace boost
|
||||
static unsigned long const max_non_infinite_wait=0xfffffffe;
|
||||
|
||||
timeout(uintmax_t milliseconds_):
|
||||
start(win32::GetTickCount64()()),
|
||||
start(win32::GetTickCount64_()()),
|
||||
milliseconds(milliseconds_),
|
||||
relative(true),
|
||||
abs_time(boost::get_system_time())
|
||||
relative(true)
|
||||
//,
|
||||
// abs_time(boost::get_system_time())
|
||||
{}
|
||||
|
||||
timeout(boost::system_time const& abs_time_):
|
||||
start(win32::GetTickCount64()()),
|
||||
start(win32::GetTickCount64_()()),
|
||||
milliseconds(0),
|
||||
relative(false),
|
||||
abs_time(abs_time_)
|
||||
@@ -205,7 +218,7 @@ namespace boost
|
||||
}
|
||||
else if(relative)
|
||||
{
|
||||
win32::ticks_type const now=win32::GetTickCount64()();
|
||||
win32::ticks_type const now=win32::GetTickCount64_()();
|
||||
win32::ticks_type const elapsed=now-start;
|
||||
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/predef/platform.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
@@ -18,6 +19,10 @@
|
||||
//#include <boost/detail/winapi/synchronization.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
@@ -28,40 +33,60 @@ namespace boost
|
||||
namespace win32
|
||||
{
|
||||
typedef HANDLE handle;
|
||||
typedef SYSTEM_INFO system_info;
|
||||
typedef unsigned __int64 ticks_type;
|
||||
unsigned const infinite=INFINITE;
|
||||
unsigned const timeout=WAIT_TIMEOUT;
|
||||
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
||||
unsigned const event_modify_state=EVENT_MODIFY_STATE;
|
||||
unsigned const synchronize=SYNCHRONIZE;
|
||||
unsigned const wait_abandoned=WAIT_ABANDONED;
|
||||
|
||||
unsigned const create_event_initial_set = 0x00000002;
|
||||
unsigned const create_event_manual_reset = 0x00000001;
|
||||
unsigned const event_all_access = EVENT_ALL_ACCESS;
|
||||
unsigned const semaphore_all_access = SEMAPHORE_ALL_ACCESS;
|
||||
|
||||
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
# if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
|
||||
using ::CreateMutexW;
|
||||
using ::CreateEventW;
|
||||
using ::OpenEventW;
|
||||
using ::CreateSemaphoreW;
|
||||
# else
|
||||
using ::CreateMutexExW;
|
||||
using ::CreateEventExW;
|
||||
using ::CreateSemaphoreExW;
|
||||
# endif
|
||||
using ::OpenEventW;
|
||||
# else
|
||||
using ::CreateMutexA;
|
||||
using ::CreateEventA;
|
||||
using ::OpenEventA;
|
||||
using ::CreateSemaphoreA;
|
||||
# endif
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
using ::GetNativeSystemInfo;
|
||||
using ::GetTickCount64;
|
||||
#else
|
||||
using ::GetSystemInfo;
|
||||
#endif
|
||||
using ::CloseHandle;
|
||||
using ::ReleaseMutex;
|
||||
using ::ReleaseSemaphore;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
using ::WaitForMultipleObjects;
|
||||
using ::WaitForSingleObject;
|
||||
using ::WaitForMultipleObjectsEx;
|
||||
using ::WaitForSingleObjectEx;
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::DuplicateHandle;
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
using ::SleepEx;
|
||||
using ::Sleep;
|
||||
using ::QueueUserAPC;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,13 +107,19 @@ extern "C" {
|
||||
typedef int BOOL;
|
||||
typedef unsigned long DWORD;
|
||||
typedef void* HANDLE;
|
||||
|
||||
# include <kfuncs.h>
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
struct _SYSTEM_INFO;
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -102,20 +133,32 @@ namespace boost
|
||||
typedef unsigned long ulong_ptr;
|
||||
# endif
|
||||
typedef void* handle;
|
||||
typedef _SYSTEM_INFO system_info;
|
||||
typedef unsigned __int64 ticks_type;
|
||||
unsigned const infinite=~0U;
|
||||
unsigned const timeout=258U;
|
||||
handle const invalid_handle_value=(handle)(-1);
|
||||
unsigned const event_modify_state=2;
|
||||
unsigned const synchronize=0x100000u;
|
||||
unsigned const wait_abandoned=0x00000080u;
|
||||
unsigned const create_event_initial_set = 0x00000002;
|
||||
unsigned const create_event_manual_reset = 0x00000001;
|
||||
unsigned const event_all_access = 0x1F0003;
|
||||
unsigned const semaphore_all_access = 0x1F0003;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
# if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
|
||||
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
|
||||
# else
|
||||
__declspec(dllimport) void* __stdcall CreateMutexExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long);
|
||||
__declspec(dllimport) void* __stdcall CreateEventExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreExW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*,unsigned long,unsigned long);
|
||||
# endif
|
||||
__declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
|
||||
# else
|
||||
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
|
||||
@@ -123,16 +166,24 @@ namespace boost
|
||||
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
|
||||
__declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*);
|
||||
# endif
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
__declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*);
|
||||
__declspec(dllimport) ticks_type __stdcall GetTickCount64();
|
||||
#else
|
||||
__declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*);
|
||||
#endif
|
||||
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
||||
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObjectEx(void*,unsigned long,int);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjectsEx(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds,int bAlertable);
|
||||
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
|
||||
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
|
||||
__declspec(dllimport) void __stdcall Sleep(unsigned long);
|
||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
#endif
|
||||
|
||||
# ifndef UNDER_CE
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
@@ -165,19 +216,26 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
typedef unsigned __int64 ticks_type;
|
||||
namespace detail { typedef int (__stdcall *farproc_t)(); typedef ticks_type (__stdcall *gettickcount64_t)(); }
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *);
|
||||
__declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *);
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
__declspec(dllimport) void * __stdcall GetModuleHandleA(const char *);
|
||||
__declspec(dllimport) void * __stdcall GetModuleHandleA(const char *);
|
||||
#else
|
||||
__declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *);
|
||||
__declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *);
|
||||
#endif
|
||||
int __stdcall GetTickCount();
|
||||
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||
#ifdef _MSC_VER
|
||||
long _InterlockedCompareExchange(long volatile *, long, long);
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
#elif defined(__MINGW64_VERSION_MAJOR)
|
||||
long _InterlockedCompareExchange(long volatile *, long, long);
|
||||
#else
|
||||
// Mingw doesn't provide intrinsics
|
||||
#define _InterlockedCompareExchange InterlockedCompareExchange
|
||||
#endif
|
||||
}
|
||||
// Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
|
||||
inline ticks_type __stdcall GetTickCount64emulation()
|
||||
@@ -227,11 +285,19 @@ namespace boost
|
||||
// Oops, we weren't called often enough, we're stuck
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
inline detail::gettickcount64_t GetTickCount64()
|
||||
#else
|
||||
#endif
|
||||
inline detail::gettickcount64_t GetTickCount64_()
|
||||
{
|
||||
static detail::gettickcount64_t gettickcount64impl;
|
||||
if(gettickcount64impl)
|
||||
return gettickcount64impl;
|
||||
|
||||
// GetTickCount and GetModuleHandle are not allowed in the Windows Runtime,
|
||||
// and kernel32 isn't used in Windows Phone.
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
gettickcount64impl = &GetTickCount64;
|
||||
#else
|
||||
detail::farproc_t addr=GetProcAddress(
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
GetModuleHandleA("KERNEL32.DLL"),
|
||||
@@ -243,10 +309,11 @@ namespace boost
|
||||
gettickcount64impl=(detail::gettickcount64_t) addr;
|
||||
else
|
||||
gettickcount64impl=&GetTickCount64emulation;
|
||||
#endif
|
||||
return gettickcount64impl;
|
||||
}
|
||||
|
||||
enum event_type
|
||||
enum event_type
|
||||
{
|
||||
auto_reset_event=false,
|
||||
manual_reset_event=true
|
||||
@@ -258,13 +325,32 @@ namespace boost
|
||||
event_initially_set=true
|
||||
};
|
||||
|
||||
inline handle create_anonymous_event(event_type type,initial_event_state state)
|
||||
inline handle create_event(
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
const char *mutex_name,
|
||||
#else
|
||||
const wchar_t *mutex_name,
|
||||
#endif
|
||||
event_type type,
|
||||
initial_event_state state)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=win32::CreateEventA(0,type,state,0);
|
||||
handle const res = win32::CreateEventA(0, type, state, mutex_name);
|
||||
#elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
|
||||
handle const res = win32::CreateEventW(0, type, state, mutex_name);
|
||||
#else
|
||||
handle const res=win32::CreateEventW(0,type,state,0);
|
||||
handle const res = win32::CreateEventExW(
|
||||
0,
|
||||
mutex_name,
|
||||
type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0,
|
||||
event_all_access);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_event(event_type type,initial_event_state state)
|
||||
{
|
||||
handle const res = create_event(0, type, state);
|
||||
if(!res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
@@ -272,28 +358,29 @@ namespace boost
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
|
||||
handle const res=win32::CreateSemaphoreA(0,initial_count,max_count,0);
|
||||
#else
|
||||
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
|
||||
#if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
|
||||
handle const res=win32::CreateSemaphoreEx(0,initial_count,max_count,0,0);
|
||||
#else
|
||||
handle const res=win32::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access);
|
||||
#endif
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
{
|
||||
handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count);
|
||||
if(!res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
|
||||
#else
|
||||
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle duplicate_handle(handle source)
|
||||
{
|
||||
@@ -312,7 +399,64 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
|
||||
}
|
||||
|
||||
inline void get_system_info(system_info *info)
|
||||
{
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
win32::GetNativeSystemInfo(info);
|
||||
#else
|
||||
win32::GetSystemInfo(info);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void sleep(unsigned long milliseconds)
|
||||
{
|
||||
if(milliseconds == 0)
|
||||
{
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
std::this_thread::yield();
|
||||
#else
|
||||
::boost::detail::win32::Sleep(0);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
::boost::detail::win32::WaitForSingleObjectEx(::boost::detail::win32::GetCurrentThread(), milliseconds, 0);
|
||||
#else
|
||||
::boost::detail::win32::Sleep(milliseconds);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
class BOOST_THREAD_DECL scoped_winrt_thread
|
||||
{
|
||||
public:
|
||||
scoped_winrt_thread() : m_completionHandle(invalid_handle_value)
|
||||
{}
|
||||
|
||||
~scoped_winrt_thread()
|
||||
{
|
||||
if (m_completionHandle != ::boost::detail::win32::invalid_handle_value)
|
||||
{
|
||||
CloseHandle(m_completionHandle);
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned(__stdcall * thread_func)(void *);
|
||||
bool start(thread_func address, void *parameter, unsigned int *thrdId);
|
||||
|
||||
handle waitable_handle() const
|
||||
{
|
||||
BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value);
|
||||
return m_completionHandle;
|
||||
}
|
||||
|
||||
private:
|
||||
handle m_completionHandle;
|
||||
};
|
||||
#endif
|
||||
class BOOST_THREAD_DECL handle_manager
|
||||
{
|
||||
private:
|
||||
@@ -375,7 +519,6 @@ namespace boost
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,12 @@ namespace boost {
|
||||
* );
|
||||
*/
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(
|
||||
typename boost::result_of<Function(Args...)>::type with_lock_guard(
|
||||
Lockable& m,
|
||||
BOOST_FWD_REF(Function) func,
|
||||
BOOST_FWD_REF(Args)... args
|
||||
) -> decltype(func(boost::forward<Args>(args)...)) {
|
||||
) //-> decltype(func(boost::forward<Args>(args)...))
|
||||
{
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
@@ -33,6 +32,19 @@
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <boost/predef/platform.h>
|
||||
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <Activation.h>
|
||||
#include <wrl\client.h>
|
||||
#include <wrl\event.h>
|
||||
#include <wrl\wrappers\corewrappers.h>
|
||||
#include <wrl\ftm.h>
|
||||
#include <windows.system.threading.h>
|
||||
#pragma comment(lib, "runtimeobject.lib")
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -65,50 +77,67 @@ namespace boost
|
||||
// Windows CE does not define the TLS_OUT_OF_INDEXES constant.
|
||||
#define TLS_OUT_OF_INDEXES 0xFFFFFFFF
|
||||
#endif
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
|
||||
#else
|
||||
__declspec(thread) boost::detail::thread_data_base* current_thread_data_base;
|
||||
#endif
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
current_thread_tls_key=TlsAlloc();
|
||||
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cleanup_tls_key()
|
||||
{
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
TlsFree(current_thread_tls_key);
|
||||
current_thread_tls_key=TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
if (current_thread_tls_key!=TLS_OUT_OF_INDEXES)
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
current_thread_data_base = new_data;
|
||||
#else
|
||||
if (current_thread_tls_key != TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
|
||||
BOOST_VERIFY(TlsSetValue(current_thread_tls_key, new_data));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_VERIFY(false);
|
||||
//boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
thread_data_base* get_current_thread_data()
|
||||
{
|
||||
if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
return current_thread_data_base;
|
||||
#else
|
||||
if (current_thread_tls_key == TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifndef BOOST_HAS_THREADEX
|
||||
@@ -165,6 +194,66 @@ namespace boost
|
||||
|
||||
}
|
||||
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
namespace detail
|
||||
{
|
||||
std::atomic_uint threadCount;
|
||||
|
||||
bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IThreadPoolStatics> threadPoolFactory;
|
||||
HRESULT hr = ::Windows::Foundation::GetActivationFactory(
|
||||
Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(),
|
||||
&threadPoolFactory);
|
||||
if (hr != S_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create event for tracking work item completion.
|
||||
*thrdId = ++threadCount;
|
||||
handle completionHandle = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
|
||||
if (!completionHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_completionHandle = completionHandle;
|
||||
|
||||
// Create new work item.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IWorkItemHandler> workItem =
|
||||
Microsoft::WRL::Callback<Microsoft::WRL::Implements<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::System::Threading::IWorkItemHandler, Microsoft::WRL::FtmBase>>
|
||||
([address, parameter, completionHandle](ABI::Windows::Foundation::IAsyncAction *)
|
||||
{
|
||||
// Add a reference since we need to access the completionHandle after the thread_start_function.
|
||||
// This is to handle cases where detach() was called and run_thread_exit_callbacks() would end
|
||||
// up closing the handle.
|
||||
::boost::detail::thread_data_base* const thread_info(reinterpret_cast<::boost::detail::thread_data_base*>(parameter));
|
||||
intrusive_ptr_add_ref(thread_info);
|
||||
|
||||
__try
|
||||
{
|
||||
address(parameter);
|
||||
}
|
||||
__finally
|
||||
{
|
||||
SetEvent(completionHandle);
|
||||
intrusive_ptr_release(thread_info);
|
||||
}
|
||||
return S_OK;
|
||||
});
|
||||
|
||||
// Schedule work item on the threadpool.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncAction;
|
||||
hr = threadPoolFactory->RunWithPriorityAndOptionsAsync(
|
||||
workItem.Get(),
|
||||
ABI::Windows::System::Threading::WorkItemPriority_Normal,
|
||||
ABI::Windows::System::Threading::WorkItemOptions_TimeSliced,
|
||||
&asyncAction);
|
||||
return hr == S_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
void run_thread_exit_callbacks()
|
||||
@@ -199,7 +288,6 @@ namespace boost
|
||||
current_thread_data->tss_data.erase(current);
|
||||
}
|
||||
}
|
||||
|
||||
set_current_thread_data(0);
|
||||
}
|
||||
}
|
||||
@@ -236,6 +324,16 @@ namespace boost
|
||||
|
||||
bool thread::start_thread_noexcept()
|
||||
{
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
intrusive_ptr_add_ref(thread_info.get());
|
||||
if (!thread_info->thread_handle.start(&thread_start_function, thread_info.get(), &thread_info->id))
|
||||
{
|
||||
intrusive_ptr_release(thread_info.get());
|
||||
// boost::throw_exception(thread_resource_error());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
if(!new_thread)
|
||||
{
|
||||
@@ -246,10 +344,16 @@ namespace boost
|
||||
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
||||
ResumeThread(thread_info->thread_handle);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool thread::start_thread_noexcept(const attributes& attr)
|
||||
{
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
// Stack size isn't supported with Windows Runtime.
|
||||
attr;
|
||||
return start_thread_noexcept();
|
||||
#else
|
||||
//uintptr_t const new_thread=_beginthreadex(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
if(!new_thread)
|
||||
@@ -261,8 +365,9 @@ namespace boost
|
||||
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
||||
ResumeThread(thread_info->thread_handle);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
thread::thread(detail::thread_data_ptr data):
|
||||
thread_info(data)
|
||||
{}
|
||||
@@ -321,31 +426,37 @@ namespace boost
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
return local_thread_info?local_thread_info->id:0;
|
||||
//return const_cast<thread*>(this)->native_handle();
|
||||
#else
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(!local_thread_info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return local_thread_info->id;
|
||||
#else
|
||||
return thread::id((get_thread_info)());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool thread::joinable() const BOOST_NOEXCEPT
|
||||
{
|
||||
return (get_thread_info)() ? true : false;
|
||||
detail::thread_data_ptr local_thread_info = (get_thread_info)();
|
||||
if(!local_thread_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool thread::join_noexcept()
|
||||
{
|
||||
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
|
||||
this_thread::interruptible_wait(this->native_handle(),detail::timeout::sentinel());
|
||||
release_handle();
|
||||
return true;
|
||||
}
|
||||
@@ -366,7 +477,7 @@ namespace boost
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,milli))
|
||||
if(!this_thread::interruptible_wait(this->native_handle(),milli))
|
||||
{
|
||||
res=false;
|
||||
return true;
|
||||
@@ -404,21 +515,23 @@ namespace boost
|
||||
bool thread::interruption_requested() const BOOST_NOEXCEPT
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
||||
return local_thread_info.get() && (detail::win32::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
//SYSTEM_INFO info={{0}};
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
detail::win32::system_info info;
|
||||
detail::win32::get_system_info(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
return hardware_concurrency();
|
||||
#else
|
||||
unsigned cores = 0;
|
||||
#if !(defined(__MINGW32__) || defined (__MINGW64__))
|
||||
DWORD size = 0;
|
||||
@@ -439,12 +552,22 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
return cores;
|
||||
#endif
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
|
||||
if(!local_thread_info)
|
||||
{
|
||||
return detail::win32::invalid_handle_value;
|
||||
}
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
// There is no 'real' Win32 handle so we return a handle that at least can be waited on.
|
||||
return local_thread_info->thread_handle.waitable_handle();
|
||||
#else
|
||||
return (detail::win32::handle)local_thread_info->thread_handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
@@ -461,7 +584,7 @@ namespace boost
|
||||
LARGE_INTEGER due_time={{0,0}};
|
||||
if(target_time.relative)
|
||||
{
|
||||
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64()()-target_time.start;
|
||||
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64_()()-target_time.start;
|
||||
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
|
||||
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
|
||||
|
||||
@@ -535,6 +658,7 @@ namespace boost
|
||||
detail::win32::handle_manager timer_handle;
|
||||
|
||||
#ifndef UNDER_CE
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
unsigned const min_timer_wait_period=20;
|
||||
|
||||
if(!target_time.is_sentinel())
|
||||
@@ -562,6 +686,7 @@ namespace boost
|
||||
target_time=detail::timeout(time_left.milliseconds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool const using_timer=timeout_index!=~0u;
|
||||
@@ -576,7 +701,7 @@ namespace boost
|
||||
|
||||
if(handle_count)
|
||||
{
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
|
||||
if(notified_index<handle_count)
|
||||
{
|
||||
if(notified_index==wait_handle_index)
|
||||
@@ -598,7 +723,7 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::win32::Sleep(time_left.milliseconds);
|
||||
detail::win32::sleep(time_left.milliseconds);
|
||||
}
|
||||
if(target_time.relative)
|
||||
{
|
||||
@@ -625,6 +750,7 @@ namespace boost
|
||||
detail::win32::handle_manager timer_handle;
|
||||
|
||||
#ifndef UNDER_CE
|
||||
#if !BOOST_PLAT_WINDOWS_RUNTIME
|
||||
unsigned const min_timer_wait_period=20;
|
||||
|
||||
if(!target_time.is_sentinel())
|
||||
@@ -652,6 +778,7 @@ namespace boost
|
||||
target_time=detail::timeout(time_left.milliseconds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool const using_timer=timeout_index!=~0u;
|
||||
@@ -666,7 +793,7 @@ namespace boost
|
||||
|
||||
if(handle_count)
|
||||
{
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
|
||||
if(notified_index<handle_count)
|
||||
{
|
||||
if(notified_index==wait_handle_index)
|
||||
@@ -681,7 +808,7 @@ namespace boost
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::win32::Sleep(time_left.milliseconds);
|
||||
detail::win32::sleep(time_left.milliseconds);
|
||||
}
|
||||
if(target_time.relative)
|
||||
{
|
||||
@@ -695,11 +822,18 @@ namespace boost
|
||||
|
||||
thread::id get_id() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
return detail::win32::GetCurrentThreadId();
|
||||
#else
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
|
||||
if (current_thread_data)
|
||||
{
|
||||
return current_thread_data->id;
|
||||
}
|
||||
#endif
|
||||
return detail::win32::GetCurrentThreadId();
|
||||
#else
|
||||
return thread::id(get_or_make_current_thread_data());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
@@ -719,13 +853,13 @@ namespace boost
|
||||
|
||||
bool interruption_requested() BOOST_NOEXCEPT
|
||||
{
|
||||
return detail::get_current_thread_data() && (detail::win32::WaitForSingleObject(detail::get_current_thread_data()->interruption_handle,0)==0);
|
||||
return detail::get_current_thread_data() && (detail::win32::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void yield() BOOST_NOEXCEPT
|
||||
{
|
||||
detail::win32::Sleep(0);
|
||||
detail::win32::sleep(0);
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
@@ -839,6 +973,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_process_enter()
|
||||
{}
|
||||
|
||||
|
||||
152
test/Jamfile.v2
152
test/Jamfile.v2
@@ -49,7 +49,8 @@ project
|
||||
<toolset>pathscale:<cxxflags>-pedantic
|
||||
|
||||
<toolset>clang:<cxxflags>-Wextra
|
||||
<toolset>clang:<cxxflags>-pedantic
|
||||
#<toolset>clang:<cxxflags>-pedantic
|
||||
<toolset>clang:<warnings>on
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive # doesn't work
|
||||
@@ -95,13 +96,12 @@ project
|
||||
<toolset>intel:<cxxflags>-wd193,304,383,444
|
||||
<toolset>intel:<cxxflags>-wd593,981
|
||||
<toolset>intel:<cxxflags>-wd1418
|
||||
<toolset>intel:<cxxflags>-wd2415
|
||||
|
||||
|
||||
<toolset>intel:<cxxflags>-wd2415
|
||||
;
|
||||
|
||||
rule thread-run ( sources )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread ]
|
||||
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
|
||||
@@ -112,6 +112,7 @@ rule thread-run ( sources )
|
||||
|
||||
rule thread-test ( sources )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread : : :
|
||||
<library>/boost/test//boost_unit_test_framework/<link>static
|
||||
@@ -126,6 +127,7 @@ rule thread-test ( sources )
|
||||
|
||||
rule thread-run2 ( sources : name )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread : : :
|
||||
: $(name) ]
|
||||
@@ -137,6 +139,7 @@ rule thread-run2 ( sources : name )
|
||||
|
||||
rule thread-run2-noit ( sources : name )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread : : :
|
||||
: $(name) ]
|
||||
@@ -151,6 +154,7 @@ rule thread-run2-noit ( sources : name )
|
||||
|
||||
rule thread-run2-noit-pthread ( sources : name )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) ../build//boost_thread : : : <threadapi>win32:<build>no
|
||||
: $(name) ]
|
||||
@@ -165,6 +169,7 @@ rule thread-run2-noit-pthread ( sources : name )
|
||||
|
||||
rule thread-run2-h ( sources : name )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) : : :
|
||||
<library>/boost/system//boost_system
|
||||
@@ -177,6 +182,7 @@ rule thread-run2-h ( sources : name )
|
||||
|
||||
rule thread-run-lib2 ( sources : name )
|
||||
{
|
||||
sources = $(sources) winrt_init.cpp ;
|
||||
return
|
||||
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
|
||||
: : :
|
||||
@@ -343,6 +349,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/futures/promise/set_rvalue_pass.cpp : promise__set_rvalue_p ]
|
||||
[ thread-run2-noit ./sync/futures/promise/set_value_const_pass.cpp : promise__set_value_const_p ]
|
||||
[ thread-run2-noit ./sync/futures/promise/set_value_void_pass.cpp : promise__set_value_void_p ]
|
||||
[ thread-run2-noit ./sync/futures/promise/emplace_pass.cpp : promise__emplace_p ]
|
||||
[ thread-run2-noit ./sync/futures/promise/use_allocator_pass.cpp : promise__use_allocator_p ]
|
||||
[ thread-run2-noit ./sync/futures/promise/set_exception_at_thread_exit_pass.cpp : promise__set_exception_at_thread_exit_p ]
|
||||
[ thread-run2-noit ./sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp : promise__set_lvalue_at_thread_exit_p ]
|
||||
@@ -351,6 +358,12 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/futures/promise/set_value_at_thread_exit_void_pass.cpp : promise__set_value_at_thread_exit_void_p ]
|
||||
;
|
||||
|
||||
#explicit ts_make_ready_future ;
|
||||
test-suite ts_make_ready_future
|
||||
:
|
||||
[ thread-run2-noit ./sync/futures/make_ready_future_pass.cpp : make_ready_future_p ]
|
||||
;
|
||||
|
||||
#explicit ts_future ;
|
||||
test-suite ts_future
|
||||
:
|
||||
@@ -367,6 +380,9 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/futures/future/wait_for_pass.cpp : future__wait_for_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/wait_until_pass.cpp : future__wait_until_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/then_pass.cpp : future__then_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/then_executor_pass.cpp : future__then_executor_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/async_deferred_then_pass.cpp : future__async_def_then_p ]
|
||||
[ thread-run2-noit ./sync/futures/future/then_deferred_pass.cpp : future__then_def_p ]
|
||||
;
|
||||
|
||||
#explicit ts_shared_future ;
|
||||
@@ -383,6 +399,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/futures/shared_future/wait_for_pass.cpp : shared_future__wait_for_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/wait_until_pass.cpp : shared_future__wait_until_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/then_pass.cpp : shared_future__then_p ]
|
||||
[ thread-run2-noit ./sync/futures/shared_future/then_executor_pass.cpp : shared_future__then_executor_p ]
|
||||
;
|
||||
|
||||
#explicit ts_packaged_task ;
|
||||
@@ -407,6 +424,24 @@ rule thread-compile ( sources : reqs * : name )
|
||||
;
|
||||
|
||||
|
||||
#explicit ts_when_all ;
|
||||
test-suite ts_when_all
|
||||
:
|
||||
[ thread-run2-noit ./sync/futures/when_all/none_pass.cpp : when_all__none_p ]
|
||||
[ thread-run2-noit ./sync/futures/when_all/one_pass.cpp : when_all__one_p ]
|
||||
[ thread-run2-noit ./sync/futures/when_all/iterators_pass.cpp : when_all__iterators_p ]
|
||||
[ thread-run2-noit ./sync/futures/when_all/variadic_pass.cpp : when_all__variadic_p ]
|
||||
;
|
||||
|
||||
#explicit ts_when_any ;
|
||||
test-suite ts_when_any
|
||||
:
|
||||
[ thread-run2-noit ./sync/futures/when_any/none_pass.cpp : when_any__none_p ]
|
||||
[ thread-run2-noit ./sync/futures/when_any/one_pass.cpp : when_any__one_p ]
|
||||
[ thread-run2-noit ./sync/futures/when_any/iterators_pass.cpp : when_any__iterators_p ]
|
||||
[ thread-run2-noit ./sync/futures/when_any/variadic_pass.cpp : when_any__variadic_p ]
|
||||
;
|
||||
|
||||
#explicit ts_lock_guard ;
|
||||
test-suite ts_lock_guard
|
||||
:
|
||||
@@ -430,10 +465,10 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/duration_pass.cpp : unique_lock__cons__duration_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_assign_pass.cpp : unique_lock__cons__move_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_pass.cpp : unique_lock__cons__move_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_try_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_until_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp : uq_lk_cons_mv_c_upg_lk_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp : uq_lk_cons_mv_c_upg_lk_t_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp : uq_lk_cons_mv_c_upg_lk_f_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp : uq_lk_cons_mv_c_upg_lk_u_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/mutex_pass.cpp : unique_lock__cons__mutex_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/time_point_pass.cpp : unique_lock__cons__time_point_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/try_to_lock_pass.cpp : unique_lock__cons__try_to_lock_p ]
|
||||
@@ -477,8 +512,8 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/duration_pass.cpp : shared_lock__cons__duration_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_assign_pass.cpp : shared_lock__cons__move_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_pass.cpp : shared_lock__cons__move_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp : shared_lock__cons__move_ctor_unique_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp : shared_lock__cons__move_ctor_upgrade_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp : sh_lock_cons_move_ctor_unq_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp : sh_lock_cons_move_ctor_upg_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/mutex_pass.cpp : shared_lock__cons__mutex_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/time_point_pass.cpp : shared_lock__cons__time_point_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/try_to_lock_pass.cpp : shared_lock__cons__try_to_lock_p ]
|
||||
@@ -511,7 +546,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/duration_pass.cpp : upgrade_lock__cons__duration_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_assign_pass.cpp : upgrade_lock__cons__move_assign_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_pass.cpp : upgrade_lock__cons__move_ctor_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp : upgrade_lock__cons__move_ctor_unique_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp : upg_lock_cons_mv_ctor_uq_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/mutex_pass.cpp : upgrade_lock__cons__mutex_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/time_point_pass.cpp : upgrade_lock__cons__time_point_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/try_to_lock_pass.cpp : upgrade_lock__cons__try_to_lock_p ]
|
||||
@@ -543,8 +578,8 @@ rule thread-compile ( sources : reqs * : name )
|
||||
#explicit ts_nested_strict_lock ;
|
||||
test-suite ts_nested_strict_lock
|
||||
:
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_assign_fail.cpp : : nested_strict_lock__cons__copy_assign_f ]
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_ctor_fail.cpp : : nested_strict_lock__cons__copy_ctor_f ]
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_assign_fail.cpp : : nested_strict_lock_cons_copy_assign_f ]
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_ctor_fail.cpp : : nested_strict_lock_cons_copy_ctor_f ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/nested_strict_lock/default_pass.cpp : nested_strict_lock__cons__default_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/nested_strict_lock/owns_lock_pass.cpp : nested_strict_lock__owns_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/nested_strict_lock/types_pass.cpp : nested_strict_lock__types_p ]
|
||||
@@ -590,10 +625,10 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-compile-fail ./sync/mutual_exclusion/recursive_timed_mutex/copy_fail.cpp : : recursive_timed_mutex__copy_f ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/default_pass.cpp : recursive_timed_mutex__default_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/lock_pass.cpp : recursive_timed_mutex__lock_p ]
|
||||
[ thread-run2-noit-pthread ./sync/mutual_exclusion/recursive_timed_mutex/native_handle_pass.cpp : recursive_timed_mutex__native_handle_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_for_pass.cpp : recursive_timed_mutex__try_lock_for_p ]
|
||||
[ thread-run2-noit-pthread ./sync/mutual_exclusion/recursive_timed_mutex/native_handle_pass.cpp : rec_timed_mutex_native_handle_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_for_pass.cpp : rec_timed_mutex_try_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_pass.cpp : recursive_timed_mutex__try_lock_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_until_pass.cpp : recursive_timed_mutex__try_lock_until_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_until_pass.cpp : rec_timed_mutex_try_lock_until_p ]
|
||||
;
|
||||
|
||||
#explicit ts_timed_mutex ;
|
||||
@@ -643,8 +678,33 @@ rule thread-compile ( sources : reqs * : name )
|
||||
|
||||
test-suite ts_sync_bounded_queue
|
||||
:
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/single_thread_pass.cpp : sync_bounded_queue__single_thread_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_queue__multi_thread_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/single_thread_pass.cpp : sync_bounded_q_single_thread_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_q_multi_thread_p ]
|
||||
;
|
||||
|
||||
test-suite ts_sync_pq
|
||||
:
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/pq_single_thread_pass.cpp : sync_pq_single_thread_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/pq_multi_thread_pass.cpp : sync_pq_multi_thread_p ]
|
||||
;
|
||||
|
||||
test-suite ts_sync_tq
|
||||
:
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_single_thread_pass.cpp : sync_tq_single_thread_p ]
|
||||
#[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_multi_thread_pass.cpp : sync_tq_multi_thread_p ]
|
||||
;
|
||||
|
||||
test-suite ts_scheduler
|
||||
:
|
||||
[ thread-run2-noit ./test_scheduled_tp.cpp : test_scheduled_tp_p ]
|
||||
[ thread-run2-noit ./test_scheduling_adaptor.cpp : test_scheduling_adaptor_p ]
|
||||
[ thread-run2-noit ./test_scheduler.cpp : test_scheduler_p ]
|
||||
;
|
||||
|
||||
test-suite ts_queue_views
|
||||
:
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/queue_views/single_thread_pass.cpp : queue_views__single_thread_p ]
|
||||
#[ thread-run2-noit ./sync/mutual_exclusion/queue_views/multi_thread_pass.cpp : queue_views__multi_thread_p ]
|
||||
;
|
||||
|
||||
#explicit ts_this_thread ;
|
||||
@@ -719,29 +779,31 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ../example/ba_externallly_locked.cpp : ex_ba_externallly_locked ]
|
||||
[ thread-run2 ../example/producer_consumer_bounded.cpp : ex_producer_consumer_bounded ]
|
||||
[ thread-run2 ../example/producer_consumer.cpp : ex_producer_consumer ]
|
||||
[ thread-run2 ../example/producer_consumer2.cpp : ex_producer_consumer2 ]
|
||||
[ thread-run2 ../example/not_interleaved.cpp : ex_not_interleaved ]
|
||||
[ thread-run2 ../example/lambda_future.cpp : ex_lambda_future ]
|
||||
[ thread-run2 ../example/not_interleaved2.cpp : ex_not_interleaved2 ]
|
||||
[ thread-run2 ../example/thread_pool.cpp : ex_thread_pool ]
|
||||
[ thread-run2 ../example/user_scheduler.cpp : ex_user_scheduler ]
|
||||
[ thread-run2 ../example/executor.cpp : ex_executor ]
|
||||
[ thread-run2 ../example/future_when_all.cpp : future_when_all ]
|
||||
[ thread-run2 ../example/generic_executor_ref.cpp : ex_generic_executor_ref ]
|
||||
[ thread-run2 ../example/future_when_all.cpp : ex_future_when_all ]
|
||||
[ thread-run2 ../example/parallel_accumulate.cpp : ex_parallel_accumulate ]
|
||||
[ thread-run2 ../example/parallel_quick_sort.cpp : ex_parallel_quick_sort ]
|
||||
[ thread-run2 ../example/with_lock_guard.cpp : ex_with_lock_guard ]
|
||||
|
||||
[ thread-run2 ../example/fib_task_region.cpp : ex_fib_task_region ]
|
||||
;
|
||||
|
||||
#explicit ts_shared_upwards ;
|
||||
test-suite ts_shared_upwards
|
||||
:
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp : unique_lock__cons__move_ctor_shared_lock_try_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp : unique_lock__cons__move_ctor_shared_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp : unique_lock__cons__move_ctor_shared_lock_until_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp : uq_lock_cons_mv_ctor_sh_lock_try_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp : uq_lock_cons_mv_ctor_sh_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp : uq_lock_cons_mv_ctor_sh_lock_until_p ]
|
||||
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp : upgrade_lock__cons__move_ctor_shared_lock_try_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp : upgrade_lock__cons__move_ctor_shared_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp : upgrade_lock__cons__move_ctor_shared_lock_until_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp : upg_lock_cons_move_ctor_sh_lock_try_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp : upg_lock_cons_move_ctor_sh_lock_for_p ]
|
||||
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp : upg_lock_cons_move_ctor_sh_lock_untl_p ]
|
||||
;
|
||||
|
||||
|
||||
@@ -810,6 +872,8 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run2-noit ./functional/invoker/invoker_rvalue_pass.cpp : invoker_rvalue_p ]
|
||||
;
|
||||
|
||||
|
||||
|
||||
explicit ts_more ;
|
||||
test-suite ts_more
|
||||
:
|
||||
@@ -825,6 +889,11 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run test_9079_a.cpp ]
|
||||
[ thread-run test_9079_b.cpp ]
|
||||
[ thread-run test_9192.cpp ]
|
||||
#[ thread-run test_9303.cpp ]
|
||||
#[ thread-run test_9720.cpp ]
|
||||
#[ thread-run test_10125.cpp ]
|
||||
#[ thread-run test_10128.cpp ]
|
||||
#[ thread-run test_10340.cpp ]
|
||||
;
|
||||
|
||||
explicit ts_more_cpp11 ;
|
||||
@@ -833,21 +902,30 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ thread-run test_8596.cpp ]
|
||||
[ thread-run test_8600.cpp ]
|
||||
;
|
||||
|
||||
explicit perf ;
|
||||
test-suite perf
|
||||
:
|
||||
#[ thread-run ../example/perf_condition_variable.cpp ]
|
||||
#[ thread-run ../example/perf_shared_mutex.cpp ]
|
||||
;
|
||||
|
||||
|
||||
#explicit ts_exception_list ;
|
||||
test-suite ts_exception_list
|
||||
:
|
||||
[ thread-run2-noit ./experimental/parallel/v1/exception_list_pass.cpp : exception_list_p ]
|
||||
;
|
||||
|
||||
#explicit ts_task_region ;
|
||||
test-suite ts_task_region
|
||||
:
|
||||
[ thread-run2-noit ./experimental/parallel/v2/task_region_pass.cpp : task_region_p ]
|
||||
;
|
||||
|
||||
explicit ts_ ;
|
||||
test-suite ts_
|
||||
:
|
||||
#[ thread-run ../example/test_so.cpp ]
|
||||
#[ thread-run ../example/test_so2.cpp ]
|
||||
#[ thread-run ../example/perf_condition_variable.cpp ]
|
||||
#[ thread-run ../example/perf_shared_mutex.cpp ]
|
||||
#[ thread-run ../example/std_async_test.cpp ]
|
||||
#[ compile virtual_noexcept.cpp ]
|
||||
#[ thread-run clang_main.cpp ]
|
||||
#[ thread-run test_9303.cpp ]
|
||||
#[ thread-run test_9720.cpp ]
|
||||
#[ thread-run test_10125.cpp ]
|
||||
#[ thread-run test_10128.cpp ]
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
23
test/experimental/parallel/v1/exception_list_pass.cpp
Normal file
23
test/experimental/parallel/v1/exception_list_pass.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// <boost/thread/experimental/parallel/v1/exception_list.hpp>
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/experimental/parallel/v1/exception_list.hpp>
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
return boost::report_errors();
|
||||
}
|
||||
293
test/experimental/parallel/v2/task_region_pass.cpp
Normal file
293
test/experimental/parallel/v2/task_region_pass.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// <boost/thread/experimental/parallel/v1/exception_list.hpp>
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/experimental/parallel/v2/task_region.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR
|
||||
using boost::experimental::parallel::v2::task_region;
|
||||
using boost::experimental::parallel::v2::task_region_handle;
|
||||
using boost::experimental::parallel::v1::exception_list;
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
|
||||
void run_no_exception()
|
||||
{
|
||||
std::string s("test");
|
||||
bool parent_flag = false;
|
||||
bool task1_flag = false;
|
||||
bool task2_flag = false;
|
||||
bool task21_flag = false;
|
||||
bool task3_flag = false;
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
parent_flag = true;
|
||||
trh.run([&]()
|
||||
{
|
||||
task1_flag = true;
|
||||
std::cout << "task1: " << s << std::endl;
|
||||
});
|
||||
trh.run([&]()
|
||||
{
|
||||
task2_flag = true;
|
||||
std::cout << "task2" << std::endl;
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]()
|
||||
{
|
||||
task21_flag = true;
|
||||
std::cout << "task2.1" << std::endl;
|
||||
});
|
||||
});
|
||||
});
|
||||
int i = 0, j = 10, k = 20;
|
||||
trh.run([=, &task3_flag]()
|
||||
{
|
||||
task3_flag = true;
|
||||
std::cout << "task3: " << i << " " << j << " " << k << std::endl;
|
||||
});
|
||||
std::cout << "parent" << std::endl;
|
||||
});
|
||||
BOOST_TEST(parent_flag);
|
||||
BOOST_TEST(task1_flag);
|
||||
BOOST_TEST(task2_flag);
|
||||
BOOST_TEST(task21_flag);
|
||||
BOOST_TEST(task3_flag);
|
||||
}
|
||||
|
||||
void run_no_exception_wait()
|
||||
{
|
||||
std::string s("test");
|
||||
bool parent_flag = false;
|
||||
bool wait_flag = false;
|
||||
bool task1_flag = false;
|
||||
bool task2_flag = false;
|
||||
bool task21_flag = false;
|
||||
bool task3_flag = false;
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
parent_flag = true;
|
||||
trh.run([&]()
|
||||
{
|
||||
task1_flag = true;
|
||||
std::cout << "task1: " << s << std::endl;
|
||||
});
|
||||
trh.run([&]()
|
||||
{
|
||||
task2_flag = true;
|
||||
std::cout << "task2" << std::endl;
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]()
|
||||
{
|
||||
task21_flag = true;
|
||||
std::cout << "task2.1" << std::endl;
|
||||
});
|
||||
});
|
||||
});
|
||||
int i = 0, j = 10, k = 20;
|
||||
trh.run([=, &task3_flag]()
|
||||
{
|
||||
task3_flag = true;
|
||||
std::cout << "task3: " << i << " " << j << " " << k << std::endl;
|
||||
});
|
||||
std::cout << "before" << std::endl;
|
||||
trh.wait();
|
||||
wait_flag = true;
|
||||
std::cout << "parent" << std::endl;
|
||||
});
|
||||
BOOST_TEST(parent_flag);
|
||||
BOOST_TEST(wait_flag);
|
||||
BOOST_TEST(task1_flag);
|
||||
BOOST_TEST(task2_flag);
|
||||
BOOST_TEST(task21_flag);
|
||||
BOOST_TEST(task3_flag);
|
||||
}
|
||||
|
||||
void run_exception_1()
|
||||
{
|
||||
try
|
||||
{
|
||||
task_region([](task_region_handle& trh)
|
||||
{
|
||||
trh.run([]()
|
||||
{
|
||||
std::cout << "task1" << std::endl;
|
||||
throw 1;
|
||||
});
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
trh.run([]()
|
||||
{
|
||||
std::cout << "task3" << std::endl;
|
||||
});
|
||||
BOOST_TEST(false);
|
||||
});
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (exception_list const& e)
|
||||
{
|
||||
BOOST_TEST_EQ(e.size(), 1u);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
|
||||
void run_exception()
|
||||
{
|
||||
try
|
||||
{
|
||||
task_region([](task_region_handle& trh)
|
||||
{
|
||||
trh.run([]()
|
||||
{
|
||||
std::cout << "task1" << std::endl;
|
||||
throw 1;
|
||||
});
|
||||
trh.run([]()
|
||||
{
|
||||
std::cout << "task2" << std::endl;
|
||||
throw 2;
|
||||
});
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
trh.run([]()
|
||||
{
|
||||
std::cout << "task3" << std::endl;
|
||||
throw 3;
|
||||
});
|
||||
std::cout << "parent" << std::endl;
|
||||
throw 100;
|
||||
});
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (exception_list const& el)
|
||||
{
|
||||
BOOST_TEST(el.size() >= 1u);
|
||||
for (boost::exception_ptr const& e: el)
|
||||
{
|
||||
try {
|
||||
boost::rethrow_exception(e);
|
||||
}
|
||||
catch (boost::exception&)
|
||||
{
|
||||
BOOST_TEST(true);
|
||||
}
|
||||
catch (int i) // this doesn't works yet
|
||||
{
|
||||
BOOST_TEST((i == 1) || (i == 2) || (i == 3));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void run_nested_exception()
|
||||
{
|
||||
std::string s("test");
|
||||
bool parent_flag = false;
|
||||
bool task1_flag = false;
|
||||
bool task2_flag = false;
|
||||
bool task21_flag = false;
|
||||
bool task3_flag = false;
|
||||
try
|
||||
{
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
parent_flag = true;
|
||||
trh.run([&]()
|
||||
{
|
||||
task1_flag = true;
|
||||
std::cout << "task1: " << s << std::endl;
|
||||
});
|
||||
trh.run([&]()
|
||||
{
|
||||
task2_flag = true;
|
||||
std::cout << "task2" << std::endl;
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]()
|
||||
{
|
||||
task21_flag = true;
|
||||
std::cout << "task2.1" << std::endl;
|
||||
throw 21;
|
||||
});
|
||||
});
|
||||
});
|
||||
int i = 0, j = 10, k = 20;
|
||||
trh.run([=, &task3_flag]()
|
||||
{
|
||||
task3_flag = true;
|
||||
std::cout << "task3: " << i << " " << j << " " << k << std::endl;
|
||||
});
|
||||
std::cout << "parent" << std::endl;
|
||||
});
|
||||
}
|
||||
catch (exception_list const& el)
|
||||
{
|
||||
BOOST_TEST(el.size() == 1u);
|
||||
for (boost::exception_ptr const& e: el)
|
||||
{
|
||||
try {
|
||||
boost::rethrow_exception(e);
|
||||
}
|
||||
catch (int i) // this doesn't works yet
|
||||
{
|
||||
BOOST_TEST_EQ(i, 21);
|
||||
}
|
||||
catch (boost::exception&)
|
||||
{
|
||||
BOOST_TEST(true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
BOOST_TEST(parent_flag);
|
||||
BOOST_TEST(task1_flag);
|
||||
BOOST_TEST(task2_flag);
|
||||
BOOST_TEST(task21_flag);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
run_no_exception();
|
||||
run_no_exception_wait();
|
||||
run_exception();
|
||||
run_exception_1();
|
||||
run_nested_exception();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -70,38 +70,38 @@ public:
|
||||
|
||||
int value;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
|
||||
BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
|
||||
MoveOnly()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
MoveOnly( BOOST_THREAD_RV_REF(MoveOnly))
|
||||
{
|
||||
value = 1;
|
||||
}
|
||||
MoveOnly& operator=(BOOST_THREAD_RV_REF(MoveOnly))
|
||||
{
|
||||
value = 2;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
return 3;
|
||||
}
|
||||
template <typename OS>
|
||||
friend OS& operator<<(OS& os, MoveOnly const& v)
|
||||
{
|
||||
os << v.value;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
BOOST_THREAD_DCL_MOVABLE (MoveOnly)
|
||||
{
|
||||
value = 1;
|
||||
}
|
||||
MoveOnly& operator=(BOOST_THREAD_RV_REF(MoveOnly))
|
||||
{
|
||||
value = 2;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
boost::this_thread::sleep_for(ms(200));
|
||||
return 3;
|
||||
}
|
||||
template <typename OS>
|
||||
friend OS& operator<<(OS& os, MoveOnly const& v)
|
||||
{
|
||||
os << v.value;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
BOOST_THREAD_DCL_MOVABLE (MoveOnly)
|
||||
}
|
||||
|
||||
int f0()
|
||||
{
|
||||
@@ -263,6 +263,32 @@ int main()
|
||||
}
|
||||
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<long> f = boost::async(boost::launch::deferred, A(3));
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
int res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
res = f.get();
|
||||
}
|
||||
BOOST_TEST(res == 3);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
@@ -289,6 +315,31 @@ int main()
|
||||
}
|
||||
|
||||
}
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
A a(3);
|
||||
boost::future<long> f = boost::async(boost::launch::deferred, &A::doit, &a);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
int res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
res = f.get();
|
||||
}
|
||||
BOOST_TEST(res == 3);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
@@ -313,6 +364,31 @@ int main()
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f = boost::async(boost::launch::deferred, BOOST_THREAD_MAKE_RV_REF(MoveOnly()));
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
int res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
res = f.get();
|
||||
}
|
||||
BOOST_TEST(res == 3);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
try
|
||||
@@ -342,7 +418,7 @@ int main()
|
||||
try
|
||||
{
|
||||
boost::future<int> f = boost::async(boost::launch::deferred, f0);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
int res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
@@ -436,7 +512,7 @@ int main()
|
||||
try
|
||||
{
|
||||
boost::future<int&> f = boost::async(boost::launch::deferred, f1);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
int* res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
@@ -524,7 +600,7 @@ int main()
|
||||
try
|
||||
{
|
||||
boost::future<void> f = boost::async(boost::launch::deferred, f2);
|
||||
boost::this_thread::sleep_for(ms(300));
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
f.get();
|
||||
@@ -565,6 +641,31 @@ int main()
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<MoveOnly> f = boost::async(boost::launch::deferred, &f3_1);
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
MoveOnly res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
res = f.get();
|
||||
}
|
||||
BOOST_TEST_EQ(res.value, 2);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
{
|
||||
try
|
||||
@@ -638,6 +739,29 @@ int main()
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<boost::csbl::unique_ptr<int> > f = boost::async(boost::launch::deferred, &f3, 3);
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
boost::csbl::unique_ptr<int> res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
res = f.get();
|
||||
}
|
||||
BOOST_TEST(*res == 3);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -687,6 +811,29 @@ int main()
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<boost::csbl::unique_ptr<int> > f = boost::async(boost::launch::deferred, &f4, boost::csbl::unique_ptr<int>(new int(3)));
|
||||
//boost::this_thread::sleep_for(ms(300));
|
||||
boost::csbl::unique_ptr<int> res;
|
||||
{
|
||||
check_timer timer(ms(500));
|
||||
res = f.get();
|
||||
}
|
||||
BOOST_TEST(*res == 3);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false && "exception thrown");
|
||||
}
|
||||
}
|
||||
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
130
test/sync/futures/future/async_deferred_then_pass.cpp
Normal file
130
test/sync/futures/future/async_deferred_then_pass.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2012-2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class future<R>
|
||||
|
||||
// template<typename F>
|
||||
// auto then(F&& func) -> future<decltype(func(*this))>;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
return 2 * i;
|
||||
}
|
||||
|
||||
void p3(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p3 <" << &f << " " <<i << BOOST_THREAD_END_LOG;
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
BOOST_TEST(f2.valid());
|
||||
BOOST_TEST(! f1.valid());
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<void> f2 = f1.then(&p3);
|
||||
BOOST_TEST(f2.valid());
|
||||
try
|
||||
{
|
||||
f2.wait();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f2 = boost::async(boost::launch::deferred, p1).then(&p2);
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, p1);
|
||||
boost::future<int> f21 = f1.then(&p2);
|
||||
boost::future<int> f2= f21.then(&p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, p1);
|
||||
boost::future<int> f2= f1.then(&p2).then(&p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f2 = boost::async(boost::launch::deferred, p1).then(&p2).then(&p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -11,7 +11,7 @@
|
||||
// R& future<R&>::get_or(R&);
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
|
||||
130
test/sync/futures/future/then_deferred_pass.cpp
Normal file
130
test/sync/futures/future/then_deferred_pass.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2012-2013 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class future<R>
|
||||
|
||||
// template<typename F>
|
||||
// auto then(F&& func) -> future<decltype(func(*this))>;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
return 2 * i;
|
||||
}
|
||||
|
||||
void p3(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p3 <" << &f << " " <<i << BOOST_THREAD_END_LOG;
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<int> f2 = f1.then(boost::launch::deferred, &p2);
|
||||
BOOST_TEST(f2.valid());
|
||||
BOOST_TEST(! f1.valid());
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<void> f2 = f1.then(boost::launch::deferred, &p3);
|
||||
BOOST_TEST(f2.valid());
|
||||
try
|
||||
{
|
||||
f2.wait();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f2 = boost::async(p1).then(boost::launch::deferred, &p2);
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
boost::future<int> f21 = f1.then(boost::launch::deferred, &p2);
|
||||
boost::future<int> f2= f21.then(boost::launch::deferred, &p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
boost::future<int> f2= f1.then(boost::launch::deferred, &p2).then(boost::launch::deferred, &p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::future<int> f2 = boost::async(p1).then(boost::launch::deferred, &p2).then(boost::launch::deferred, &p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
139
test/sync/futures/future/then_executor_pass.cpp
Normal file
139
test/sync/futures/future/then_executor_pass.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
// 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)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class future<R>
|
||||
|
||||
// template<typename F>
|
||||
// auto then(F&& func) -> future<decltype(func(*this))>;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executor.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
|
||||
return 2 * i;
|
||||
}
|
||||
|
||||
void p3(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(f.valid());
|
||||
int i = f.get();
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
BOOST_THREAD_LOG << "p3 <" << &f << " " <<i << BOOST_THREAD_END_LOG;
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::basic_thread_pool ex(1);
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<int> f2 = f1.then(ex, &p2);
|
||||
BOOST_TEST(f2.valid());
|
||||
BOOST_TEST(! f1.valid());
|
||||
try
|
||||
{
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::basic_thread_pool ex(1);
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_TEST(f1.valid());
|
||||
boost::future<void> f2 = f1.then(ex, &p3);
|
||||
BOOST_TEST(f2.valid());
|
||||
try
|
||||
{
|
||||
f2.wait();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::basic_thread_pool ex(1);
|
||||
boost::future<int> f2 = boost::async(p1).then(ex, &p2);
|
||||
BOOST_TEST(f2.get()==2);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::basic_thread_pool ex(1);
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
boost::future<int> f21 = f1.then(ex, &p2);
|
||||
boost::future<int> f2= f21.then(ex, &p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::basic_thread_pool ex(1);
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
boost::future<int> f2= f1.then(&p2).then(ex, &p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
boost::basic_thread_pool ex(1);
|
||||
boost::future<int> f2 = boost::async(p1).then(ex, &p2).then(ex, &p2);
|
||||
BOOST_TEST(f2.get()==4);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -11,7 +11,7 @@
|
||||
// auto then(F&& func) -> future<decltype(func(*this))>;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
// wait_for(const chrono::duration<Rep, Period>& rel_time) const;
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
//#define BOOST_THREAD_VERSION 3
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
|
||||
|
||||
157
test/sync/futures/make_ready_future_pass.cpp
Normal file
157
test/sync/futures/make_ready_future_pass.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Copyright (C) 2011,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// <boost/thread/future.hpp>
|
||||
|
||||
// class promise<R>
|
||||
|
||||
// future<void> make_ready_future();
|
||||
// template <class T>
|
||||
// future<decay_t<T>> make_ready_future(T&&);
|
||||
// template <class T>
|
||||
// future<T> make_ready_future(remove_reference_t<T>&);
|
||||
// template <class T>
|
||||
// future<T> make_ready_future(remove_reference_t<T>&&);
|
||||
// template <class T, class ...Args>
|
||||
// future<T> make_ready_future(Args&& ... args);
|
||||
|
||||
#define BOOST_THREAD_VERSION 3
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
struct A
|
||||
{
|
||||
A() :
|
||||
value(0)
|
||||
{
|
||||
}
|
||||
A(int i) :
|
||||
value(i)
|
||||
{
|
||||
}
|
||||
A(int i, int j) :
|
||||
value(i+j)
|
||||
{
|
||||
}
|
||||
int value;
|
||||
};
|
||||
|
||||
A make(int i) {
|
||||
return A(i);
|
||||
}
|
||||
A make(int i, int j) {
|
||||
return A(i, j);
|
||||
}
|
||||
|
||||
struct movable2
|
||||
{
|
||||
int value_;
|
||||
BOOST_THREAD_MOVABLE_ONLY(movable2)
|
||||
movable2() : value_(1){}
|
||||
movable2(int i) : value_(i){}
|
||||
movable2(int i, int j) : value_(i+j){}
|
||||
|
||||
//Move constructor and assignment
|
||||
movable2(BOOST_RV_REF(movable2) m)
|
||||
{ value_ = m.value_; m.value_ = 0; }
|
||||
|
||||
movable2 & operator=(BOOST_THREAD_RV_REF(movable2) m)
|
||||
{ value_ = m.value_; m.value_ = 0; return *this; }
|
||||
|
||||
bool moved() const //Observer
|
||||
{ return !value_; }
|
||||
|
||||
int value() const //Observer
|
||||
{ return value_; }
|
||||
};
|
||||
|
||||
|
||||
movable2 move_return_function2(int i) {
|
||||
return movable2(i);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
BOOST_STATIC_ASSERT((boost::is_copy_constructible<movable2>::value == false));
|
||||
BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled<movable2>::value == true));
|
||||
BOOST_STATIC_ASSERT((boost::is_copy_constructible<A>::value == true));
|
||||
BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled<A>::value == false));
|
||||
#endif
|
||||
|
||||
{
|
||||
boost::future<void> f = boost::make_ready_future();
|
||||
f.wait();
|
||||
}
|
||||
{
|
||||
typedef A T;
|
||||
T i;
|
||||
boost::future<T> f = boost::make_ready_future(i);
|
||||
BOOST_TEST(f.get().value==0);
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
{
|
||||
typedef A T;
|
||||
boost::future<T> f = boost::make_ready_future<T>();
|
||||
BOOST_TEST(f.get().value==0);
|
||||
}
|
||||
{
|
||||
typedef A T;
|
||||
boost::future<T> f = boost::make_ready_future<T>(1);
|
||||
BOOST_TEST(f.get().value==1);
|
||||
}
|
||||
{
|
||||
typedef A T;
|
||||
boost::future<T> f = boost::make_ready_future<T>(1,2);
|
||||
BOOST_TEST(f.get().value==3);
|
||||
}
|
||||
{
|
||||
typedef A T;
|
||||
T i;
|
||||
boost::future<T&> f = boost::make_ready_future<T&>(i);
|
||||
BOOST_TEST(f.get().value==0);
|
||||
}
|
||||
#endif
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
// sync/futures/make_ready_future_pass.cpp:125:65: erreur: conversion from Ôboost::future<boost::rv<movable2> >Õ to non-scalar type Ôboost::future<movable2>Õ requested
|
||||
{
|
||||
typedef movable2 T;
|
||||
T i;
|
||||
boost::future<T> f = boost::make_ready_future(boost::move(i));
|
||||
BOOST_TEST_EQ(f.get().value(),1);
|
||||
}
|
||||
#endif
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
{
|
||||
typedef movable2 T;
|
||||
boost::future<T> f = boost::make_ready_future<T>();
|
||||
BOOST_TEST(f.get().value()==1);
|
||||
}
|
||||
{
|
||||
typedef movable2 T;
|
||||
boost::future<T> f = boost::make_ready_future<T>(1);
|
||||
BOOST_TEST(f.get().value()==1);
|
||||
}
|
||||
{
|
||||
typedef movable2 T;
|
||||
boost::future<T> f = boost::make_ready_future<T>(1,2);
|
||||
BOOST_TEST(f.get().value()==3);
|
||||
}
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -64,11 +64,24 @@ public:
|
||||
++n_instances;
|
||||
++n_moves; BOOST_THREAD_RV(a).data_ = -1;
|
||||
}
|
||||
A& operator=(BOOST_THREAD_RV_REF(A) a)
|
||||
{
|
||||
data_ = BOOST_THREAD_RV(a).data_;
|
||||
BOOST_THREAD_RV(a).data_ = -1;
|
||||
++n_moves;
|
||||
return *this;
|
||||
}
|
||||
A(const A& a) : data_(a.data_)
|
||||
{
|
||||
++n_instances;
|
||||
++n_copies;
|
||||
}
|
||||
A& operator=(BOOST_THREAD_COPY_ASSIGN_REF(A) a)
|
||||
{
|
||||
data_ = a.data_;
|
||||
++n_copies;
|
||||
return *this;
|
||||
}
|
||||
~A()
|
||||
{
|
||||
--n_instances;
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
{
|
||||
++n_copies;
|
||||
}
|
||||
A& operator=(A const& a)
|
||||
A& operator=(BOOST_THREAD_COPY_ASSIGN_REF(A) a)
|
||||
{
|
||||
data_ = a.data_;
|
||||
++n_copies;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user