Geant4 Cross Reference |
1 // 1 // 2 // MIT License 2 // MIT License 3 // Copyright (c) 2020 Jonathan R. Madsen 3 // Copyright (c) 2020 Jonathan R. Madsen 4 // Permission is hereby granted, free of charg 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentati 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, includ 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distr 7 // to use, copy, modify, merge, publish, distribute, sublicense, and 8 // copies of the Software, and to permit perso 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the followin 9 // furnished to do so, subject to the following conditions: 10 // The above copyright notice and this permiss 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the S 11 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 12 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPR 12 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 13 // LIMITED TO THE WARRANTIES OF MERCHANTABILIT 13 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SH 14 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 16 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARIS 16 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 17 // WITH THE SOFTWARE OR THE USE OR OTHER DEALI 17 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 // 18 // 19 // 19 // 20 // ------------------------------------------- 20 // --------------------------------------------------------------- 21 // Tasking class header file 21 // Tasking class header file 22 // 22 // 23 // Class Description: 23 // Class Description: 24 // 24 // 25 // This file defines the task types for TaskMa 25 // This file defines the task types for TaskManager and ThreadPool 26 // 26 // 27 // ------------------------------------------- 27 // --------------------------------------------------------------- 28 // Author: Jonathan Madsen (Feb 13th 2018) 28 // Author: Jonathan Madsen (Feb 13th 2018) 29 // ------------------------------------------- 29 // --------------------------------------------------------------- 30 30 31 #pragma once 31 #pragma once 32 32 33 #include "PTL/VTask.hh" << 33 #include "Globals.hh" 34 #include "PTL/detail/CxxBackports.hh" << 34 #include "TaskAllocator.hh" >> 35 #include "VTask.hh" 35 36 36 #include <cstdint> 37 #include <cstdint> 37 #include <future> << 38 #include <functional> 38 #include <tuple> << 39 #include <stdexcept> 39 #include <utility> << 40 40 41 namespace PTL 41 namespace PTL 42 { 42 { 43 //============================================ << 43 class VTaskGroup; 44 << 44 class ThreadPool; 45 /// \brief The task class is supplied to threa << 46 template <typename RetT> << 47 class TaskFuture : public VTask << 48 { << 49 public: << 50 using promise_type = std::promise<RetT>; << 51 using future_type = std::future<RetT>; << 52 using result_type = RetT; << 53 << 54 public: << 55 // pass a free function pointer << 56 template <typename... Args> << 57 TaskFuture(Args&&... args) << 58 : VTask{ std::forward<Args>(args)... } << 59 {} << 60 << 61 ~TaskFuture() override = default; << 62 << 63 TaskFuture(const TaskFuture&) = delete; << 64 TaskFuture& operator=(const TaskFuture&) = << 65 << 66 TaskFuture(TaskFuture&&) noexcept = defaul << 67 TaskFuture& operator=(TaskFuture&&) noexce << 68 << 69 public: << 70 // execution operator << 71 virtual future_type get_future() = 0; << 72 virtual void wait() = 0; << 73 virtual RetT get() = 0; << 74 }; << 75 45 76 //============================================ 46 //======================================================================================// 77 47 78 /// \brief The task class is supplied to threa 48 /// \brief The task class is supplied to thread_pool. 79 template <typename RetT, typename... Args> 49 template <typename RetT, typename... Args> 80 class PackagedTask : public TaskFuture<RetT> << 50 class PackagedTask : public VTask 81 { 51 { 82 public: 52 public: 83 using this_type = PackagedTask<Re << 53 typedef PackagedTask<RetT, Args...> this_type; 84 using promise_type = std::promise<Re << 54 typedef std::promise<RetT> promise_type; 85 using future_type = std::future<Ret << 55 typedef std::future<RetT> future_type; 86 using packaged_task_type = std::packaged_t << 56 typedef std::packaged_task<RetT(Args...)> packaged_task_type; 87 using result_type = RetT; << 57 typedef RetT result_type; 88 using tuple_type = std::tuple<Args << 58 typedef std::tuple<Args...> tuple_type; 89 59 90 public: 60 public: 91 // pass a free function pointer 61 // pass a free function pointer 92 template <typename FuncT> 62 template <typename FuncT> 93 PackagedTask(FuncT func, Args... args) << 63 PackagedTask(FuncT&& func, Args... args) 94 : TaskFuture<RetT>{ true, 0 } << 64 : VTask() 95 , m_ptask{ std::move(func) } << 65 , m_ptask(std::forward<FuncT>(func)) 96 , m_args{ args... } << 66 , m_args(args...) 97 {} 67 {} 98 68 99 template <typename FuncT> 69 template <typename FuncT> 100 PackagedTask(bool _is_native, intmax_t _de << 70 PackagedTask(VTaskGroup* tg, FuncT&& func, Args... args) 101 : TaskFuture<RetT>{ _is_native, _depth } << 71 : VTask(tg) 102 , m_ptask{ std::move(func) } << 72 , m_ptask(std::forward<FuncT>(func)) 103 , m_args{ args... } << 73 , m_args(args...) 104 {} 74 {} 105 75 106 ~PackagedTask() override = default; << 76 template <typename FuncT> 107 << 77 PackagedTask(ThreadPool* _pool, FuncT&& func, Args... args) 108 PackagedTask(const PackagedTask&) = delete << 78 : VTask(_pool) 109 PackagedTask& operator=(const PackagedTask << 79 , m_ptask(std::forward<FuncT>(func)) >> 80 , m_args(args...) >> 81 {} 110 82 111 PackagedTask(PackagedTask&&) noexcept = de << 83 virtual ~PackagedTask() {} 112 PackagedTask& operator=(PackagedTask&&) no << 113 84 114 public: 85 public: 115 // execution operator 86 // execution operator 116 void operator()() final { PTL::appl << 87 virtual void operator()() override 117 future_type get_future() final { return m_ << 88 { 118 void wait() final { return m_ptask. << 89 mpl::apply(std::move(m_ptask), std::move(m_args)); 119 RetT get() final { return m_ptask.g << 90 } >> 91 future_type get_future() { return m_ptask.get_future(); } >> 92 virtual bool is_native_task() const override { return true; } 120 93 121 private: 94 private: 122 packaged_task_type m_ptask; 95 packaged_task_type m_ptask; 123 tuple_type m_args; 96 tuple_type m_args; 124 }; 97 }; 125 98 126 //============================================ 99 //======================================================================================// 127 100 128 /// \brief The task class is supplied to threa 101 /// \brief The task class is supplied to thread_pool. 129 template <typename RetT, typename... Args> 102 template <typename RetT, typename... Args> 130 class Task : public TaskFuture<RetT> << 103 class Task : public VTask 131 { 104 { 132 public: 105 public: 133 using this_type = Task<RetT, Args << 106 typedef Task<RetT, Args...> this_type; 134 using promise_type = std::promise<Re << 107 typedef std::promise<RetT> promise_type; 135 using future_type = std::future<Ret << 108 typedef std::future<RetT> future_type; 136 using packaged_task_type = std::packaged_t << 109 typedef std::packaged_task<RetT(Args...)> packaged_task_type; 137 using result_type = RetT; << 110 typedef RetT result_type; 138 using tuple_type = std::tuple<Args << 111 typedef std::tuple<Args...> tuple_type; 139 112 140 public: 113 public: 141 template <typename FuncT> 114 template <typename FuncT> 142 Task(FuncT func, Args... args) << 115 Task(FuncT&& func, Args... args) 143 : TaskFuture<RetT>{} << 116 : VTask() 144 , m_ptask{ std::move(func) } << 117 , m_ptask(std::forward<FuncT>(func)) 145 , m_args{ args... } << 118 , m_args(args...) 146 {} 119 {} 147 120 148 template <typename FuncT> 121 template <typename FuncT> 149 Task(bool _is_native, intmax_t _depth, Fun << 122 Task(VTaskGroup* tg, FuncT&& func, Args... args) 150 : TaskFuture<RetT>{ _is_native, _depth } << 123 : VTask(tg) 151 , m_ptask{ std::move(func) } << 124 , m_ptask(std::forward<FuncT>(func)) 152 , m_args{ args... } << 125 , m_args(args...) 153 {} 126 {} 154 127 155 ~Task() override = default; << 128 template <typename FuncT> 156 << 129 Task(ThreadPool* tp, FuncT&& func, Args... args) 157 Task(const Task&) = delete; << 130 : VTask(tp) 158 Task& operator=(const Task&) = delete; << 131 , m_ptask(std::forward<FuncT>(func)) >> 132 , m_args(args...) >> 133 {} 159 134 160 Task(Task&&) noexcept = default; << 135 virtual ~Task() {} 161 Task& operator=(Task&&) noexcept = default << 162 136 163 public: 137 public: 164 // execution operator 138 // execution operator 165 void operator()() final << 139 virtual void operator()() final 166 { 140 { 167 if(m_ptask.valid()) << 141 mpl::apply(std::move(m_ptask), std::move(m_args)); 168 PTL::apply(std::move(m_ptask), std << 142 // decrements the task-group counter on active tasks >> 143 // when the counter is < 2, if the thread owning the task group is >> 144 // sleeping at the TaskGroup::wait(), it signals the thread to wake >> 145 // up and check if all tasks are finished, proceeding if this >> 146 // check returns as true >> 147 this_type::operator--(); 169 } 148 } 170 future_type get_future() final { return m_ << 149 171 void wait() final { return m_ptask. << 150 virtual bool is_native_task() const override { return true; } 172 RetT get() final { return m_ptask.g << 151 future_type get_future() { return m_ptask.get_future(); } 173 152 174 private: 153 private: 175 packaged_task_type m_ptask{}; << 154 packaged_task_type m_ptask; 176 tuple_type m_args{}; << 155 tuple_type m_args; 177 }; 156 }; 178 157 179 //============================================ 158 //======================================================================================// 180 159 181 /// \brief The task class is supplied to threa 160 /// \brief The task class is supplied to thread_pool. 182 template <typename RetT> 161 template <typename RetT> 183 class Task<RetT, void> : public TaskFuture<Ret << 162 class Task<RetT, void> : public VTask 184 { 163 { 185 public: 164 public: 186 using this_type = Task<RetT>; << 165 typedef Task<RetT> this_type; 187 using promise_type = std::promise<Re << 166 typedef std::promise<RetT> promise_type; 188 using future_type = std::future<Ret << 167 typedef std::future<RetT> future_type; 189 using packaged_task_type = std::packaged_t << 168 typedef std::packaged_task<RetT()> packaged_task_type; 190 using result_type = RetT; << 169 typedef RetT result_type; 191 170 192 public: 171 public: 193 template <typename FuncT> 172 template <typename FuncT> 194 Task(FuncT func) << 173 Task(FuncT&& func) 195 : TaskFuture<RetT>() << 174 : VTask() 196 , m_ptask{ std::move(func) } << 175 , m_ptask(std::forward<FuncT>(func)) 197 {} 176 {} 198 177 199 template <typename FuncT> 178 template <typename FuncT> 200 Task(bool _is_native, intmax_t _depth, Fun << 179 Task(VTaskGroup* tg, FuncT&& func) 201 : TaskFuture<RetT>{ _is_native, _depth } << 180 : VTask(tg) 202 , m_ptask{ std::move(func) } << 181 , m_ptask(std::forward<FuncT>(func)) 203 {} 182 {} 204 183 205 virtual ~Task() = default; << 184 template <typename FuncT> 206 << 185 Task(ThreadPool* tp, FuncT&& func) 207 Task(const Task&) = delete; << 186 : VTask(tp) 208 Task& operator=(const Task&) = delete; << 187 , m_ptask(std::forward<FuncT>(func)) >> 188 {} 209 189 210 Task(Task&&) noexcept = default; << 190 virtual ~Task() {} 211 Task& operator=(Task&&) noexcept = default << 212 191 213 public: 192 public: 214 // execution operator 193 // execution operator 215 virtual void operator()() final { m << 194 virtual void operator()() final 216 virtual future_type get_future() final { r << 195 { 217 virtual void wait() final { return << 196 m_ptask(); 218 virtual RetT get() final { return m << 197 // decrements the task-group counter on active tasks >> 198 // when the counter is < 2, if the thread owning the task group is >> 199 // sleeping at the TaskGroup::wait(), it signals the thread to wake >> 200 // up and check if all tasks are finished, proceeding if this >> 201 // check returns as true >> 202 this_type::operator--(); >> 203 } >> 204 >> 205 virtual bool is_native_task() const override { return true; } >> 206 future_type get_future() { return m_ptask.get_future(); } 219 207 220 private: 208 private: 221 packaged_task_type m_ptask{}; << 209 packaged_task_type m_ptask; 222 }; 210 }; 223 211 224 //============================================ 212 //======================================================================================// 225 213 226 /// \brief The task class is supplied to threa 214 /// \brief The task class is supplied to thread_pool. 227 template <> 215 template <> 228 class Task<void, void> : public TaskFuture<voi << 216 class Task<void, void> : public VTask 229 { 217 { 230 public: 218 public: 231 using RetT = void; << 219 typedef void RetT; 232 using this_type = Task<void, void << 220 typedef Task<void, void> this_type; 233 using promise_type = std::promise<Re << 221 typedef std::promise<RetT> promise_type; 234 using future_type = std::future<Ret << 222 typedef std::future<RetT> future_type; 235 using packaged_task_type = std::packaged_t << 223 typedef std::packaged_task<RetT()> packaged_task_type; 236 using result_type = RetT; << 224 typedef RetT result_type; 237 225 238 public: 226 public: 239 template <typename FuncT> 227 template <typename FuncT> 240 explicit Task(FuncT func) << 228 explicit Task(FuncT&& func) 241 : TaskFuture<RetT>{} << 229 : VTask() 242 , m_ptask{ std::move(func) } << 230 , m_ptask(std::forward<FuncT>(func)) 243 {} 231 {} 244 232 245 template <typename FuncT> 233 template <typename FuncT> 246 Task(bool _is_native, intmax_t _depth, Fun << 234 Task(VTaskGroup* tg, FuncT&& func) 247 : TaskFuture<RetT>{ _is_native, _depth } << 235 : VTask(tg) 248 , m_ptask{ std::move(func) } << 236 , m_ptask(std::forward<FuncT>(func)) 249 {} 237 {} 250 238 251 ~Task() override = default; << 239 template <typename FuncT> 252 << 240 Task(ThreadPool* tp, FuncT&& func) 253 Task(const Task&) = delete; << 241 : VTask(tp) 254 Task& operator=(const Task&) = delete; << 242 , m_ptask(std::forward<FuncT>(func)) >> 243 {} 255 244 256 Task(Task&&) = default; << 245 virtual ~Task() {} 257 Task& operator=(Task&&) = default; << 258 246 259 public: 247 public: 260 // execution operator 248 // execution operator 261 void operator()() final { m_ptask() << 249 virtual void operator()() final 262 future_type get_future() final { return m_ << 250 { 263 void wait() final { return m_ptask. << 251 m_ptask(); 264 RetT get() final { return m_ptask.g << 252 // decrements the task-group counter on active tasks >> 253 // when the counter is < 2, if the thread owning the task group is >> 254 // sleeping at the TaskGroup::wait(), it signals the thread to wake >> 255 // up and check if all tasks are finished, proceeding if this >> 256 // check returns as true >> 257 this_type::operator--(); >> 258 } >> 259 >> 260 virtual bool is_native_task() const override { return true; } >> 261 future_type get_future() { return m_ptask.get_future(); } 265 262 266 private: 263 private: 267 packaged_task_type m_ptask{}; << 264 packaged_task_type m_ptask; 268 }; 265 }; 269 266 270 //============================================ 267 //======================================================================================// 271 268 272 } // namespace PTL 269 } // namespace PTL 273 270