Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:47

0001 //
0002 // MIT License
0003 // Copyright (c) 2020 Jonathan R. Madsen
0004 // Permission is hereby granted, free of charge, to any person obtaining a copy
0005 // of this software and associated documentation files (the "Software"), to deal
0006 // in the Software without restriction, including without limitation the rights
0007 // to use, copy, modify, merge, publish, distribute, sublicense, and
0008 // copies of the Software, and to permit persons to whom the Software is
0009 // furnished to do so, subject to the following conditions:
0010 // The above copyright notice and this permission notice shall be included in
0011 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
0012 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
0013 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
0014 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
0015 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0016 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0017 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0018 //
0019 // ---------------------------------------------------------------
0020 // Tasking class header file
0021 //
0022 // Class Description:
0023 //
0024 // This file creates a class for handling the wrapping of functions
0025 // into task objects and submitting to thread pool
0026 //
0027 // ---------------------------------------------------------------
0028 // Author: Jonathan Madsen (Feb 13th 2018)
0029 // ---------------------------------------------------------------
0030 
0031 #pragma once
0032 
0033 #include "PTL/Globals.hh"
0034 #include "PTL/Task.hh"
0035 #include "PTL/TaskGroup.hh"
0036 #include "PTL/ThreadPool.hh"
0037 
0038 #include <iostream>
0039 #include <memory>
0040 #include <stdexcept>
0041 #include <thread>
0042 #include <utility>
0043 
0044 namespace PTL
0045 {
0046 //======================================================================================//
0047 
0048 class TaskManager
0049 {
0050 public:
0051     using this_type = TaskManager;
0052     using size_type = ThreadPool::size_type;
0053 
0054 public:
0055     // Constructor and Destructors
0056     explicit TaskManager(ThreadPool*, bool _manage_pool = true);
0057     virtual ~TaskManager() noexcept(false);
0058 
0059     TaskManager(const TaskManager&) = delete;
0060     TaskManager(TaskManager&&)      = default;
0061     TaskManager& operator=(const TaskManager&) = delete;
0062     TaskManager& operator=(TaskManager&&) = default;
0063 
0064 public:
0065     /// get the singleton pointer
0066     static TaskManager* GetInstance();
0067     static TaskManager* GetInstanceIfExists();
0068     static unsigned     ncores() { return std::thread::hardware_concurrency(); }
0069 
0070 public:
0071     //------------------------------------------------------------------------//
0072     // return the thread pool
0073     inline ThreadPool* thread_pool() const { return m_pool; }
0074 
0075     //------------------------------------------------------------------------//
0076     // return the number of threads in the thread pool
0077     inline size_type size() const { return (m_pool) ? m_pool->size() : 0; }
0078 
0079     //------------------------------------------------------------------------//
0080     // kill all the threads
0081     inline void finalize()
0082     {
0083         if(m_is_finalized)
0084             return;
0085         m_is_finalized = true;
0086         if(m_pool)
0087             m_pool->destroy_threadpool();
0088     }
0089     //------------------------------------------------------------------------//
0090 
0091 public:
0092     //------------------------------------------------------------------------//
0093     // direct insertion of a task
0094     //------------------------------------------------------------------------//
0095     template <typename... Args>
0096     void exec(Task<Args...>* _task)
0097     {
0098         if(!m_pool)
0099             throw std::runtime_error("Nullptr to thread-pool");
0100         m_pool->add_task(_task);
0101     }
0102 
0103     //------------------------------------------------------------------------//
0104     // direct insertion of a packaged_task
0105     //------------------------------------------------------------------------//
0106     template <typename RetT, typename FuncT, typename... Args>
0107     std::shared_ptr<PackagedTask<RetT, Args...>> async(FuncT&& func, Args&&... args)
0108     {
0109         using task_type = PackagedTask<RetT, Args...>;
0110 
0111         if(!m_pool)
0112             throw std::runtime_error("Nullptr to thread-pool");
0113 
0114         auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func),
0115                                                   std::forward<Args>(args)...);
0116         m_pool->add_task(_ptask);
0117         return _ptask;
0118     }
0119     //------------------------------------------------------------------------//
0120     template <typename RetT, typename FuncT>
0121     std::shared_ptr<PackagedTask<RetT>> async(FuncT&& func)
0122     {
0123         using task_type = PackagedTask<RetT>;
0124 
0125         if(!m_pool)
0126             throw std::runtime_error("Nullptr to thread-pool");
0127 
0128         auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func));
0129         m_pool->add_task(_ptask);
0130         return _ptask;
0131     }
0132     //------------------------------------------------------------------------//
0133     template <typename FuncT, typename... Args>
0134     auto async(FuncT&& func, Args... args)
0135         -> std::shared_ptr<PackagedTask<decay_t<decltype(func(args...))>, Args...>>
0136     {
0137         using RetT      = decay_t<decltype(func(args...))>;
0138         using task_type = PackagedTask<RetT, Args...>;
0139 
0140         if(!m_pool)
0141             throw std::runtime_error("Nullptr to thread-pool");
0142 
0143         auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func),
0144                                                   std::forward<Args>(args)...);
0145         m_pool->add_task(_ptask);
0146         return _ptask;
0147     }
0148     //------------------------------------------------------------------------//
0149 
0150 public:
0151     //------------------------------------------------------------------------//
0152     // public wrap functions
0153     //------------------------------------------------------------------------//
0154     template <typename RetT, typename ArgT, typename FuncT, typename... Args>
0155     std::shared_ptr<Task<RetT, ArgT, Args...>> wrap(TaskGroup<RetT, ArgT>& tg,
0156                                                     FuncT&& func, Args&&... args)
0157     {
0158         return tg.wrap(std::forward<FuncT>(func), std::forward<Args>(args)...);
0159     }
0160     //------------------------------------------------------------------------//
0161     template <typename RetT, typename ArgT, typename FuncT>
0162     std::shared_ptr<Task<RetT, ArgT>> wrap(TaskGroup<RetT, ArgT>& tg, FuncT&& func)
0163     {
0164         return tg.wrap(std::forward<FuncT>(func));
0165     }
0166 
0167 public:
0168     //------------------------------------------------------------------------//
0169     // public exec functions
0170     //------------------------------------------------------------------------//
0171     template <typename RetT, typename ArgT, typename FuncT, typename... Args>
0172     void exec(TaskGroup<RetT, ArgT>& tg, FuncT&& func, Args&&... args)
0173     {
0174         tg.exec(std::forward<FuncT>(func), std::forward<Args>(args)...);
0175     }
0176     //------------------------------------------------------------------------//
0177     template <typename RetT, typename ArgT, typename FuncT>
0178     void exec(TaskGroup<RetT, ArgT>& tg, FuncT&& func)
0179     {
0180         tg.exec(std::forward<FuncT>(func));
0181     }
0182     //------------------------------------------------------------------------//
0183     template <typename RetT, typename ArgT, typename FuncT, typename... Args>
0184     void rexec(TaskGroup<RetT, ArgT>& tg, FuncT&& func, Args&&... args)
0185     {
0186         tg.exec(std::forward<FuncT>(func), std::forward<Args>(args)...);
0187     }
0188     //------------------------------------------------------------------------//
0189     template <typename RetT, typename ArgT, typename FuncT>
0190     void rexec(TaskGroup<RetT, ArgT>& tg, FuncT&& func)
0191     {
0192         tg.exec(std::forward<FuncT>(func));
0193     }
0194     //------------------------------------------------------------------------//
0195     // public exec functions (void specializations)
0196     //------------------------------------------------------------------------//
0197     template <typename FuncT, typename... Args>
0198     void rexec(TaskGroup<void, void>& tg, FuncT&& func, Args&&... args)
0199     {
0200         tg.exec(std::forward<FuncT>(func), std::forward<Args>(args)...);
0201     }
0202     //------------------------------------------------------------------------//
0203     template <typename FuncT>
0204     void rexec(TaskGroup<void, void>& tg, FuncT&& func)
0205     {
0206         tg.exec(std::forward<FuncT>(func));
0207     }
0208     //------------------------------------------------------------------------//
0209 
0210 protected:
0211     // Protected variables
0212     ThreadPool* m_pool         = nullptr;
0213     bool        m_is_finalized = false;
0214 
0215 private:
0216     static TaskManager*& fgInstance();
0217 };
0218 
0219 }  // namespace PTL
0220 //======================================================================================//
0221 
0222 #include "TaskRunManager.hh"
0223 
0224 //--------------------------------------------------------------------------------------//
0225 
0226 inline PTL::TaskManager*&
0227 PTL::TaskManager::fgInstance()
0228 {
0229     static thread_local TaskManager* _instance = nullptr;
0230     return _instance;
0231 }
0232 
0233 //--------------------------------------------------------------------------------------//
0234 
0235 inline PTL::TaskManager*
0236 PTL::TaskManager::GetInstance()
0237 {
0238     if(!fgInstance())
0239     {
0240         auto nthreads = std::thread::hardware_concurrency();
0241         std::cout << "Allocating mad::TaskManager with " << nthreads << " thread(s)..."
0242                   << std::endl;
0243         new TaskManager(TaskRunManager::GetMasterRunManager()->GetThreadPool());
0244     }
0245     return fgInstance();
0246 }
0247 
0248 //--------------------------------------------------------------------------------------//
0249 
0250 inline PTL::TaskManager*
0251 PTL::TaskManager::GetInstanceIfExists()
0252 {
0253     return fgInstance();
0254 }
0255 
0256 //--------------------------------------------------------------------------------------//
0257 
0258 inline PTL::TaskManager::TaskManager(ThreadPool* _pool, bool _manage_pool)
0259 : m_pool(_pool)
0260 , m_is_finalized(!_manage_pool)
0261 {
0262     if(!fgInstance())
0263         fgInstance() = this;
0264 }
0265 
0266 //--------------------------------------------------------------------------------------//
0267 
0268 inline PTL::TaskManager::~TaskManager() noexcept(false)
0269 {
0270     finalize();
0271     if(fgInstance() == this)
0272         fgInstance() = nullptr;
0273 }
0274 
0275 //======================================================================================//