annotate DEPENDENCIES/generic/include/boost/thread/user_scheduler.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents f46d142149f5
children
rev   line source
Chris@102 1 // Copyright (C) 2013 Vicente J. Botet Escriba
Chris@102 2 //
Chris@102 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
Chris@102 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@102 5 //
Chris@102 6 // 2013/11 Vicente J. Botet Escriba
Chris@102 7 // first implementation of a simple serial scheduler.
Chris@102 8
Chris@102 9 #ifndef BOOST_THREAD_USER_SCHEDULER_HPP
Chris@102 10 #define BOOST_THREAD_USER_SCHEDULER_HPP
Chris@102 11
Chris@102 12 #include <boost/thread/detail/config.hpp>
Chris@102 13 #include <boost/thread/detail/delete.hpp>
Chris@102 14 #include <boost/thread/detail/move.hpp>
Chris@102 15 #include <boost/thread/concurrent_queues/sync_queue.hpp>
Chris@102 16 #include <boost/thread/executors/work.hpp>
Chris@102 17
Chris@102 18 #include <boost/config/abi_prefix.hpp>
Chris@102 19
Chris@102 20 namespace boost
Chris@102 21 {
Chris@102 22
Chris@102 23 class user_scheduler
Chris@102 24 {
Chris@102 25 /// type-erasure to store the works to do
Chris@102 26 typedef thread_detail::work work;
Chris@102 27
Chris@102 28 /// the thread safe work queue
Chris@102 29 sync_queue<work > work_queue;
Chris@102 30
Chris@102 31 public:
Chris@102 32 /**
Chris@102 33 * Effects: try to execute one task.
Chris@102 34 * Returns: whether a task has been executed.
Chris@102 35 * Throws: whatever the current task constructor throws or the task() throws.
Chris@102 36 */
Chris@102 37 bool try_executing_one()
Chris@102 38 {
Chris@102 39 work task;
Chris@102 40 try
Chris@102 41 {
Chris@102 42 if (work_queue.try_pull(task) == queue_op_status::success)
Chris@102 43 {
Chris@102 44 task();
Chris@102 45 return true;
Chris@102 46 }
Chris@102 47 return false;
Chris@102 48 }
Chris@102 49 catch (std::exception& )
Chris@102 50 {
Chris@102 51 return false;
Chris@102 52 }
Chris@102 53 catch (...)
Chris@102 54 {
Chris@102 55 return false;
Chris@102 56 }
Chris@102 57 }
Chris@102 58 private:
Chris@102 59 /**
Chris@102 60 * Effects: schedule one task or yields
Chris@102 61 * Throws: whatever the current task constructor throws or the task() throws.
Chris@102 62 */
Chris@102 63 void schedule_one_or_yield()
Chris@102 64 {
Chris@102 65 if ( ! try_executing_one())
Chris@102 66 {
Chris@102 67 this_thread::yield();
Chris@102 68 }
Chris@102 69 }
Chris@102 70
Chris@102 71
Chris@102 72 /**
Chris@102 73 * The main loop of the worker thread
Chris@102 74 */
Chris@102 75 void worker_thread()
Chris@102 76 {
Chris@102 77 while (!closed())
Chris@102 78 {
Chris@102 79 schedule_one_or_yield();
Chris@102 80 }
Chris@102 81 while (try_executing_one())
Chris@102 82 {
Chris@102 83 }
Chris@102 84 }
Chris@102 85
Chris@102 86 public:
Chris@102 87 /// user_scheduler is not copyable.
Chris@102 88 BOOST_THREAD_NO_COPYABLE(user_scheduler)
Chris@102 89
Chris@102 90 /**
Chris@102 91 * \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
Chris@102 92 *
Chris@102 93 * \b Throws: Whatever exception is thrown while initializing the needed resources.
Chris@102 94 */
Chris@102 95 user_scheduler()
Chris@102 96 {
Chris@102 97 }
Chris@102 98 /**
Chris@102 99 * \b Effects: Destroys the thread pool.
Chris@102 100 *
Chris@102 101 * \b Synchronization: The completion of all the closures happen before the completion of the \c user_scheduler destructor.
Chris@102 102 */
Chris@102 103 ~user_scheduler()
Chris@102 104 {
Chris@102 105 // signal to all the worker thread that there will be no more submissions.
Chris@102 106 close();
Chris@102 107 }
Chris@102 108
Chris@102 109 /**
Chris@102 110 * loop
Chris@102 111 */
Chris@102 112 void loop() { worker_thread(); }
Chris@102 113 /**
Chris@102 114 * \b Effects: close the \c user_scheduler for submissions.
Chris@102 115 * The loop will work until there is no more closures to run.
Chris@102 116 */
Chris@102 117 void close()
Chris@102 118 {
Chris@102 119 work_queue.close();
Chris@102 120 }
Chris@102 121
Chris@102 122 /**
Chris@102 123 * \b Returns: whether the pool is closed for submissions.
Chris@102 124 */
Chris@102 125 bool closed()
Chris@102 126 {
Chris@102 127 return work_queue.closed();
Chris@102 128 }
Chris@102 129
Chris@102 130 /**
Chris@102 131 * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
Chris@102 132 *
Chris@102 133 * \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
Chris@102 134 * If invoked closure throws an exception the \c user_scheduler will call \c std::terminate, as is the case with threads.
Chris@102 135 *
Chris@102 136 * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
Chris@102 137 *
Chris@102 138 * \b Throws: \c sync_queue_is_closed if the thread pool is closed.
Chris@102 139 * Whatever exception that can be throw while storing the closure.
Chris@102 140 */
Chris@102 141
Chris@102 142 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
Chris@102 143 template <typename Closure>
Chris@102 144 void submit(Closure & closure)
Chris@102 145 {
Chris@102 146 work w ((closure));
Chris@102 147 work_queue.push(boost::move(w));
Chris@102 148 //work_queue.push(work(closure)); // todo check why this doesn't work
Chris@102 149 }
Chris@102 150 #endif
Chris@102 151 void submit(void (*closure)())
Chris@102 152 {
Chris@102 153 work w ((closure));
Chris@102 154 work_queue.push(boost::move(w));
Chris@102 155 //work_queue.push(work(closure)); // todo check why this doesn't work
Chris@102 156 }
Chris@102 157
Chris@102 158 template <typename Closure>
Chris@102 159 void submit(BOOST_THREAD_RV_REF(Closure) closure)
Chris@102 160 {
Chris@102 161 work w =boost::move(closure);
Chris@102 162 work_queue.push(boost::move(w));
Chris@102 163 //work_queue.push(work(boost::move(closure))); // todo check why this doesn't work
Chris@102 164 }
Chris@102 165
Chris@102 166 /**
Chris@102 167 * \b Requires: This must be called from an scheduled task.
Chris@102 168 *
Chris@102 169 * \b Effects: reschedule functions until pred()
Chris@102 170 */
Chris@102 171 template <typename Pred>
Chris@102 172 bool reschedule_until(Pred const& pred)
Chris@102 173 {
Chris@102 174 do {
Chris@102 175 if ( ! try_executing_one())
Chris@102 176 {
Chris@102 177 return false;
Chris@102 178 }
Chris@102 179 } while (! pred());
Chris@102 180 return true;
Chris@102 181 }
Chris@102 182 /**
Chris@102 183 * run queued closures
Chris@102 184 */
Chris@102 185 void run_queued_closures()
Chris@102 186 {
Chris@102 187 sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
Chris@102 188 while (q.empty())
Chris@102 189 {
Chris@102 190 work task = q.front();
Chris@102 191 q.pop_front();
Chris@102 192 task();
Chris@102 193 }
Chris@102 194 }
Chris@102 195
Chris@102 196 };
Chris@102 197
Chris@102 198 }
Chris@102 199
Chris@102 200 #include <boost/config/abi_suffix.hpp>
Chris@102 201
Chris@102 202 #endif