| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // Copyright (C) 2014 Vicente Botet | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
|
|
||
| #define BOOST_THREAD_VERSION 4 | ||
| #define BOOST_THREAD_PROVIDES_EXECUTORS | ||
| #define BOOST_THREAD_USES_LOG_THREAD_ID | ||
| #define BOOST_THREAD_QUEUE_DEPRECATE_OLD | ||
| #if ! defined BOOST_NO_CXX11_DECLTYPE | ||
| //#define BOOST_RESULT_OF_USE_DECLTYPE | ||
| #endif | ||
|
|
||
| #include <boost/thread/executors/basic_thread_pool.hpp> | ||
| #include <boost/thread/future.hpp> | ||
|
|
||
| #include <numeric> | ||
| #include <algorithm> | ||
| #include <functional> | ||
| #include <iostream> | ||
| #include <vector> | ||
|
|
||
| #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) | ||
|
|
||
| template<typename Iterator,typename T> | ||
| struct accumulate_block | ||
| { | ||
| //typedef T result_type; | ||
| T operator()(Iterator first,Iterator last) | ||
| { | ||
| return std::accumulate(first,last,T()); | ||
| } | ||
| }; | ||
|
|
||
| template<typename Iterator,typename T> | ||
| T parallel_accumulate(Iterator first,Iterator last,T init) | ||
| { | ||
| unsigned long const length=std::distance(first,last); | ||
|
|
||
| if(!length) | ||
| return init; | ||
|
|
||
| unsigned long const block_size=25; | ||
| unsigned long const num_blocks=(length+block_size-1)/block_size; | ||
|
|
||
| boost::csbl::vector<boost::future<T> > futures(num_blocks-1); | ||
| boost::basic_thread_pool pool; | ||
|
|
||
| Iterator block_start=first; | ||
| for(unsigned long i=0;i<(num_blocks-1);++i) | ||
| { | ||
| Iterator block_end=block_start; | ||
| std::advance(block_end,block_size); | ||
| futures[i]=boost::async(pool, accumulate_block<Iterator,T>(), block_start, block_end); | ||
| block_start=block_end; | ||
| } | ||
| T last_result=accumulate_block<Iterator,T>()(block_start,last); | ||
| T result=init; | ||
| for(unsigned long i=0;i<(num_blocks-1);++i) | ||
| { | ||
| result+=futures[i].get(); | ||
| } | ||
| result += last_result; | ||
| return result; | ||
| } | ||
|
|
||
|
|
||
| int main() | ||
| { | ||
| try | ||
| { | ||
| const int s = 1001; | ||
| std::vector<int> vec; | ||
| vec.reserve(s); | ||
| for (int i=0; i<s;++i) | ||
| vec.push_back(1); | ||
| int r = parallel_accumulate(vec.begin(), vec.end(),0); | ||
| std::cout << r << std::endl; | ||
|
|
||
| } | ||
| catch (std::exception& ex) | ||
| { | ||
| std::cout << "ERROR= " << ex.what() << "" << std::endl; | ||
| return 1; | ||
| } | ||
| catch (...) | ||
| { | ||
| std::cout << " ERROR= exception thrown" << std::endl; | ||
| return 2; | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| #else | ||
| ///#warning "This compiler doesn't supports variadics" | ||
| int main() | ||
| { | ||
| return 0; | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // (C) Copyright 2013 Ruslan Baratov | ||
| // Copyright (C) 2014 Vicente Botet | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
|
|
||
| // See www.boost.org/libs/thread for documentation. | ||
|
|
||
| #define BOOST_THREAD_VERSION 4 | ||
|
|
||
| #include <iostream> // std::cout | ||
| #include <boost/thread/scoped_thread.hpp> | ||
| #include <boost/thread/with_lock_guard.hpp> | ||
|
|
||
| boost::mutex m; // protection for 'x' and 'std::cout' | ||
| int x; | ||
|
|
||
| #if defined(BOOST_NO_CXX11_LAMBDAS) | ||
| void print_x() { | ||
| ++x; | ||
| std::cout << "x = " << x << std::endl; | ||
| } | ||
|
|
||
| void job() { | ||
| for (int i = 0; i < 10; ++i) { | ||
| boost::with_lock_guard(m, print_x); | ||
| boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); | ||
| } | ||
| } | ||
| #else | ||
| void job() { | ||
| for (int i = 0; i < 10; ++i) { | ||
| boost::with_lock_guard( | ||
| m, | ||
| []() { | ||
| ++x; | ||
| std::cout << "x = " << x << std::endl; | ||
| } | ||
| ); | ||
| boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| int main() { | ||
| #if defined(BOOST_NO_CXX11_LAMBDAS) | ||
| std::cout << "(no lambdas)" << std::endl; | ||
| #endif | ||
| boost::scoped_thread<> thread_1(job); | ||
| boost::scoped_thread<> thread_2(job); | ||
| boost::scoped_thread<> thread_3(job); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // Distributed under the Boost Software License, Version 1.0. (See | ||
| // accompanying file LICENSE_1_0.txt or copy at | ||
| // http://www.boost.org/LICENSE_1_0.txt) | ||
| // (C) Copyright 2014 Vicente J. Botet Escriba | ||
|
|
||
| #ifndef BOOST_THREAD_EXCEPTIONAL_PTR_HPP | ||
| #define BOOST_THREAD_EXCEPTIONAL_PTR_HPP | ||
|
|
||
| #include <boost/thread/detail/move.hpp> | ||
| #include <boost/exception_ptr.hpp> | ||
|
|
||
| #include <boost/config/abi_prefix.hpp> | ||
|
|
||
| namespace boost | ||
| { | ||
| struct exceptional_ptr { | ||
| exception_ptr ptr_; | ||
|
|
||
| exceptional_ptr() : ptr_() {} | ||
| explicit exceptional_ptr(exception_ptr ex) : ptr_(ex) {} | ||
| template <class E> | ||
| explicit exceptional_ptr(BOOST_FWD_REF(E) ex) : ptr_(boost::copy_exception(boost::forward<E>(ex))) {} | ||
| }; | ||
|
|
||
| template <class E> | ||
| inline exceptional_ptr make_exceptional(BOOST_FWD_REF(E) ex) { | ||
| return exceptional_ptr(boost::forward<E>(ex)); | ||
| } | ||
|
|
||
| inline exceptional_ptr make_exceptional(exception_ptr ex) | ||
| { | ||
| return exceptional_ptr(ex); | ||
| } | ||
|
|
||
| inline exceptional_ptr make_exceptional() | ||
| { | ||
| return exceptional_ptr(); | ||
| } | ||
|
|
||
| } // namespace boost | ||
|
|
||
| #include <boost/config/abi_suffix.hpp> | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,326 @@ | ||
| // Copyright (C) 2013 Vicente J. Botet Escriba | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| // | ||
| // 2013/09 Vicente J. Botet Escriba | ||
| // Adapt to boost from CCIA C++11 implementation | ||
| // first implementation of a simple pool thread using a vector of threads and a sync_queue. | ||
|
|
||
| #ifndef BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP | ||
| #define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP | ||
|
|
||
| #include <boost/thread/detail/config.hpp> | ||
| #include <boost/thread/detail/delete.hpp> | ||
| #include <boost/thread/detail/move.hpp> | ||
| #include <boost/thread/scoped_thread.hpp> | ||
| #include <boost/thread/sync_queue.hpp> | ||
| #include <boost/thread/executors/work.hpp> | ||
| #include <boost/thread/csbl/vector.hpp> | ||
|
|
||
| #include <boost/config/abi_prefix.hpp> | ||
|
|
||
| namespace boost | ||
| { | ||
| namespace executors | ||
| { | ||
| class basic_thread_pool | ||
| { | ||
| public: | ||
| /// type-erasure to store the works to do | ||
| typedef executors::work work; | ||
| private: | ||
| /// the kind of stored threads are scoped threads to ensure that the threads are joined. | ||
| /// A move aware vector type | ||
| typedef scoped_thread<> thread_t; | ||
| typedef csbl::vector<thread_t> thread_vector; | ||
|
|
||
| /// the thread safe work queue | ||
| sync_queue<work > work_queue; | ||
| /// A move aware vector | ||
| thread_vector threads; | ||
|
|
||
| public: | ||
| /** | ||
| * Effects: try to execute one task. | ||
| * Returns: whether a task has been executed. | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| bool try_executing_one() | ||
| { | ||
| work task; | ||
| try | ||
| { | ||
| if (work_queue.try_pull_front(task) == queue_op_status::success) | ||
| { | ||
| task(); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| catch (std::exception& ) | ||
| { | ||
| return false; | ||
| } | ||
| catch (...) | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
| private: | ||
| /** | ||
| * Effects: schedule one task or yields | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| void schedule_one_or_yield() | ||
| { | ||
| if ( ! try_executing_one()) | ||
| { | ||
| this_thread::yield(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * The main loop of the worker threads | ||
| */ | ||
| void worker_thread() | ||
| { | ||
| while (!closed()) | ||
| { | ||
| schedule_one_or_yield(); | ||
| } | ||
| while (try_executing_one()) | ||
| { | ||
| } | ||
| } | ||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <class AtThreadEntry> | ||
| void worker_thread1(AtThreadEntry& at_thread_entry) | ||
| { | ||
| at_thread_entry(*this); | ||
| while (!closed()) | ||
| { | ||
| schedule_one_or_yield(); | ||
| } | ||
| while (try_executing_one()) | ||
| { | ||
| } | ||
| } | ||
| #endif | ||
| void worker_thread2(void(*at_thread_entry)(basic_thread_pool&)) | ||
| { | ||
| at_thread_entry(*this); | ||
| while (!closed()) | ||
| { | ||
| schedule_one_or_yield(); | ||
| } | ||
| while (try_executing_one()) | ||
| { | ||
| } | ||
| } | ||
| template <class AtThreadEntry> | ||
| void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry) | ||
| { | ||
| at_thread_entry(*this); | ||
| while (!closed()) | ||
| { | ||
| schedule_one_or_yield(); | ||
| } | ||
| while (try_executing_one()) | ||
| { | ||
| } | ||
| } | ||
| static void do_nothing_at_thread_entry(basic_thread_pool&) {} | ||
|
|
||
| public: | ||
| /// basic_thread_pool is not copyable. | ||
| BOOST_THREAD_NO_COPYABLE(basic_thread_pool) | ||
|
|
||
| /** | ||
| * \b Effects: creates a thread pool that runs closures on \c thread_count threads. | ||
| * | ||
| * \b Throws: Whatever exception is thrown while initializing the needed resources. | ||
| */ | ||
| basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()) | ||
| { | ||
| try | ||
| { | ||
| threads.reserve(thread_count); | ||
| for (unsigned i = 0; i < thread_count; ++i) | ||
| { | ||
| #if 1 | ||
| thread th (&basic_thread_pool::worker_thread, this); | ||
| threads.push_back(thread_t(boost::move(th))); | ||
| #else | ||
| threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile | ||
| #endif | ||
| } | ||
| } | ||
| catch (...) | ||
| { | ||
| close(); | ||
| throw; | ||
| } | ||
| } | ||
| /** | ||
| * \b Effects: creates a thread pool that runs closures on \c thread_count threads | ||
| * and executes the at_thread_entry function at the entry of each created thread. . | ||
| * | ||
| * \b Throws: Whatever exception is thrown while initializing the needed resources. | ||
| */ | ||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <class AtThreadEntry> | ||
| basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry) | ||
| { | ||
| try | ||
| { | ||
| threads.reserve(thread_count); | ||
| for (unsigned i = 0; i < thread_count; ++i) | ||
| { | ||
| thread th (&basic_thread_pool::worker_thread1<AtThreadEntry>, this, at_thread_entry); | ||
| threads.push_back(thread_t(boost::move(th))); | ||
| //threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile | ||
| } | ||
| } | ||
| catch (...) | ||
| { | ||
| close(); | ||
| throw; | ||
| } | ||
| } | ||
| #endif | ||
| basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool&)) | ||
| { | ||
| try | ||
| { | ||
| threads.reserve(thread_count); | ||
| for (unsigned i = 0; i < thread_count; ++i) | ||
| { | ||
| thread th (&basic_thread_pool::worker_thread2, this, at_thread_entry); | ||
| threads.push_back(thread_t(boost::move(th))); | ||
| //threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile | ||
| } | ||
| } | ||
| catch (...) | ||
| { | ||
| close(); | ||
| throw; | ||
| } | ||
| } | ||
| template <class AtThreadEntry> | ||
| basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry) | ||
| { | ||
| try | ||
| { | ||
| threads.reserve(thread_count); | ||
| for (unsigned i = 0; i < thread_count; ++i) | ||
| { | ||
| thread th (&basic_thread_pool::worker_thread3<AtThreadEntry>, this, boost::forward<AtThreadEntry>(at_thread_entry)); | ||
| threads.push_back(thread_t(boost::move(th))); | ||
| //threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile | ||
| } | ||
| } | ||
| catch (...) | ||
| { | ||
| close(); | ||
| throw; | ||
| } | ||
| } | ||
| /** | ||
| * \b Effects: Destroys the thread pool. | ||
| * | ||
| * \b Synchronization: The completion of all the closures happen before the completion of the \c basic_thread_pool destructor. | ||
| */ | ||
| ~basic_thread_pool() | ||
| { | ||
| // signal to all the worker threads that there will be no more submissions. | ||
| close(); | ||
| // joins all the threads as the threads were scoped_threads | ||
| } | ||
|
|
||
| /** | ||
| * \b Effects: close the \c basic_thread_pool for submissions. | ||
| * The worker threads will work until there is no more closures to run. | ||
| */ | ||
| void close() | ||
| { | ||
| work_queue.close(); | ||
| } | ||
|
|
||
| /** | ||
| * \b Returns: whether the pool is closed for submissions. | ||
| */ | ||
| bool closed() | ||
| { | ||
| return work_queue.closed(); | ||
| } | ||
|
|
||
| /** | ||
| * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. | ||
| * | ||
| * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. | ||
| * If invoked closure throws an exception the \c basic_thread_pool will call \c std::terminate, as is the case with threads. | ||
| * | ||
| * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. | ||
| * | ||
| * \b Throws: \c sync_queue_is_closed if the thread pool is closed. | ||
| * Whatever exception that can be throw while storing the closure. | ||
| */ | ||
|
|
||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <typename Closure> | ||
| void submit(Closure & closure) | ||
| { | ||
| //work w ((closure)); | ||
| //work_queue.push_back(boost::move(w)); | ||
| work_queue.push_back(work(closure)); // todo check why this doesn't work | ||
| } | ||
| #endif | ||
| void submit(void (*closure)()) | ||
| { | ||
| //work w ((closure)); | ||
| //work_queue.push_back(boost::move(w)); | ||
| work_queue.push_back(work(closure)); // todo check why this doesn't work | ||
| } | ||
|
|
||
| #if 0 | ||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_RV_REF(Closure) closure) | ||
| { | ||
| work w = boost::move(closure); | ||
| work_queue.push_back(boost::move(w)); | ||
| //work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work | ||
| } | ||
| #else | ||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_FWD_REF(Closure) closure) | ||
| { | ||
| work_queue.push_back(work(boost::forward<Closure>(closure))); | ||
| } | ||
| #endif | ||
| /** | ||
| * \b Requires: This must be called from an scheduled task. | ||
| * | ||
| * \b Effects: reschedule functions until pred() | ||
| */ | ||
| template <typename Pred> | ||
| bool reschedule_until(Pred const& pred) | ||
| { | ||
| do { | ||
| if ( ! try_executing_one()) | ||
| { | ||
| return false; | ||
| } | ||
| } while (! pred()); | ||
| return true; | ||
| } | ||
|
|
||
| }; | ||
| } | ||
| using executors::basic_thread_pool; | ||
|
|
||
| } | ||
|
|
||
| #include <boost/config/abi_suffix.hpp> | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| // Copyright (C) 2013,2014 Vicente J. Botet Escriba | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| // | ||
| // 2013/09 Vicente J. Botet Escriba | ||
| // Adapt to boost from CCIA C++11 implementation | ||
|
|
||
| #ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_HPP | ||
| #define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP | ||
|
|
||
| #include <boost/thread/detail/config.hpp> | ||
|
|
||
| #include <boost/thread/detail/delete.hpp> | ||
| #include <boost/thread/detail/move.hpp> | ||
| #include <boost/thread/executors/work.hpp> | ||
|
|
||
| #include <boost/config/abi_prefix.hpp> | ||
|
|
||
| namespace boost | ||
| { | ||
| namespace executors | ||
| { | ||
| class executor | ||
| { | ||
| public: | ||
| /// type-erasure to store the works to do | ||
| typedef executors::work work; | ||
|
|
||
| /// executor is not copyable. | ||
| BOOST_THREAD_NO_COPYABLE(executor) | ||
| executor() {} | ||
|
|
||
| /** | ||
| * \b Effects: Destroys the executor. | ||
| * | ||
| * \b Synchronization: The completion of all the closures happen before the completion of the executor destructor. | ||
| */ | ||
| virtual ~executor() {}; | ||
|
|
||
| /** | ||
| * \b Effects: close the \c executor for submissions. | ||
| * The worker threads will work until there is no more closures to run. | ||
| */ | ||
| virtual void close() = 0; | ||
|
|
||
| /** | ||
| * \b Returns: whether the pool is closed for submissions. | ||
| */ | ||
| virtual bool closed() = 0; | ||
|
|
||
| /** | ||
| * \b Effects: The specified closure will be scheduled for execution at some point in the future. | ||
| * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. | ||
| * | ||
| * \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables. | ||
| * | ||
| * \b Throws: \c sync_queue_is_closed if the thread pool is closed. | ||
| * Whatever exception that can be throw while storing the closure. | ||
| */ | ||
| virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0; | ||
|
|
||
| /** | ||
| * \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible. | ||
| * | ||
| * \b Effects: The specified closure will be scheduled for execution at some point in the future. | ||
| * If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads. | ||
| * | ||
| * \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables. | ||
| * | ||
| * \b Throws: \c sync_queue_is_closed if the thread pool is closed. | ||
| * Whatever exception that can be throw while storing the closure. | ||
| */ | ||
|
|
||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <typename Closure> | ||
| void submit(Closure & closure) | ||
| { | ||
| work w ((closure)); | ||
| submit(boost::move(w)); | ||
| } | ||
| #endif | ||
| void submit(void (*closure)()) | ||
| { | ||
| work w ((closure)); | ||
| submit(boost::move(w)); | ||
| } | ||
|
|
||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_RV_REF(Closure) closure) | ||
| { | ||
| work w = boost::move(closure); | ||
| submit(boost::move(w)); | ||
| } | ||
|
|
||
| /** | ||
| * Effects: try to execute one task. | ||
| * Returns: whether a task has been executed. | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| virtual bool try_executing_one() = 0; | ||
|
|
||
| /** | ||
| * \b Requires: This must be called from an scheduled task. | ||
| * | ||
| * \b Effects: reschedule functions until pred() | ||
| */ | ||
| template <typename Pred> | ||
| bool reschedule_until(Pred const& pred) | ||
| { | ||
| do { | ||
| //schedule_one_or_yield(); | ||
| if ( ! try_executing_one()) | ||
| { | ||
| return false; | ||
| } | ||
| } while (! pred()); | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
|
|
||
| } | ||
| using executors::executor; | ||
| } | ||
|
|
||
| #include <boost/config/abi_suffix.hpp> | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| // Copyright (C) 2013,2014 Vicente J. Botet Escriba | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| // | ||
| // 2013/09 Vicente J. Botet Escriba | ||
| // Adapt to boost from CCIA C++11 implementation | ||
|
|
||
| #ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP | ||
| #define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP | ||
|
|
||
| #include <boost/thread/detail/config.hpp> | ||
|
|
||
| #include <boost/thread/executors/executor.hpp> | ||
|
|
||
| #include <boost/config/abi_prefix.hpp> | ||
|
|
||
| namespace boost | ||
| { | ||
| namespace executors | ||
| { | ||
| /** | ||
| * Polymorphic adaptor of a model of Executor to an executor. | ||
| */ | ||
| template <typename Executor> | ||
| class executor_adaptor : public executor | ||
| { | ||
| Executor ex; | ||
| public: | ||
| /// type-erasure to store the works to do | ||
| typedef executor::work work; | ||
|
|
||
| /// executor is not copyable. | ||
| BOOST_THREAD_NO_COPYABLE(executor_adaptor) | ||
|
|
||
| /** | ||
| * executor_adaptor constructor | ||
| */ | ||
| #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) | ||
| template <typename ...Args> | ||
| executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward<Args>(args)...) {} | ||
| #else | ||
| /** | ||
| * executor_adaptor constructor | ||
| */ | ||
| executor_adaptor() : ex() {} | ||
|
|
||
| template <typename A1> | ||
| executor_adaptor( | ||
| BOOST_THREAD_FWD_REF(A1) a1 | ||
| ) : | ||
| ex( | ||
| boost::forward<A1>(a1) | ||
| ) {} | ||
| template <typename A1, typename A2> | ||
| executor_adaptor( | ||
| BOOST_THREAD_FWD_REF(A1) a1, | ||
| BOOST_THREAD_FWD_REF(A2) a2 | ||
| ) : | ||
| ex( | ||
| boost::forward<A1>(a1), | ||
| boost::forward<A2>(a2) | ||
| ) {} | ||
| template <typename A1, typename A2, typename A3> | ||
| executor_adaptor( | ||
| BOOST_THREAD_FWD_REF(A1) a1, | ||
| BOOST_THREAD_FWD_REF(A2) a2, | ||
| BOOST_THREAD_FWD_REF(A3) a3 | ||
| ) : | ||
| ex( | ||
| boost::forward<A1>(a1), | ||
| boost::forward<A2>(a2), | ||
| boost::forward<A3>(a3) | ||
| ) {} | ||
| #endif | ||
| Executor& underlying_executor() { return ex; } | ||
|
|
||
| /** | ||
| * \b Effects: close the \c executor for submissions. | ||
| * The worker threads will work until there is no more closures to run. | ||
| */ | ||
| void close() { ex.close(); } | ||
|
|
||
| /** | ||
| * \b Returns: whether the pool is closed for submissions. | ||
| */ | ||
| bool closed() { return ex.closed(); } | ||
|
|
||
| /** | ||
| * \b Effects: The specified closure will be scheduled for execution at some point in the future. | ||
| * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. | ||
| * | ||
| * \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables. | ||
| * | ||
| * \b Throws: \c sync_queue_is_closed if the thread pool is closed. | ||
| * Whatever exception that can be throw while storing the closure. | ||
| */ | ||
| void submit(BOOST_THREAD_RV_REF(work) closure) { | ||
| return ex.submit(boost::move(closure)); | ||
| //return ex.submit(boost::forward<work>(closure)); | ||
| } | ||
|
|
||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <typename Closure> | ||
| void submit(Closure & closure) | ||
| { | ||
| work w ((closure)); | ||
| submit(boost::move(w)); | ||
| //submit(work(closure)); | ||
| } | ||
| #endif | ||
| void submit(void (*closure)()) | ||
| { | ||
| work w ((closure)); | ||
| submit(boost::move(w)); | ||
| //submit(work(closure)); | ||
| } | ||
|
|
||
| #if 0 | ||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_RV_REF(Closure) closure) | ||
| { | ||
| work w =boost::move(closure); | ||
| submit(boost::move(w)); | ||
| } | ||
| #else | ||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_FWD_REF(Closure) closure) | ||
| { | ||
| submit(work(boost::forward<Closure>(closure))); | ||
| } | ||
| #endif | ||
|
|
||
| /** | ||
| * Effects: try to execute one task. | ||
| * Returns: whether a task has been executed. | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| bool try_executing_one() { return ex.try_executing_one(); } | ||
|
|
||
| }; | ||
| } | ||
| using executors::executor_adaptor; | ||
| } | ||
|
|
||
| #include <boost/config/abi_suffix.hpp> | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| // Copyright (C) 2014 Vicente J. Botet Escriba | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| // | ||
| // 2013/11 Vicente J. Botet Escriba | ||
| // first implementation of a simple serial scheduler. | ||
|
|
||
| #ifndef BOOST_THREAD_INLINE_EXECUTOR_HPP | ||
| #define BOOST_THREAD_INLINE_EXECUTOR_HPP | ||
|
|
||
| #include <boost/thread/detail/config.hpp> | ||
| #include <boost/thread/detail/delete.hpp> | ||
| #include <boost/thread/detail/move.hpp> | ||
| #include <boost/thread/executors/work.hpp> | ||
|
|
||
| #include <boost/config/abi_prefix.hpp> | ||
|
|
||
| namespace boost | ||
| { | ||
| namespace executors | ||
| { | ||
| class inline_executor | ||
| { | ||
| public: | ||
| /// type-erasure to store the works to do | ||
| typedef executors::work work; | ||
| bool closed_; | ||
| /** | ||
| * Effects: try to execute one task. | ||
| * Returns: whether a task has been executed. | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| bool try_executing_one() | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| public: | ||
| /// inline_executor is not copyable. | ||
| BOOST_THREAD_NO_COPYABLE(inline_executor) | ||
|
|
||
| /** | ||
| * \b Effects: creates a inline executor that runs closures immediately. | ||
| * | ||
| * \b Throws: Nothing. | ||
| */ | ||
| inline_executor() | ||
| : closed_(false) | ||
| { | ||
| } | ||
| /** | ||
| * \b Effects: Destroys the inline executor. | ||
| * | ||
| * \b Synchronization: The completion of all the closures happen before the completion of the \c inline_executor destructor. | ||
| */ | ||
| ~inline_executor() | ||
| { | ||
| // signal to all the worker thread that there will be no more submissions. | ||
| close(); | ||
| } | ||
|
|
||
| /** | ||
| * \b Effects: close the \c inline_executor for submissions. | ||
| * The loop will work until there is no more closures to run. | ||
| */ | ||
| void close() | ||
| { | ||
| closed_ = true; | ||
| } | ||
|
|
||
| /** | ||
| * \b Returns: whether the pool is closed for submissions. | ||
| */ | ||
| bool closed() | ||
| { | ||
| return closed_; | ||
| } | ||
|
|
||
| /** | ||
| * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. | ||
| * | ||
| * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. | ||
| * If invoked closure throws an exception the \c inline_executor will call \c std::terminate, as is the case with threads. | ||
| * | ||
| * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. | ||
| * | ||
| * \b Throws: \c sync_queue_is_closed if the thread pool is closed. | ||
| * Whatever exception that can be throw while storing the closure. | ||
| */ | ||
|
|
||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <typename Closure> | ||
| void submit(Closure & closure) | ||
| { | ||
| if (closed()) return; | ||
| closure(); | ||
| } | ||
| #endif | ||
| void submit(void (*closure)()) | ||
| { | ||
| if (closed()) return; | ||
| closure(); | ||
| } | ||
|
|
||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_FWD_REF(Closure) closure) | ||
| { | ||
| if (closed()) return; | ||
| closure(); | ||
| } | ||
|
|
||
| /** | ||
| * \b Requires: This must be called from an scheduled task. | ||
| * | ||
| * \b Effects: reschedule functions until pred() | ||
| */ | ||
| template <typename Pred> | ||
| bool reschedule_until(Pred const& ) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| }; | ||
| } | ||
| using executors::inline_executor; | ||
| } | ||
|
|
||
| #include <boost/config/abi_suffix.hpp> | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,209 @@ | ||
| // Copyright (C) 2013,2014 Vicente J. Botet Escriba | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| // | ||
| // 2013/11 Vicente J. Botet Escriba | ||
| // first implementation of a simple user scheduler. | ||
| // 2013/11 Vicente J. Botet Escriba | ||
| // rename loop_executor. | ||
|
|
||
| #ifndef BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP | ||
| #define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP | ||
|
|
||
| #include <boost/thread/detail/config.hpp> | ||
| #include <boost/thread/detail/delete.hpp> | ||
| #include <boost/thread/detail/move.hpp> | ||
| #include <boost/thread/sync_queue.hpp> | ||
| #include <boost/thread/executors/work.hpp> | ||
|
|
||
| #include <boost/config/abi_prefix.hpp> | ||
|
|
||
| namespace boost | ||
| { | ||
| namespace executors | ||
| { | ||
|
|
||
| class loop_executor | ||
| { | ||
| public: | ||
| /// type-erasure to store the works to do | ||
| typedef executors::work work; | ||
| private: | ||
| /// the thread safe work queue | ||
| sync_queue<work > work_queue; | ||
|
|
||
| public: | ||
| /** | ||
| * Effects: try to execute one task. | ||
| * Returns: whether a task has been executed. | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| bool try_executing_one() | ||
| { | ||
| work task; | ||
| try | ||
| { | ||
| if (work_queue.try_pull_front(task) == queue_op_status::success) | ||
| { | ||
| task(); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| catch (std::exception& ) | ||
| { | ||
| return false; | ||
| } | ||
| catch (...) | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
| private: | ||
| /** | ||
| * Effects: schedule one task or yields | ||
| * Throws: whatever the current task constructor throws or the task() throws. | ||
| */ | ||
| void schedule_one_or_yield() | ||
| { | ||
| if ( ! try_executing_one()) | ||
| { | ||
| this_thread::yield(); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * The main loop of the worker thread | ||
| */ | ||
| void worker_thread() | ||
| { | ||
| while (!closed()) | ||
| { | ||
| schedule_one_or_yield(); | ||
| } | ||
| while (try_executing_one()) | ||
| { | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| /// loop_executor is not copyable. | ||
| BOOST_THREAD_NO_COPYABLE(loop_executor) | ||
|
|
||
| /** | ||
| * \b Effects: creates a thread pool that runs closures using one of its closure-executing methods. | ||
| * | ||
| * \b Throws: Whatever exception is thrown while initializing the needed resources. | ||
| */ | ||
| loop_executor() | ||
| { | ||
| } | ||
| /** | ||
| * \b Effects: Destroys the thread pool. | ||
| * | ||
| * \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor. | ||
| */ | ||
| ~loop_executor() | ||
| { | ||
| // signal to all the worker thread that there will be no more submissions. | ||
| close(); | ||
| } | ||
|
|
||
| /** | ||
| * loop | ||
| */ | ||
| void loop() { worker_thread(); } | ||
| /** | ||
| * \b Effects: close the \c loop_executor for submissions. | ||
| * The loop will work until there is no more closures to run. | ||
| */ | ||
| void close() | ||
| { | ||
| work_queue.close(); | ||
| } | ||
|
|
||
| /** | ||
| * \b Returns: whether the pool is closed for submissions. | ||
| */ | ||
| bool closed() | ||
| { | ||
| return work_queue.closed(); | ||
| } | ||
|
|
||
| /** | ||
| * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. | ||
| * | ||
| * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. | ||
| * If invoked closure throws an exception the \c loop_executor will call \c std::terminate, as is the case with threads. | ||
| * | ||
| * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. | ||
| * | ||
| * \b Throws: \c sync_queue_is_closed if the thread pool is closed. | ||
| * Whatever exception that can be throw while storing the closure. | ||
| */ | ||
|
|
||
| #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | ||
| template <typename Closure> | ||
| void submit(Closure & closure) | ||
| { | ||
| work w ((closure)); | ||
| work_queue.push_back(boost::move(w)); | ||
| //work_queue.push(work(closure)); // todo check why this doesn't work | ||
| } | ||
| #endif | ||
| void submit(void (*closure)()) | ||
| { | ||
| work w ((closure)); | ||
| work_queue.push_back(boost::move(w)); | ||
| //work_queue.push_back(work(closure)); // todo check why this doesn't work | ||
| } | ||
|
|
||
| template <typename Closure> | ||
| void submit(BOOST_THREAD_RV_REF(Closure) closure) | ||
| { | ||
| work w =boost::move(closure); | ||
| work_queue.push_back(boost::move(w)); | ||
| //work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work | ||
| } | ||
|
|
||
| /** | ||
| * \b Requires: This must be called from an scheduled task. | ||
| * | ||
| * \b Effects: reschedule functions until pred() | ||
| */ | ||
| template <typename Pred> | ||
| bool reschedule_until(Pred const& pred) | ||
| { | ||
| do { | ||
| if ( ! try_executing_one()) | ||
| { | ||
| return false; | ||
| } | ||
| } while (! pred()); | ||
| return true; | ||
| } | ||
| /** | ||
| * run queued closures | ||
| */ | ||
| void run_queued_closures() | ||
| { | ||
| sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue(); | ||
| while (q.empty()) | ||
| { | ||
| work task = q.front(); | ||
| q.pop_front(); | ||
| task(); | ||
| } | ||
| } | ||
|
|
||
| }; | ||
| } | ||
| using executors::loop_executor; | ||
|
|
||
| } | ||
|
|
||
| #include <boost/config/abi_suffix.hpp> | ||
|
|
||
| #endif |