Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/ptl/include/PTL/TaskManager.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // MIT License
  3 // Copyright (c) 2020 Jonathan R. Madsen
  4 // Permission is hereby granted, free of charge, to any person obtaining a copy
  5 // of this software and associated documentation files (the "Software"), to deal
  6 // in the Software without restriction, including without limitation the rights
  7 // to use, copy, modify, merge, publish, distribute, sublicense, and
  8 // copies of the Software, and to permit persons to whom the Software is
  9 // furnished to do so, subject to the following conditions:
 10 // The above copyright notice and this permission notice shall be included in
 11 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
 12 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 13 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 14 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 16 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 17 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 18 //
 19 // ---------------------------------------------------------------
 20 // Tasking class header file
 21 //
 22 // Class Description:
 23 //
 24 // This file creates a class for handling the wrapping of functions
 25 // into task objects and submitting to thread pool
 26 //
 27 // ---------------------------------------------------------------
 28 // Author: Jonathan Madsen (Feb 13th 2018)
 29 // ---------------------------------------------------------------
 30 
 31 #pragma once
 32 
 33 #include "PTL/Macros.hh"
 34 #include "PTL/Task.hh"
 35 #include "PTL/TaskGroup.hh"
 36 #include "PTL/ThreadPool.hh"
 37 
 38 #include <iostream>
 39 #include <memory>
 40 #include <stdexcept>
 41 #include <thread>
 42 #include <utility>
 43 
 44 namespace PTL
 45 {
 46 //======================================================================================//
 47 
 48 class TaskManager
 49 {
 50 public:
 51     using this_type = TaskManager;
 52     using size_type = ThreadPool::size_type;
 53 
 54 public:
 55     // Constructor and Destructors
 56     explicit TaskManager(ThreadPool*, bool _manage_pool = true);
 57     virtual ~TaskManager() noexcept(false);
 58 
 59     TaskManager(const TaskManager&) = delete;
 60     TaskManager(TaskManager&&)      = default;
 61     TaskManager& operator=(const TaskManager&) = delete;
 62     TaskManager& operator=(TaskManager&&) = default;
 63 
 64 public:
 65     /// get the singleton pointer
 66     static TaskManager* GetInstance();
 67     static TaskManager* GetInstanceIfExists();
 68     static unsigned     ncores() { return std::thread::hardware_concurrency(); }
 69 
 70 public:
 71     //------------------------------------------------------------------------//
 72     // return the thread pool
 73     inline ThreadPool* thread_pool() const { return m_pool; }
 74 
 75     //------------------------------------------------------------------------//
 76     // return the number of threads in the thread pool
 77     inline size_type size() const { return (m_pool) ? m_pool->size() : 0; }
 78 
 79     //------------------------------------------------------------------------//
 80     // kill all the threads
 81     inline void finalize()
 82     {
 83         if(m_is_finalized)
 84             return;
 85         m_is_finalized = true;
 86         if(m_pool)
 87             m_pool->destroy_threadpool();
 88     }
 89     //------------------------------------------------------------------------//
 90 
 91 public:
 92     //------------------------------------------------------------------------//
 93     // direct insertion of a task
 94     //------------------------------------------------------------------------//
 95     template <typename... Args>
 96     void exec(Task<Args...>* _task)
 97     {
 98         if(!m_pool)
 99             throw std::runtime_error("Nullptr to thread-pool");
100         m_pool->add_task(_task);
101     }
102 
103     //------------------------------------------------------------------------//
104     // direct insertion of a packaged_task
105     //------------------------------------------------------------------------//
106     template <typename RetT, typename FuncT, typename... Args>
107     std::shared_ptr<PackagedTask<RetT, Args...>> async(FuncT&& func, Args&&... args)
108     {
109         using task_type = PackagedTask<RetT, Args...>;
110 
111         if(!m_pool)
112             throw std::runtime_error("Nullptr to thread-pool");
113 
114         auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func),
115                                                   std::forward<Args>(args)...);
116         m_pool->add_task(_ptask);
117         return _ptask;
118     }
119     //------------------------------------------------------------------------//
120     template <typename RetT, typename FuncT>
121     std::shared_ptr<PackagedTask<RetT>> async(FuncT&& func)
122     {
123         using task_type = PackagedTask<RetT>;
124 
125         if(!m_pool)
126             throw std::runtime_error("Nullptr to thread-pool");
127 
128         auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func));
129         m_pool->add_task(_ptask);
130         return _ptask;
131     }
132     //------------------------------------------------------------------------//
133     template <typename FuncT, typename... Args>
134     auto async(FuncT&& func, Args... args)
135         -> std::shared_ptr<PackagedTask<decay_t<decltype(func(args...))>, Args...>>
136     {
137         using RetT      = decay_t<decltype(func(args...))>;
138         using task_type = PackagedTask<RetT, Args...>;
139 
140         if(!m_pool)
141             throw std::runtime_error("Nullptr to thread-pool");
142 
143         auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func),
144                                                   std::forward<Args>(args)...);
145         m_pool->add_task(_ptask);
146         return _ptask;
147     }
148     //------------------------------------------------------------------------//
149 
150 public:
151     //------------------------------------------------------------------------//
152     // public wrap functions
153     //------------------------------------------------------------------------//
154     template <typename RetT, typename ArgT, typename FuncT, typename... Args>
155     std::shared_ptr<Task<RetT, ArgT, Args...>> wrap(TaskGroup<RetT, ArgT>& tg,
156                                                     FuncT&& func, Args&&... args)
157     {
158         return tg.wrap(std::forward<FuncT>(func), std::forward<Args>(args)...);
159     }
160     //------------------------------------------------------------------------//
161     template <typename RetT, typename ArgT, typename FuncT>
162     std::shared_ptr<Task<RetT, ArgT>> wrap(TaskGroup<RetT, ArgT>& tg, FuncT&& func)
163     {
164         return tg.wrap(std::forward<FuncT>(func));
165     }
166 
167 public:
168     //------------------------------------------------------------------------//
169     // public exec functions
170     //------------------------------------------------------------------------//
171     template <typename RetT, typename ArgT, typename FuncT, typename... Args>
172     void exec(TaskGroup<RetT, ArgT>& tg, FuncT&& func, Args&&... args)
173     {
174         tg.exec(std::forward<FuncT>(func), std::forward<Args>(args)...);
175     }
176     //------------------------------------------------------------------------//
177     template <typename RetT, typename ArgT, typename FuncT>
178     void exec(TaskGroup<RetT, ArgT>& tg, FuncT&& func)
179     {
180         tg.exec(std::forward<FuncT>(func));
181     }
182     //------------------------------------------------------------------------//
183     template <typename RetT, typename ArgT, typename FuncT, typename... Args>
184     void rexec(TaskGroup<RetT, ArgT>& tg, FuncT&& func, Args&&... args)
185     {
186         tg.exec(std::forward<FuncT>(func), std::forward<Args>(args)...);
187     }
188     //------------------------------------------------------------------------//
189     template <typename RetT, typename ArgT, typename FuncT>
190     void rexec(TaskGroup<RetT, ArgT>& tg, FuncT&& func)
191     {
192         tg.exec(std::forward<FuncT>(func));
193     }
194     //------------------------------------------------------------------------//
195     // public exec functions (void specializations)
196     //------------------------------------------------------------------------//
197     template <typename FuncT, typename... Args>
198     void rexec(TaskGroup<void, void>& tg, FuncT&& func, Args&&... args)
199     {
200         tg.exec(std::forward<FuncT>(func), std::forward<Args>(args)...);
201     }
202     //------------------------------------------------------------------------//
203     template <typename FuncT>
204     void rexec(TaskGroup<void, void>& tg, FuncT&& func)
205     {
206         tg.exec(std::forward<FuncT>(func));
207     }
208     //------------------------------------------------------------------------//
209 
210 protected:
211     // Protected variables
212     ThreadPool* m_pool         = nullptr;
213     bool        m_is_finalized = false;
214 
215 private:
216     static TaskManager*& fgInstance();
217 };
218 
219 }  // namespace PTL
220 //======================================================================================//
221 
222 #include "TaskRunManager.hh"
223 
224 //--------------------------------------------------------------------------------------//
225 
226 inline PTL::TaskManager*&
227 PTL::TaskManager::fgInstance()
228 {
229     static thread_local TaskManager* _instance = nullptr;
230     return _instance;
231 }
232 
233 //--------------------------------------------------------------------------------------//
234 
235 inline PTL::TaskManager*
236 PTL::TaskManager::GetInstance()
237 {
238     if(!fgInstance())
239     {
240         auto nthreads = std::thread::hardware_concurrency();
241         std::cout << "Allocating mad::TaskManager with " << nthreads << " thread(s)..."
242                   << std::endl;
243         new TaskManager(TaskRunManager::GetMasterRunManager()->GetThreadPool());
244     }
245     return fgInstance();
246 }
247 
248 //--------------------------------------------------------------------------------------//
249 
250 inline PTL::TaskManager*
251 PTL::TaskManager::GetInstanceIfExists()
252 {
253     return fgInstance();
254 }
255 
256 //--------------------------------------------------------------------------------------//
257 
258 inline PTL::TaskManager::TaskManager(ThreadPool* _pool, bool _manage_pool)
259 : m_pool(_pool)
260 , m_is_finalized(!_manage_pool)
261 {
262     if(!fgInstance())
263         fgInstance() = this;
264 }
265 
266 //--------------------------------------------------------------------------------------//
267 
268 inline PTL::TaskManager::~TaskManager() noexcept(false)
269 {
270     finalize();
271     if(fgInstance() == this)
272         fgInstance() = nullptr;
273 }
274 
275 //======================================================================================//
276