mirror of
https://github.com/boostorg/thread.git
synced 2026-02-13 12:52:11 +00:00
Compare commits
25 Commits
boost-1.57
...
feature/ex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -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.
|
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]
|
[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:
|
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`.
|
* have a single instance of a `scheduled_executor<Clock>` for each `CLock`.
|
||||||
|
|
||||||
The library chose the first of those options, largely for simplicity.
|
The library chose the first of those options, largely for simplicity.
|
||||||
]
|
|
||||||
|
|
||||||
[heading Not Handled Exceptions]
|
[heading Not Handled Exceptions]
|
||||||
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
|
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
|
||||||
@@ -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.
|
The library would provide in the future a cancelable_task that could support cancelation.
|
||||||
|
|
||||||
class cancelation_state {
|
class cancelation_state
|
||||||
std::atomic<bool> requested; std::atomic<bool> enabled; std::condition_variable* cond; std::mutex cond_mutex;
|
{
|
||||||
|
std::atomic<bool> requested;
|
||||||
|
std::atomic<bool> enabled;
|
||||||
|
std::condition_variable* cond;
|
||||||
|
std::mutex cond_mutex;
|
||||||
public:
|
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); }
|
cancelation_state() :
|
||||||
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(); } };
|
thread_cond(0)
|
||||||
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(); }
|
void cancel()
|
||||||
class disable_cancelation
|
{
|
||||||
|
requested.store(true, std::memory_order_relaxed);
|
||||||
|
std::lock_guard < std::mutex > lk(cond_mutex);
|
||||||
|
if (cond)
|
||||||
{
|
{
|
||||||
public:
|
cond->notify_all();
|
||||||
disable_cancelation(const disable_cancelation&) = delete;
|
}
|
||||||
disable_cancelation& operator=(const disable_cancelation&) = delete;
|
}
|
||||||
disable_cancelation(cancelable_closure& closure) noexcept;
|
bool cancellation_requested() const
|
||||||
~disable_cancelation() noexcept;
|
{
|
||||||
};
|
return requested.load(std::memory_order_relaxed);
|
||||||
class restore_cancelation
|
}
|
||||||
|
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()
|
||||||
{
|
{
|
||||||
public:
|
this_thread_interrupt_flag.clear_condition_variable();
|
||||||
restore_cancelation(const restore_cancelation&) = delete;
|
}
|
||||||
restore_cancelation& operator=(const restore_cancelation&) = delete;
|
};
|
||||||
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
|
void cancelation_point();
|
||||||
~restore_cancelation() noexcept;
|
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>
|
template <class Closure>
|
||||||
struct cancelable_closure_mixin : cancelable_closure {
|
struct cancelable_closure_mixin: cancelable_closure
|
||||||
void operator() {
|
{
|
||||||
cancel_point();
|
void operator()
|
||||||
this->Closure::run();
|
{
|
||||||
}
|
cancel_point();this->Closure::run();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct my_clousure : cancelable_closure_mixin<my_clousure>
|
struct my_clousure: cancelable_closure_mixin<my_clousure>
|
||||||
{
|
{
|
||||||
void run() {
|
void run()
|
||||||
while () {
|
{
|
||||||
cancel_point();
|
while ()
|
||||||
}
|
{
|
||||||
}
|
cancel_point();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[heading Current executor]
|
[heading Current executor]
|
||||||
@@ -512,7 +569,7 @@ Polymorphic adaptor of a model of Executor to an executor.
|
|||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
executor_adaptor(Args&& ... args);
|
executor_adaptor(Args&& ... args);
|
||||||
|
|
||||||
Executor& underlying_executor();
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
bool closed();
|
bool closed();
|
||||||
@@ -558,14 +615,12 @@ Polymorphic adaptor of a model of Executor to an executor.
|
|||||||
[/////////////////////////////////////]
|
[/////////////////////////////////////]
|
||||||
[section:underlying_executor Function member `underlying_executor()`]
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
|
|
||||||
Executor& underlying_executor();
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
[[Return:] [The underlying executor instance. ]]
|
[[Return:] [The underlying executor instance. ]]
|
||||||
|
|
||||||
[[Throws:] [Nothing.]]
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -587,7 +642,7 @@ Executor abstract base class.
|
|||||||
generic_executor_ref& operator=(generic_executor_ref const&);
|
generic_executor_ref& operator=(generic_executor_ref const&);
|
||||||
|
|
||||||
template <class Executor>
|
template <class Executor>
|
||||||
executor(Executor& ex);
|
generic_executor_ref(Executor& ex);
|
||||||
generic_executor_ref() {};
|
generic_executor_ref() {};
|
||||||
|
|
||||||
void close() = 0;
|
void close() = 0;
|
||||||
@@ -605,28 +660,27 @@ Executor abstract base class.
|
|||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
[/
|
|
||||||
[//////////////////////////////////////////////////////////]
|
[//////////////////////////////////////////////////////////]
|
||||||
[section:scheduled_executor Template Class `scheduled_executor`]
|
[section:scheduled_executor_ref Template Class `scheduled_executor_ref`]
|
||||||
|
|
||||||
Executor providing time related functions.
|
Executor providing time related functions.
|
||||||
|
|
||||||
#include <boost/thread/scheduled_executor.hpp>
|
#include <boost/thread/executors/scheduled_executor_ref.hpp>
|
||||||
namespace boost {
|
namespace boost {
|
||||||
template <class Executor>
|
template <class Executor>
|
||||||
class scheduled_executor
|
class scheduled_executor_ref
|
||||||
{
|
{
|
||||||
Executor& ex;
|
Executor& ex;
|
||||||
public:
|
public:
|
||||||
typedef executor::work work;
|
typedef executor::work work;
|
||||||
|
|
||||||
scheduled_executor(scheduled_executor const&) = delete;
|
scheduled_executor_ref(scheduled_executor_ref const&) = delete;
|
||||||
scheduled_executor& operator=(scheduled_executor const&) = delete;
|
scheduled_executor_ref& operator=(scheduled_executor_ref const&) = delete;
|
||||||
|
|
||||||
template <class Rep, class 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));
|
||||||
|
|
||||||
Executor& underlying_executor();
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
bool closed();
|
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>
|
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
|
[variablelist
|
||||||
|
|
||||||
[[Effects:] [Constructs a scheduled_executor. ]]
|
[[Effects:] [Constructs a scheduled_executor_ref. ]]
|
||||||
|
|
||||||
[[Throws:] [Nothing. ]]
|
[[Throws:] [Nothing. ]]
|
||||||
|
|
||||||
@@ -668,9 +722,9 @@ Executor providing time related functions.
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
[/////////////////////////////////////]
|
[/////////////////////////////////////]
|
||||||
[section:destructor Destructor `~scheduled_executor()`]
|
[section:destructor Destructor `~scheduled_executor_ref()`]
|
||||||
|
|
||||||
~scheduled_executor();
|
~scheduled_executor_ref();
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
@@ -684,12 +738,29 @@ Executor providing time related functions.
|
|||||||
[/////////////////////////////////////]
|
[/////////////////////////////////////]
|
||||||
[section:underlying_executor Function member `underlying_executor()`]
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
|
|
||||||
Executor& underlying_executor();
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
[[Return:] [The underlying executor instance. ]]
|
[[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.]]
|
[[Throws:] [Nothing.]]
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -697,16 +768,18 @@ Executor providing time related functions.
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
[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.
|
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||||
|
|
||||||
#include <boost/thread/serial_executor.hpp>
|
#include <boost/thread/serial_executor.hpp>
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
template <class Executor>
|
||||||
class serial_executor
|
class serial_executor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -716,7 +789,7 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
template <class Executor>
|
template <class Executor>
|
||||||
serial_executor(Executor& ex);
|
serial_executor(Executor& ex);
|
||||||
|
|
||||||
generic_executor_ref underlying_executor();
|
Executor& underlying_executor() noexcept;
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
bool closed();
|
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()`]
|
[section:underlying_executor Function member `underlying_executor()`]
|
||||||
|
|
||||||
generic_executor_ref underlying_executor();
|
generic_executor_ref& underlying_executor() noexcept;
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
@@ -779,6 +852,84 @@ A serial executor ensuring that there are no two work units that executes concur
|
|||||||
|
|
||||||
[endsect]
|
[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`]
|
[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.
|
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 {
|
namespace boost {
|
||||||
class basic_thread_pool
|
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()`]
|
[section:destructor Destructor `~basic_thread_pool()`]
|
||||||
|
|
||||||
virtual ~basic_thread_pool();
|
~basic_thread_pool();
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
@@ -905,6 +1056,64 @@ A thread pool with up to a fixed number of threads.
|
|||||||
|
|
||||||
[endsect]
|
[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`]
|
[section:loop_executor Class `loop_executor`]
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
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)
|
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||||
|
|
||||||
struct sync_queue_is_closed : std::exception
|
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;
|
typedef csbl::vector<thread_t> thread_vector;
|
||||||
|
|
||||||
/// the thread safe work queue
|
/// the thread safe work queue
|
||||||
sync_queue<work > work_queue;
|
concurrent::sync_queue<work > work_queue;
|
||||||
/// A move aware vector
|
/// A move aware vector
|
||||||
thread_vector threads;
|
thread_vector threads;
|
||||||
|
|
||||||
@@ -48,9 +48,9 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
bool try_executing_one()
|
bool try_executing_one()
|
||||||
{
|
{
|
||||||
work task;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
work task;
|
||||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||||
{
|
{
|
||||||
task();
|
task();
|
||||||
@@ -58,12 +58,9 @@ namespace executors
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (std::exception& )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
std::terminate();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,12 +92,9 @@ namespace executors
|
|||||||
task();
|
task();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
std::terminate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +128,7 @@ namespace executors
|
|||||||
*
|
*
|
||||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||||
*/
|
*/
|
||||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
|
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
|
||||||
{
|
{
|
||||||
try
|
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
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
bool closed_;
|
bool closed_;
|
||||||
|
mutable mutex mtx_;
|
||||||
/**
|
/**
|
||||||
* Effects: try to execute one task.
|
* Effects: try to execute one task.
|
||||||
* Returns: whether a task has been executed.
|
* Returns: whether a task has been executed.
|
||||||
@@ -66,16 +67,22 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
closed_ = true;
|
closed_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Returns: whether the pool is closed for submissions.
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
*/
|
*/
|
||||||
bool closed()
|
bool closed(lock_guard<mutex>& )
|
||||||
{
|
{
|
||||||
return closed_;
|
return closed_;
|
||||||
}
|
}
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
return closed(lk);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
* \b 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>
|
template <typename Closure>
|
||||||
void submit(Closure & 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
|
#endif
|
||||||
void submit(void (*closure)())
|
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>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_FWD_REF(Closure) 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;
|
typedef executors::work work;
|
||||||
private:
|
private:
|
||||||
/// the thread safe work queue
|
/// the thread safe work queue
|
||||||
sync_queue<work > work_queue;
|
concurrent::sync_queue<work > work_queue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -51,12 +51,9 @@ namespace executors
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (std::exception& )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
std::terminate();
|
||||||
return false;
|
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:
|
public:
|
||||||
/// loop_executor is not copyable.
|
/// 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.
|
* \b Effects: close the \c loop_executor for submissions.
|
||||||
* The loop will work until there is no more closures to run.
|
* 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;
|
typedef scoped_thread<> thread_t;
|
||||||
|
|
||||||
/// the thread safe work queue
|
/// the thread safe work queue
|
||||||
sync_queue<work > work_queue;
|
concurrent::sync_queue<work > work_queue;
|
||||||
generic_executor_ref ex;
|
generic_executor_ref ex;
|
||||||
thread_t thr;
|
thread_t thr;
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ namespace executors
|
|||||||
try_executing_one_task(work& task, boost::promise<void> &p)
|
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||||
: task(task), p(p) {}
|
: task(task), p(p) {}
|
||||||
void operator()() {
|
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();
|
p.set_value();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -52,7 +52,7 @@ namespace executors
|
|||||||
* \par Returns
|
* \par Returns
|
||||||
* The underlying executor wrapped on a generic executor reference.
|
* 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.
|
* Effects: try to execute one task.
|
||||||
@@ -69,22 +69,14 @@ namespace executors
|
|||||||
boost::promise<void> p;
|
boost::promise<void> p;
|
||||||
try_executing_one_task tmp(task,p);
|
try_executing_one_task tmp(task,p);
|
||||||
ex.submit(tmp);
|
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();
|
p.get_future().wait();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (std::exception& )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
std::terminate();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +128,7 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
~serial_executor()
|
~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();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include <boost/thread/executors/work.hpp>
|
#include <boost/thread/executors/work.hpp>
|
||||||
#include <boost/thread/executors/executor.hpp>
|
#include <boost/thread/executors/executor.hpp>
|
||||||
#include <boost/thread/thread_only.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>
|
#include <boost/config/abi_prefix.hpp>
|
||||||
|
|
||||||
@@ -28,6 +30,11 @@ namespace executors
|
|||||||
/// type-erasure to store the works to do
|
/// type-erasure to store the works to do
|
||||||
typedef executors::work work;
|
typedef executors::work work;
|
||||||
bool closed_;
|
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.
|
* Effects: try to execute one task.
|
||||||
* Returns: whether a task has been executed.
|
* 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.
|
* \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.
|
// signal to all the worker thread that there will be no more submissions.
|
||||||
close();
|
close();
|
||||||
|
// all the scoped threads will join before destroying
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,16 +76,22 @@ namespace executors
|
|||||||
*/
|
*/
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
closed_ = true;
|
closed_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Returns: whether the pool is closed for submissions.
|
* \b Returns: whether the pool is closed for submissions.
|
||||||
*/
|
*/
|
||||||
bool closed()
|
bool closed(lock_guard<mutex>& )
|
||||||
{
|
{
|
||||||
return closed_;
|
return closed_;
|
||||||
}
|
}
|
||||||
|
bool closed()
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lk(mtx_);
|
||||||
|
return closed(lk);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
* \b 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>
|
template <typename Closure>
|
||||||
void submit(Closure & 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);
|
thread th(closure);
|
||||||
th.detach();
|
threads_.push_back(thread_t(boost::move(th)));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void submit(void (*closure)())
|
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);
|
thread th(closure);
|
||||||
th.detach();
|
threads_.push_back(thread_t(boost::move(th)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Closure>
|
template <typename Closure>
|
||||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||||
{
|
{
|
||||||
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));
|
thread th(boost::forward<Closure>(closure));
|
||||||
th.detach();
|
threads_.push_back(thread_t(boost::move(th)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,712 +11,6 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/concurrent_queues/sync_bounded_queue.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>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,653 +11,6 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <boost/thread/detail/config.hpp>
|
#include <boost/thread/concurrent_queues/sync_queue.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>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -675,6 +675,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 ]
|
[ 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
|
test-suite ts_queue_views
|
||||||
:
|
:
|
||||||
[ thread-run2-noit ./sync/mutual_exclusion/queue_views/single_thread_pass.cpp : queue_views__single_thread_p ]
|
[ thread-run2-noit ./sync/mutual_exclusion/queue_views/single_thread_pass.cpp : queue_views__single_thread_p ]
|
||||||
|
|||||||
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);
|
BOOST_TEST(c == 345);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BOOST_NO_VARIADIC_TEMPLATES)
|
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||||
void test_bind_non_const() {
|
void test_bind_non_const() {
|
||||||
std::cout << "c++11 variadic templates disabled" << std::endl;
|
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
|
#define BOOST_THREAD_VERSION 4
|
||||||
|
|
||||||
#include <boost/thread/future.hpp>
|
#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/shared_memory_object.hpp>
|
||||||
#include <boost/interprocess/mapped_region.hpp>
|
#include <boost/interprocess/mapped_region.hpp>
|
||||||
#include <boost/thread.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
|
#define BOOST_THREAD_VERSION 4
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -81,7 +86,7 @@
|
|||||||
|
|
||||||
#if defined EXAMPLE_3
|
#if defined EXAMPLE_3
|
||||||
//! Doesn't compile in C++03.
|
//! 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);
|
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
|
||||||
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
#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
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user