mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 21:52:07 +00:00
Compare commits
33 Commits
boost-1.57
...
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 |
@@ -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.
|
||||
|
||||
@@ -142,7 +142,6 @@ The third one is related to performance. They assert that "any mechanism for sto
|
||||
|
||||
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.
|
||||
@@ -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]
|
||||
@@ -512,7 +569,7 @@ 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();
|
||||
@@ -558,14 +615,12 @@ 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.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -587,7 +642,7 @@ Executor abstract base class.
|
||||
generic_executor_ref& operator=(generic_executor_ref const&);
|
||||
|
||||
template <class Executor>
|
||||
executor(Executor& ex);
|
||||
generic_executor_ref(Executor& ex);
|
||||
generic_executor_ref() {};
|
||||
|
||||
void close() = 0;
|
||||
@@ -605,28 +660,27 @@ Executor abstract base class.
|
||||
[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();
|
||||
@@ -652,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. ]]
|
||||
|
||||
@@ -668,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
|
||||
|
||||
@@ -684,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.]]
|
||||
|
||||
]
|
||||
@@ -697,16 +768,18 @@ Executor providing time related functions.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
]
|
||||
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:serial_executor Class `serial_executor`]
|
||||
[section:serial_executor Template Class `serial_executor`]
|
||||
|
||||
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||
|
||||
#include <boost/thread/serial_executor.hpp>
|
||||
namespace boost {
|
||||
template <class Executor>
|
||||
class serial_executor
|
||||
{
|
||||
public:
|
||||
@@ -716,7 +789,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
template <class Executor>
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
generic_executor_ref underlying_executor();
|
||||
Executor& underlying_executor() noexcept;
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
@@ -764,7 +837,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
generic_executor_ref underlying_executor();
|
||||
generic_executor_ref& underlying_executor() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -779,6 +852,84 @@ 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`]
|
||||
|
||||
@@ -848,7 +999,7 @@ 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
|
||||
{
|
||||
@@ -892,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
|
||||
|
||||
@@ -905,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`]
|
||||
|
||||
|
||||
@@ -8,6 +8,40 @@
|
||||
|
||||
[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:]
|
||||
@@ -557,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.
|
||||
|
||||
@@ -567,9 +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 extensions related to fork-join as:
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9600 #9600] Async: Add task_region/task_run.
|
||||
|
||||
# And some additional extensions related to futures as:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic shared_future::then.
|
||||
|
||||
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]
|
||||
@@ -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]
|
||||
|
||||
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
|
||||
@@ -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
|
||||
@@ -22,7 +22,7 @@ namespace concurrent
|
||||
{
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
|
||||
{ success = 0, empty, full, closed, busy }
|
||||
{ success = 0, empty, full, closed, busy, timeout, not_ready }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
struct sync_queue_is_closed : std::exception
|
||||
|
||||
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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -95,12 +92,9 @@ namespace executors
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -134,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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
@@ -33,7 +33,7 @@ namespace executors
|
||||
typedef scoped_thread<> thread_t;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
generic_executor_ref ex;
|
||||
thread_t thr;
|
||||
|
||||
@@ -43,7 +43,7 @@ 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();
|
||||
}
|
||||
};
|
||||
@@ -52,7 +52,7 @@ namespace executors
|
||||
* \par Returns
|
||||
* The underlying executor wrapped on a generic executor reference.
|
||||
*/
|
||||
generic_executor_ref underlying_executor() BOOST_NOEXCEPT { return ex; }
|
||||
generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex; }
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
@@ -69,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;
|
||||
}
|
||||
}
|
||||
@@ -136,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
@@ -432,24 +432,24 @@ namespace boost
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void mark_interrupted_finish()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(this->mutex);
|
||||
exception = boost::copy_exception(boost::thread_interrupted());
|
||||
mark_finished_internal(lock);
|
||||
}
|
||||
// void mark_interrupted_finish()
|
||||
// {
|
||||
// boost::unique_lock<boost::mutex> lock(this->mutex);
|
||||
// exception = boost::copy_exception(boost::thread_interrupted());
|
||||
// mark_finished_internal(lock);
|
||||
// }
|
||||
|
||||
void set_interrupted_at_thread_exit()
|
||||
{
|
||||
unique_lock<boost::mutex> lk(this->mutex);
|
||||
if (has_value(lk))
|
||||
{
|
||||
throw_exception(promise_already_satisfied());
|
||||
}
|
||||
exception = boost::copy_exception(boost::thread_interrupted());
|
||||
this->is_constructed = true;
|
||||
detail::make_ready_at_thread_exit(shared_from_this());
|
||||
}
|
||||
// void set_interrupted_at_thread_exit()
|
||||
// {
|
||||
// unique_lock<boost::mutex> lk(this->mutex);
|
||||
// if (has_value(lk))
|
||||
// {
|
||||
// throw_exception(promise_already_satisfied());
|
||||
// }
|
||||
// exception = boost::copy_exception(boost::thread_interrupted());
|
||||
// this->is_constructed = true;
|
||||
// detail::make_ready_at_thread_exit(shared_from_this());
|
||||
// }
|
||||
#endif
|
||||
|
||||
void set_exception_at_thread_exit(exception_ptr e)
|
||||
@@ -481,14 +481,14 @@ namespace boost
|
||||
return done && exception;
|
||||
}
|
||||
|
||||
bool has_exception(unique_lock<boost::mutex>&) const
|
||||
{
|
||||
return done && exception;
|
||||
}
|
||||
// bool has_exception(unique_lock<boost::mutex>&) const
|
||||
// {
|
||||
// return done && exception;
|
||||
// }
|
||||
|
||||
bool is_deferred(boost::lock_guard<boost::mutex>&) const {
|
||||
return is_deferred_;
|
||||
}
|
||||
// bool is_deferred(boost::lock_guard<boost::mutex>&) const {
|
||||
// return is_deferred_;
|
||||
// }
|
||||
|
||||
launch launch_policy(boost::unique_lock<boost::mutex>&) const
|
||||
{
|
||||
@@ -511,13 +511,14 @@ namespace boost
|
||||
exception_ptr get_exception_ptr()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(this->mutex);
|
||||
return get_exception_ptr(lock);
|
||||
}
|
||||
exception_ptr get_exception_ptr(boost::unique_lock<boost::mutex>& lock)
|
||||
{
|
||||
wait_internal(lock, false);
|
||||
return exception;
|
||||
}
|
||||
// exception_ptr get_exception_ptr(boost::unique_lock<boost::mutex>& lock)
|
||||
// {
|
||||
// wait_internal(lock, false);
|
||||
// return exception;
|
||||
// }
|
||||
|
||||
template<typename F,typename U>
|
||||
void set_wait_callback(F f,U* u)
|
||||
@@ -580,21 +581,29 @@ namespace boost
|
||||
|
||||
void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock<boost::mutex>& lock)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL
|
||||
result = boost::move(result_);
|
||||
#else
|
||||
#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
result.reset(new T(boost::move(result_)));
|
||||
#endif
|
||||
#else
|
||||
#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL
|
||||
result = boost::move(result_);
|
||||
#else
|
||||
result.reset(new T(static_cast<rvalue_source_type>(result_)));
|
||||
#endif
|
||||
this->mark_finished_internal(lock);
|
||||
}
|
||||
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class ...Args>
|
||||
void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock, BOOST_THREAD_FWD_REF(Args)... args)
|
||||
{
|
||||
#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL
|
||||
result.emplace(boost::forward<Args>(args)...);
|
||||
#else
|
||||
result.reset(new T(boost::forward<Args>(args)...));
|
||||
#endif
|
||||
this->mark_finished_internal(lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
void mark_finished_with_result(source_reference_type result_)
|
||||
{
|
||||
@@ -830,12 +839,6 @@ namespace boost
|
||||
{
|
||||
that->mark_finished_with_result(f());
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
that->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
that->mark_exceptional_finish();
|
||||
@@ -858,12 +861,6 @@ namespace boost
|
||||
f();
|
||||
that->mark_finished_with_result();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
that->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
that->mark_exceptional_finish();
|
||||
@@ -885,12 +882,6 @@ namespace boost
|
||||
{
|
||||
that->mark_finished_with_result(f());
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
that->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
that->mark_exceptional_finish();
|
||||
@@ -1277,7 +1268,6 @@ namespace boost
|
||||
future_ = p.get_future().future_;
|
||||
}
|
||||
|
||||
|
||||
future_ptr future_;
|
||||
|
||||
basic_future(future_ptr a_future):
|
||||
@@ -2077,6 +2067,22 @@ namespace boost
|
||||
future_->mark_finished_with_result_internal(static_cast<rvalue_source_type>(r), lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class ...Args>
|
||||
void emplace(BOOST_THREAD_FWD_REF(Args) ...args)
|
||||
{
|
||||
lazy_init();
|
||||
boost::unique_lock<boost::mutex> lock(future_->mutex);
|
||||
if(future_->done)
|
||||
{
|
||||
boost::throw_exception(promise_already_satisfied());
|
||||
}
|
||||
future_->mark_finished_with_result_internal(lock, boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void set_exception(boost::exception_ptr p)
|
||||
{
|
||||
lazy_init();
|
||||
@@ -2606,12 +2612,12 @@ namespace boost
|
||||
this->set_value_at_thread_exit(f());
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->set_interrupted_at_thread_exit();
|
||||
}
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// catch(thread_interrupted& )
|
||||
// {
|
||||
// this->set_interrupted_at_thread_exit();
|
||||
// }
|
||||
//#endif
|
||||
catch(...)
|
||||
{
|
||||
this->set_exception_at_thread_exit(current_exception());
|
||||
@@ -2637,12 +2643,6 @@ namespace boost
|
||||
this->mark_finished_with_result(f());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
@@ -2693,12 +2693,12 @@ namespace boost
|
||||
this->set_value_at_thread_exit(f());
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->set_interrupted_at_thread_exit();
|
||||
}
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// catch(thread_interrupted& )
|
||||
// {
|
||||
// this->set_interrupted_at_thread_exit();
|
||||
// }
|
||||
//#endif
|
||||
catch(...)
|
||||
{
|
||||
this->set_exception_at_thread_exit(current_exception());
|
||||
@@ -2720,12 +2720,6 @@ namespace boost
|
||||
R& res((f()));
|
||||
this->mark_finished_with_result(res);
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
@@ -2783,12 +2777,12 @@ namespace boost
|
||||
this->set_value_at_thread_exit(boost::move(r));
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->set_interrupted_at_thread_exit();
|
||||
}
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// catch(thread_interrupted& )
|
||||
// {
|
||||
// this->set_interrupted_at_thread_exit();
|
||||
// }
|
||||
//#endif
|
||||
catch(...)
|
||||
{
|
||||
this->set_exception_at_thread_exit(current_exception());
|
||||
@@ -2811,12 +2805,6 @@ namespace boost
|
||||
R res((f()));
|
||||
this->mark_finished_with_result(boost::move(res));
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
@@ -2870,12 +2858,12 @@ namespace boost
|
||||
this->set_value_at_thread_exit(f());
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->set_interrupted_at_thread_exit();
|
||||
}
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// catch(thread_interrupted& )
|
||||
// {
|
||||
// this->set_interrupted_at_thread_exit();
|
||||
// }
|
||||
//#endif
|
||||
catch(...)
|
||||
{
|
||||
this->set_exception_at_thread_exit(current_exception());
|
||||
@@ -2897,12 +2885,6 @@ namespace boost
|
||||
{
|
||||
this->mark_finished_with_result(f());
|
||||
}
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
@@ -2953,12 +2935,12 @@ namespace boost
|
||||
#endif
|
||||
this->set_value_at_thread_exit();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->set_interrupted_at_thread_exit();
|
||||
}
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// catch(thread_interrupted& )
|
||||
// {
|
||||
// this->set_interrupted_at_thread_exit();
|
||||
// }
|
||||
//#endif
|
||||
catch(...)
|
||||
{
|
||||
this->set_exception_at_thread_exit(current_exception());
|
||||
@@ -2980,12 +2962,6 @@ namespace boost
|
||||
#endif
|
||||
this->mark_finished_with_result();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
this->mark_exceptional_finish();
|
||||
@@ -3032,12 +3008,12 @@ namespace boost
|
||||
#endif
|
||||
this->set_value_at_thread_exit();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->set_interrupted_at_thread_exit();
|
||||
}
|
||||
#endif
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
// catch(thread_interrupted& )
|
||||
// {
|
||||
// this->set_interrupted_at_thread_exit();
|
||||
// }
|
||||
//#endif
|
||||
catch(...)
|
||||
{
|
||||
this->set_exception_at_thread_exit(current_exception());
|
||||
@@ -3059,12 +3035,6 @@ namespace boost
|
||||
#endif
|
||||
this->mark_finished_with_result();
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
catch(thread_interrupted& )
|
||||
{
|
||||
this->mark_interrupted_finish();
|
||||
}
|
||||
#endif
|
||||
catch(...)
|
||||
{
|
||||
this->mark_exceptional_finish();
|
||||
@@ -3602,10 +3572,6 @@ namespace detail {
|
||||
void operator()() {
|
||||
try {
|
||||
that->mark_finished_with_result(f_());
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -3653,10 +3619,6 @@ namespace detail {
|
||||
try {
|
||||
f_();
|
||||
that->mark_finished_with_result();
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -3702,10 +3664,6 @@ namespace detail {
|
||||
void operator()() {
|
||||
try {
|
||||
that->mark_finished_with_result(f_());
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -3929,7 +3887,11 @@ namespace detail {
|
||||
////////////////////////////////
|
||||
// make_ready_future
|
||||
////////////////////////////////
|
||||
template <typename T>
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <int = 0, int..., class T>
|
||||
#else
|
||||
template <class T>
|
||||
#endif
|
||||
BOOST_THREAD_FUTURE<typename decay<T>::type> make_ready_future(BOOST_THREAD_FWD_REF(T) value) {
|
||||
typedef typename decay<T>::type future_value_type;
|
||||
promise<future_value_type> p;
|
||||
@@ -3937,6 +3899,35 @@ namespace detail {
|
||||
return BOOST_THREAD_MAKE_RV_REF(p.get_future());
|
||||
}
|
||||
|
||||
// explicit overloads
|
||||
template <class T>
|
||||
BOOST_THREAD_FUTURE<T> make_ready_future(typename remove_reference<T>::type & x)
|
||||
{
|
||||
promise<T> p;
|
||||
p.set_value(x);
|
||||
return p.get_future();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_THREAD_FUTURE<T> make_ready_future(BOOST_THREAD_FWD_REF(typename remove_reference<T>::type) x)
|
||||
{
|
||||
promise<T> p;
|
||||
p.set_value(forward<typename remove_reference<T>::type>(x));
|
||||
return p.get_future();
|
||||
}
|
||||
|
||||
// variadic overload
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class T, class ...Args>
|
||||
BOOST_THREAD_FUTURE<T> make_ready_future(Args&&... args)
|
||||
{
|
||||
promise<T> p;
|
||||
p.emplace(forward<Args>(args)...);
|
||||
return p.get_future();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename T1>
|
||||
BOOST_THREAD_FUTURE<T> make_ready_no_decay_future(T1 value) {
|
||||
typedef T future_value_type;
|
||||
@@ -4052,10 +4043,6 @@ namespace detail
|
||||
static void run(future_async_continuation_shared_state* that) {
|
||||
try {
|
||||
that->mark_finished_with_result(that->continuation(boost::move(that->parent)));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4086,10 +4073,6 @@ namespace detail
|
||||
try {
|
||||
that->continuation(boost::move(that->parent));
|
||||
that->mark_finished_with_result();
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4135,10 +4118,6 @@ namespace detail
|
||||
static void run(future_executor_continuation_shared_state* that) {
|
||||
try {
|
||||
that->mark_finished_with_result(that->continuation(boost::move(that->parent)));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4172,10 +4151,6 @@ namespace detail
|
||||
try {
|
||||
that->continuation(boost::move(that->parent));
|
||||
that->mark_finished_with_result();
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4210,10 +4185,6 @@ namespace detail
|
||||
static void run(shared_future_async_continuation_shared_state* that) {
|
||||
try {
|
||||
that->mark_finished_with_result(that->continuation(that->parent));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4244,10 +4215,6 @@ namespace detail
|
||||
try {
|
||||
that->continuation(that->parent);
|
||||
that->mark_finished_with_result();
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4285,10 +4252,6 @@ namespace detail
|
||||
static void run(shared_future_executor_continuation_shared_state* that) {
|
||||
try {
|
||||
that->mark_finished_with_result(that->continuation(that->parent));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4321,10 +4284,6 @@ namespace detail
|
||||
try {
|
||||
that->continuation(that->parent);
|
||||
that->mark_finished_with_result();
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4811,10 +4770,6 @@ namespace detail
|
||||
try {
|
||||
boost::wait_for_all(that->vec_.begin(), that->vec_.end());
|
||||
that->mark_finished_with_result(boost::move(that->vec_));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4885,10 +4840,6 @@ namespace detail
|
||||
try {
|
||||
boost::wait_for_any(that->vec_.begin(), that->vec_.end());
|
||||
that->mark_finished_with_result(boost::move(that->vec_));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -4993,10 +4944,6 @@ namespace detail
|
||||
that->wait_for_all(Index());
|
||||
|
||||
that->mark_finished_with_result(boost::move(that->tup_));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
@@ -5067,10 +5014,6 @@ namespace detail
|
||||
that->wait_for_any(Index());
|
||||
|
||||
that->mark_finished_with_result(boost::move(that->tup_));
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
} catch(thread_interrupted& ) {
|
||||
that->mark_interrupted_finish();
|
||||
#endif
|
||||
} catch(...) {
|
||||
that->mark_exceptional_finish();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ 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);
|
||||
|
||||
@@ -11,712 +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/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
|
||||
{
|
||||
|
||||
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
|
||||
|
||||
@@ -11,653 +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/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.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_);
|
||||
waiting_empty_ = 0;
|
||||
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
|
||||
|
||||
@@ -349,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 ]
|
||||
@@ -357,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
|
||||
:
|
||||
@@ -675,6 +682,25 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ 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 ]
|
||||
@@ -765,7 +791,7 @@ rule thread-compile ( sources : reqs * : name )
|
||||
[ 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 ;
|
||||
@@ -883,6 +909,19 @@ rule thread-compile ( sources : reqs * : name )
|
||||
#[ 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_
|
||||
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
207
test/sync/futures/promise/emplace_pass.cpp
Normal file
207
test/sync/futures/promise/emplace_pass.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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>
|
||||
|
||||
// template <class ...Args>
|
||||
// void promise::emplace(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)
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE_ONLY(A)
|
||||
|
||||
A(BOOST_THREAD_RV_REF(A) rhs)
|
||||
{
|
||||
if(rhs.value==0)
|
||||
throw 9;
|
||||
else
|
||||
{
|
||||
value=rhs.value;
|
||||
rhs.value=0;
|
||||
}
|
||||
}
|
||||
A& operator=(BOOST_THREAD_RV_REF(A) rhs)
|
||||
{
|
||||
if(rhs.value==0)
|
||||
throw 9;
|
||||
else
|
||||
{
|
||||
value=rhs.value;
|
||||
rhs.value=0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
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 == false));
|
||||
BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled<A>::value == true));
|
||||
#endif
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
{
|
||||
typedef A T;
|
||||
T i;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
p.emplace();
|
||||
try
|
||||
{
|
||||
T a = f.get(); (void)a;
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (int j)
|
||||
{
|
||||
BOOST_TEST(j == 9);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
}
|
||||
{
|
||||
typedef A T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
p.emplace(3);
|
||||
BOOST_TEST(f.get().value == 3);
|
||||
try
|
||||
{
|
||||
T j(3);
|
||||
p.set_value(boost::move(j));
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (const boost::future_error& e)
|
||||
{
|
||||
BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
boost::promise<movable2> p;
|
||||
boost::future<movable2> f = p.get_future();
|
||||
p.emplace(3);
|
||||
BOOST_TEST(f.get().value_ == 3);
|
||||
try
|
||||
{
|
||||
p.emplace(3);
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (const boost::future_error& e)
|
||||
{
|
||||
BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
boost::promise<A> p;
|
||||
boost::future<A> f = p.get_future();
|
||||
p.emplace(1,2);
|
||||
BOOST_TEST(f.get().value == 3);
|
||||
try
|
||||
{
|
||||
p.emplace(1,2);
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
catch (const boost::future_error& e)
|
||||
{
|
||||
BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
typedef A T;
|
||||
boost::promise<T> p;
|
||||
boost::future<T> f = p.get_future();
|
||||
p.emplace(3);
|
||||
boost::promise<T> p2(boost::move(p));
|
||||
BOOST_TEST(f.get().value == 3);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
215
test/sync/mutual_exclusion/sync_pq/pq_multi_thread_pass.cpp
Normal file
215
test/sync/mutual_exclusion/sync_pq/pq_multi_thread_pass.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
// 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)
|
||||
//
|
||||
|
||||
#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 <exception>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_priority_queue.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
typedef boost::concurrent::sync_priority_queue<int> sync_pq;
|
||||
|
||||
int call_pull(sync_pq* q, boost::barrier* go)
|
||||
{
|
||||
go->wait();
|
||||
return q->pull();
|
||||
|
||||
}
|
||||
|
||||
void call_push(sync_pq* q, boost::barrier* go, int val)
|
||||
{
|
||||
go->wait();
|
||||
q->push(val);
|
||||
}
|
||||
|
||||
void test_pull(const int n)
|
||||
{
|
||||
sync_pq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
pq.push(i);
|
||||
}
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), n);
|
||||
pq.close();
|
||||
BOOST_TEST(pq.closed());
|
||||
boost::barrier b(n);
|
||||
boost::thread_group tg;
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
tg.create_thread(boost::bind(call_pull, &pq, &b));
|
||||
}
|
||||
tg.join_all();
|
||||
BOOST_TEST(pq.empty());
|
||||
}
|
||||
|
||||
void test_push(const int n)
|
||||
{
|
||||
sync_pq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
|
||||
boost::barrier b(n);
|
||||
boost::thread_group tg;
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
tg.create_thread(boost::bind(call_push, &pq, &b, i));
|
||||
}
|
||||
tg.join_all();
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), n);
|
||||
}
|
||||
|
||||
void test_both(const int n)
|
||||
{
|
||||
sync_pq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
|
||||
boost::barrier b(2*n);
|
||||
boost::thread_group tg;
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
tg.create_thread(boost::bind(call_pull, &pq, &b));
|
||||
tg.create_thread(boost::bind(call_push, &pq, &b, i));
|
||||
}
|
||||
tg.join_all();
|
||||
BOOST_TEST(pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), 0);
|
||||
}
|
||||
|
||||
void push_range(sync_pq* q, const int begin, const int end)
|
||||
{
|
||||
for(int i = begin; i < end; i++)
|
||||
q->push(i);
|
||||
}
|
||||
|
||||
void atomic_pull(sync_pq* q, boost::atomic<int>* sum)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
try{
|
||||
const int val = q->pull();
|
||||
sum->fetch_add(val);
|
||||
}
|
||||
catch(std::exception& e ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test computes the sum of the first N integers upto $limit using
|
||||
* $n threads for the push operation and $n threads for the pull and count
|
||||
* operation. The push operation push a range of numbers on the queue while
|
||||
* the pull operation pull from the queue and increments an atomic int.
|
||||
* At the end of execution the value of atomic<int> $sum should be the same
|
||||
* as n*(n+1)/2 as this is the closed form solution to this problem.
|
||||
*/
|
||||
void compute_sum(const int n)
|
||||
{
|
||||
const int limit = 1000;
|
||||
sync_pq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
boost::atomic<int> sum(0);
|
||||
boost::thread_group tg1;
|
||||
boost::thread_group tg2;
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
tg1.create_thread(boost::bind(push_range, &pq, i*(limit/n)+1, (i+1)*(limit/n)+1));
|
||||
tg2.create_thread(boost::bind(atomic_pull, &pq, &sum));
|
||||
}
|
||||
tg1.join_all();
|
||||
pq.close(); //Wait until all enqueuing is done before closing.
|
||||
BOOST_TEST(pq.closed());
|
||||
tg2.join_all();
|
||||
BOOST_TEST(pq.empty());
|
||||
BOOST_TEST_EQ(sum.load(), limit*(limit+1)/2);
|
||||
}
|
||||
|
||||
void move_between_queues(sync_pq* q1, sync_pq* q2)
|
||||
{
|
||||
while(1){
|
||||
try{
|
||||
const int val = q1->pull();
|
||||
q2->push(val);
|
||||
}
|
||||
catch(std::exception& e){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test computes the sum of the first N integers upto $limit by moving
|
||||
* numbers between 2 sync_priority_queues. A range of numbers are pushed onto
|
||||
* one queue by $n threads while $n threads pull from this queue and push onto
|
||||
* another sync_pq. At the end the main thread ensures the the values in the
|
||||
* second queue are in proper order and then sums all the values from this
|
||||
* queue. The sum should match n*(n+1)/2, the closed form solution to this
|
||||
* problem.
|
||||
*/
|
||||
void sum_with_moving(const int n)
|
||||
{
|
||||
const int limit = 1000;
|
||||
sync_pq pq1;
|
||||
sync_pq pq2;
|
||||
BOOST_TEST(pq1.empty());
|
||||
BOOST_TEST(pq2.empty());
|
||||
boost::thread_group tg1;
|
||||
boost::thread_group tg2;
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
tg1.create_thread(boost::bind(push_range, &pq1, i*(limit/n)+1, (i+1)*(limit/n)+1));
|
||||
tg2.create_thread(boost::bind(move_between_queues, &pq1, &pq2));
|
||||
}
|
||||
tg1.join_all();
|
||||
pq1.close(); //Wait until all enqueuing is done before closing.
|
||||
BOOST_TEST(pq1.closed());
|
||||
tg2.join_all();
|
||||
BOOST_TEST(pq1.empty());
|
||||
BOOST_TEST(!pq2.empty());
|
||||
int sum = 0;
|
||||
for(int i = 1000; i > 0; i--){
|
||||
const int val = pq2.pull();
|
||||
BOOST_TEST_EQ(i,val);
|
||||
sum += val;
|
||||
}
|
||||
BOOST_TEST(pq2.empty());
|
||||
BOOST_TEST_EQ(sum, limit*(limit+1)/2);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
for(int i = 1; i <= 64; i *= 2)
|
||||
{
|
||||
test_pull(i);
|
||||
test_push(i);
|
||||
test_both(i);
|
||||
}
|
||||
//These numbers must divide 1000
|
||||
compute_sum(1);
|
||||
compute_sum(4);
|
||||
compute_sum(10);
|
||||
compute_sum(25);
|
||||
compute_sum(50);
|
||||
sum_with_moving(1);
|
||||
sum_with_moving(4);
|
||||
sum_with_moving(10);
|
||||
sum_with_moving(25);
|
||||
sum_with_moving(50);
|
||||
return boost::report_errors();
|
||||
}
|
||||
429
test/sync/mutual_exclusion/sync_pq/pq_single_thread_pass.cpp
Normal file
429
test/sync/mutual_exclusion/sync_pq/pq_single_thread_pass.cpp
Normal file
@@ -0,0 +1,429 @@
|
||||
// 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)
|
||||
//
|
||||
|
||||
#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 <iostream>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_priority_queue.hpp>
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
|
||||
typedef boost::concurrent::sync_priority_queue<int> sync_pq;
|
||||
|
||||
class non_copyable
|
||||
{
|
||||
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
|
||||
int val;
|
||||
public:
|
||||
non_copyable(int v) : val(v){}
|
||||
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
|
||||
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
|
||||
bool operator==(non_copyable const& x) const {return val==x.val;}
|
||||
template <typename OSTREAM>
|
||||
friend OSTREAM& operator <<(OSTREAM& os, non_copyable const&x )
|
||||
{
|
||||
os << x.val;
|
||||
return os;
|
||||
}
|
||||
bool operator <(const non_copyable& other) const
|
||||
{
|
||||
return val < other.val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void test_pull_for()
|
||||
{
|
||||
sync_pq pq;
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
int val;
|
||||
boost::queue_op_status st = pq.pull_for(milliseconds(500), val);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(boost::queue_op_status::timeout == st);
|
||||
BOOST_TEST(diff < milliseconds(510) && diff > milliseconds(500));
|
||||
}
|
||||
|
||||
void test_pull_until()
|
||||
{
|
||||
sync_pq pq;
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
int val;
|
||||
boost::queue_op_status st = pq.pull_until(start + milliseconds(500), val);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(boost::queue_op_status::timeout == st);
|
||||
BOOST_TEST(diff < milliseconds(510) && diff > milliseconds(500));
|
||||
}
|
||||
|
||||
void test_nonblocking_pull()
|
||||
{
|
||||
sync_pq pq;
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
int val;
|
||||
boost::queue_op_status st = pq.nonblocking_pull(val);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(boost::queue_op_status::empty == st);
|
||||
BOOST_TEST(diff < milliseconds(5));
|
||||
}
|
||||
|
||||
void test_pull_for_when_not_empty()
|
||||
{
|
||||
sync_pq pq;
|
||||
pq.push(1);
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
int val;
|
||||
boost::queue_op_status st = pq.pull_for(milliseconds(500), val);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(boost::queue_op_status::success == st);
|
||||
BOOST_TEST(1 == val);
|
||||
BOOST_TEST(diff < milliseconds(5));
|
||||
}
|
||||
|
||||
void test_pull_until_when_not_empty()
|
||||
{
|
||||
sync_pq pq;
|
||||
pq.push(1);
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
int val;
|
||||
boost::queue_op_status st = pq.pull_until(start + milliseconds(500), val);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(boost::queue_op_status::success == st);
|
||||
BOOST_TEST(1 == val);
|
||||
BOOST_TEST(diff < milliseconds(5));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
sync_pq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
BOOST_TEST(!pq.closed());
|
||||
BOOST_TEST_EQ(pq.size(), 0);
|
||||
|
||||
for(int i = 1; i <= 5; i++){
|
||||
pq.push(i);
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), i);
|
||||
}
|
||||
|
||||
for(int i = 6; i <= 10; i++){
|
||||
boost::queue_op_status succ = pq.try_push(i);
|
||||
BOOST_TEST(succ == boost::queue_op_status::success );
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), i);
|
||||
}
|
||||
|
||||
for(int i = 10; i > 5; i--){
|
||||
int val = pq.pull();
|
||||
BOOST_TEST_EQ(val, i);
|
||||
}
|
||||
|
||||
// for(int i = 5; i > 0; i--){
|
||||
// boost::optional<int> val = pq.try_pull();
|
||||
// BOOST_TEST(val);
|
||||
// BOOST_TEST_EQ(*val, i);
|
||||
// }
|
||||
|
||||
// BOOST_TEST(pq.empty());
|
||||
pq.close();
|
||||
BOOST_TEST(pq.closed());
|
||||
|
||||
test_pull_for();
|
||||
test_pull_until();
|
||||
test_nonblocking_pull();
|
||||
|
||||
test_pull_for_when_not_empty();
|
||||
//test_pull_until_when_not_empty();
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if 0
|
||||
{
|
||||
// empty queue try_push rvalue/non-copyable succeeds
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
BOOST_TEST(boost::queue_op_status::success ==q.try_push(non_copyable()));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
{
|
||||
//fixme
|
||||
// empty queue try_push rvalue/non-copyable succeeds
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc(1);
|
||||
BOOST_TEST(boost::queue_op_status::success == q.try_push(boost::move(nc)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// empty queue try_push lvalue succeeds
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
int i=1;
|
||||
BOOST_TEST(boost::queue_op_status::success == q.try_push(i));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
// {
|
||||
// // empty queue try_push rvalue succeeds
|
||||
// boost::concurrent::sync_priority_queue<int> q;
|
||||
// BOOST_TEST(boost::queue_op_status::success == q.nonblocking_push(1));
|
||||
// BOOST_TEST(! q.empty());
|
||||
// BOOST_TEST(! q.full());
|
||||
// BOOST_TEST_EQ(q.size(), 1u);
|
||||
// BOOST_TEST(! q.closed());
|
||||
// }
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if 0
|
||||
{
|
||||
// empty queue nonblocking_push rvalue/non-copyable succeeds
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
BOOST_TEST(boost::queue_op_status::success == q.nonblocking_push(non_copyable(1)));
|
||||
BOOST_TEST(! q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 1u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
// {
|
||||
// // empty queue nonblocking_push rvalue/non-copyable succeeds
|
||||
// boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
// non_copyable nc(1);
|
||||
// BOOST_TEST(boost::queue_op_status::success == q.nonblocking_push(boost::move(nc)));
|
||||
// BOOST_TEST(! q.empty());
|
||||
// BOOST_TEST(! q.full());
|
||||
// BOOST_TEST_EQ(q.size(), 1u);
|
||||
// BOOST_TEST(! q.closed());
|
||||
// }
|
||||
#endif
|
||||
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
int i;
|
||||
i=q.pull();
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc2(2);
|
||||
nc2=q.pull();
|
||||
BOOST_TEST_EQ(nc1, nc2);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
int i = q.pull();
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
{
|
||||
// 1-element queue pull succeed
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc = q.pull();
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
int i;
|
||||
BOOST_TEST(boost::queue_op_status::success == q.try_pull(i));
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
{
|
||||
// 1-element queue try_pull succeed
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc(2);
|
||||
BOOST_TEST(boost::queue_op_status::success == q.try_pull(nc));
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// 1-element queue nonblocking_pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
int i;
|
||||
BOOST_TEST(boost::queue_op_status::success == q.nonblocking_pull(i));
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
{
|
||||
// 1-element queue nonblocking_pull succeed
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc(2);
|
||||
BOOST_TEST(boost::queue_op_status::success == q.nonblocking_pull(nc));
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element queue wait_pull succeed
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc(2);
|
||||
BOOST_TEST(boost::queue_op_status::success == q.wait_pull(nc));
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// 1-element queue wait_pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
int i;
|
||||
BOOST_TEST(boost::queue_op_status::success == q.wait_pull(i));
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
{
|
||||
// 1-element queue wait_pull succeed
|
||||
boost::concurrent::sync_priority_queue<non_copyable> q;
|
||||
non_copyable nc1(1);
|
||||
q.push(boost::move(nc1));
|
||||
non_copyable nc(2);
|
||||
BOOST_TEST(boost::queue_op_status::success == q.wait_pull(nc));
|
||||
BOOST_TEST_EQ(nc, nc1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(! q.closed());
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// closed invariants
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.close();
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(q.closed());
|
||||
}
|
||||
{
|
||||
// closed queue push fails
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.close();
|
||||
try {
|
||||
q.push(1);
|
||||
BOOST_TEST(false); // fixme
|
||||
} catch (...) {
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(q.closed());
|
||||
}
|
||||
}
|
||||
{
|
||||
// 1-element closed queue pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
q.close();
|
||||
int i;
|
||||
i=q.pull();
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(q.closed());
|
||||
}
|
||||
{
|
||||
// 1-element closed queue wait_pull succeed
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.push(1);
|
||||
q.close();
|
||||
int i;
|
||||
BOOST_TEST(boost::queue_op_status::success == q.wait_pull(i));
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(! q.full());
|
||||
BOOST_TEST_EQ(q.size(), 0u);
|
||||
BOOST_TEST(q.closed());
|
||||
}
|
||||
{
|
||||
// closed empty queue wait_pull fails
|
||||
boost::concurrent::sync_priority_queue<int> q;
|
||||
q.close();
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(q.closed());
|
||||
int i;
|
||||
BOOST_TEST(boost::queue_op_status::closed == q.wait_pull(i));
|
||||
BOOST_TEST(q.empty());
|
||||
BOOST_TEST(q.closed());
|
||||
}
|
||||
return boost::report_errors();
|
||||
}
|
||||
155
test/sync/mutual_exclusion/sync_pq/tq_single_thread_pass.cpp
Normal file
155
test/sync/mutual_exclusion/sync_pq/tq_single_thread_pass.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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)
|
||||
//
|
||||
|
||||
#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.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_timed_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
|
||||
typedef boost::concurrent::sync_timed_queue<int> sync_tq;
|
||||
|
||||
void test_all()
|
||||
{
|
||||
sync_tq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
BOOST_TEST(!pq.closed());
|
||||
BOOST_TEST_EQ(pq.size(), 0);
|
||||
|
||||
for(int i = 1; i <= 5; i++){
|
||||
pq.push(i, milliseconds(i*100));
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), i);
|
||||
}
|
||||
|
||||
for(int i = 6; i <= 10; i++){
|
||||
pq.push(i,steady_clock::now() + milliseconds(i*100));
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), i);
|
||||
}
|
||||
|
||||
for(int i = 1; i <= 10; i++){
|
||||
int val = pq.pull();
|
||||
BOOST_TEST_EQ(val, i);
|
||||
}
|
||||
|
||||
int val;
|
||||
boost::queue_op_status st = pq.nonblocking_pull(val);
|
||||
BOOST_TEST(boost::queue_op_status::empty == st);
|
||||
|
||||
BOOST_TEST(pq.empty());
|
||||
pq.close();
|
||||
BOOST_TEST(pq.closed());
|
||||
}
|
||||
|
||||
void test_all_with_try()
|
||||
{
|
||||
sync_tq pq;
|
||||
BOOST_TEST(pq.empty());
|
||||
BOOST_TEST(!pq.closed());
|
||||
BOOST_TEST_EQ(pq.size(), 0);
|
||||
|
||||
for(int i = 1; i <= 5; i++){
|
||||
boost::queue_op_status st = pq.try_push(i, milliseconds(i*100));
|
||||
BOOST_TEST(st == boost::queue_op_status::success );
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), i);
|
||||
}
|
||||
|
||||
for(int i = 6; i <= 10; i++){
|
||||
boost::queue_op_status st = pq.try_push(i,steady_clock::now() + milliseconds(i*100));
|
||||
BOOST_TEST(st == boost::queue_op_status::success );
|
||||
BOOST_TEST(!pq.empty());
|
||||
BOOST_TEST_EQ(pq.size(), i);
|
||||
}
|
||||
|
||||
for(int i = 1; i <= 10; i++){
|
||||
int val=0;
|
||||
boost::queue_op_status st = pq.wait_pull(val);
|
||||
BOOST_TEST(st == boost::queue_op_status::success );
|
||||
BOOST_TEST_EQ(val, i);
|
||||
}
|
||||
|
||||
int val;
|
||||
boost::queue_op_status st = pq.nonblocking_pull(val);
|
||||
BOOST_TEST(st == boost::queue_op_status::empty );
|
||||
|
||||
BOOST_TEST(pq.empty());
|
||||
pq.close();
|
||||
BOOST_TEST(pq.closed());
|
||||
}
|
||||
|
||||
void func(steady_clock::time_point pushed, steady_clock::duration dur)
|
||||
{
|
||||
BOOST_TEST(pushed + dur <= steady_clock::now());
|
||||
}
|
||||
void func2()
|
||||
{
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that when items come of the front of the queue
|
||||
* that at least $dur has elapsed.
|
||||
*/
|
||||
void test_deque_times()
|
||||
{
|
||||
boost::concurrent::sync_timed_queue<boost::function<void()> > tq;
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
steady_clock::duration d = milliseconds(i*100);
|
||||
boost::function<void()> fn = boost::bind(func, steady_clock::now(), d);
|
||||
tq.push(fn, d);
|
||||
}
|
||||
while(!tq.empty())
|
||||
{
|
||||
boost::function<void()> fn = tq.pull();
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that when items come of the front of the queue
|
||||
* that at least $dur has elapsed.
|
||||
*/
|
||||
#if 0
|
||||
void test_deque_times2()
|
||||
{
|
||||
boost::concurrent::sync_timed_queue<boost::executors::work> tq;
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
steady_clock::duration d = milliseconds(i*100);
|
||||
tq.push(func2, d);
|
||||
}
|
||||
while(!tq.empty())
|
||||
{
|
||||
boost::executors::work fn = tq.pull();
|
||||
fn();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
test_all();
|
||||
test_all_with_try();
|
||||
test_deque_times();
|
||||
//test_deque_times2(); // rt fails
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -72,7 +72,7 @@ void test_bind() {
|
||||
BOOST_TEST(c == 345);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
void test_bind_non_const() {
|
||||
std::cout << "c++11 variadic templates disabled" << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -81,7 +86,7 @@
|
||||
|
||||
#if defined EXAMPLE_3
|
||||
//! Doesn't compile in C++03.
|
||||
//! error: variable ‘boost::packaged_task<std::basic_string<char>(std::basic_string<char>&)> example’ has initializer but incomplete type
|
||||
//! error: variable âboost::packaged_task<std::basic_string<char>(std::basic_string<char>&)> exampleâ has initializer but incomplete type
|
||||
|
||||
{
|
||||
boost::packaged_task<std::string(std::string&)> example(string_with_params);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
89
test/test_scheduled_tp.cpp
Normal file
89
test/test_scheduled_tp.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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)
|
||||
//
|
||||
|
||||
#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/bind.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/executors/scheduled_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
|
||||
typedef boost::scheduled_thread_pool scheduled_tp;
|
||||
|
||||
void fn(int x)
|
||||
{
|
||||
std::cout << x << std::endl;
|
||||
}
|
||||
|
||||
void func(steady_clock::time_point pushed, steady_clock::duration dur)
|
||||
{
|
||||
BOOST_TEST(pushed + dur < steady_clock::now());
|
||||
}
|
||||
|
||||
void test_timing(const int n)
|
||||
{
|
||||
//This function should take n seconds to execute.
|
||||
boost::scheduled_thread_pool se(4);
|
||||
|
||||
for(int i = 1; i <= n; i++)
|
||||
{
|
||||
se.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
||||
}
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
//dtor is called here so all task will have to be executed before we return
|
||||
}
|
||||
|
||||
void test_deque_timing()
|
||||
{
|
||||
boost::scheduled_thread_pool se(4);
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
steady_clock::duration d = milliseconds(i*100);
|
||||
boost::function<void()> fn = boost::bind(func,steady_clock::now(),d);
|
||||
se.submit_after(fn,d);
|
||||
}
|
||||
}
|
||||
|
||||
void test_deque_multi(const int n)
|
||||
{
|
||||
scheduled_tp se(4);
|
||||
boost::thread_group tg;
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
steady_clock::duration d = milliseconds(i*100);
|
||||
boost::function<void()> fn = boost::bind(func,steady_clock::now(),d);
|
||||
tg.create_thread(boost::bind(boost::mem_fn(&scheduled_tp::submit_after), &se, fn, d));
|
||||
}
|
||||
tg.join_all();
|
||||
//dtor is called here so execution will block untill all the closures
|
||||
//have been completed.
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
test_timing(5);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(diff > milliseconds(500));
|
||||
test_deque_timing();
|
||||
test_deque_multi(4);
|
||||
test_deque_multi(8);
|
||||
test_deque_multi(16);
|
||||
return boost::report_errors();
|
||||
}
|
||||
81
test/test_scheduler.cpp
Normal file
81
test/test_scheduler.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// 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)
|
||||
//
|
||||
|
||||
#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/executors/scheduler.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
|
||||
|
||||
typedef boost::executors::basic_thread_pool thread_pool;
|
||||
|
||||
void fn(int x)
|
||||
{
|
||||
//std::cout << "[" << __LINE__ << "] " << steady_clock::now() << std::endl;
|
||||
std::cout << x << std::endl;
|
||||
}
|
||||
|
||||
void test_scheduler(const int n, boost::scheduler& sch)
|
||||
{
|
||||
for(int i = 1; i <= n; i++)
|
||||
{
|
||||
sch.submit_after(boost::bind(fn,i), seconds(i));
|
||||
sch.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
||||
}
|
||||
}
|
||||
|
||||
void test_after(const int n, boost::scheduler& sch)
|
||||
{
|
||||
for(int i = 1; i <= n; i++)
|
||||
{
|
||||
sch.after(seconds(i)).submit(boost::bind(fn,i));
|
||||
sch.after(milliseconds(i*100)).submit(boost::bind(fn,i));
|
||||
}
|
||||
}
|
||||
|
||||
void test_at(const int n, boost::scheduler& sch)
|
||||
{
|
||||
for(int i = 1; i <= n; i++)
|
||||
{
|
||||
sch.at(steady_clock::now()+seconds(i)).submit(boost::bind(fn,i));
|
||||
sch.at(steady_clock::now()+milliseconds(i*100)).submit(boost::bind(fn,i));
|
||||
}
|
||||
}
|
||||
|
||||
void test_on(const int n, boost::scheduler& sch, thread_pool& tp)
|
||||
{
|
||||
for(int i = 1; i <= n; i++)
|
||||
{
|
||||
sch.on(tp).after(seconds(i)).submit(boost::bind(fn,i));
|
||||
sch.on(tp).after(milliseconds(i*100)).submit(boost::bind(fn,i));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
thread_pool tp(4);
|
||||
boost::scheduler sch;
|
||||
test_scheduler(5, sch);
|
||||
test_after(5, sch);
|
||||
test_at(5, sch);
|
||||
test_on(5, sch, tp);
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
54
test/test_scheduling_adaptor.cpp
Normal file
54
test/test_scheduling_adaptor.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// 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)
|
||||
//
|
||||
|
||||
#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/function.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/scheduling_adaptor.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
|
||||
|
||||
typedef boost::executors::basic_thread_pool thread_pool;
|
||||
|
||||
void fn(int x)
|
||||
{
|
||||
//std::cout << "[" << __LINE__ << "] " << steady_clock::now() << std::endl;
|
||||
std::cout << x << std::endl;
|
||||
}
|
||||
|
||||
void test_timing(const int n)
|
||||
{
|
||||
thread_pool tp(4);
|
||||
boost::scheduling_adpator<thread_pool> sa(tp);
|
||||
for(int i = 1; i <= n; i++)
|
||||
{
|
||||
sa.submit_after(boost::bind(fn,i),seconds(i));
|
||||
sa.submit_after(boost::bind(fn,i), milliseconds(i*100));
|
||||
}
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
steady_clock::time_point start = steady_clock::now();
|
||||
test_timing(5);
|
||||
steady_clock::duration diff = steady_clock::now() - start;
|
||||
BOOST_TEST(diff > seconds(5));
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
// 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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user