// // MIT License // Copyright (c) 2020 Jonathan R. Madsen // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // --------------------------------------------------------------- // Tasking class header file // // Class Description: // // This file creates a class for handling the wrapping of functions // into task objects and submitting to thread pool // // --------------------------------------------------------------- // Author: Jonathan Madsen (Feb 13th 2018) // --------------------------------------------------------------- #pragma once #include "PTL/Macros.hh" #include "PTL/Task.hh" #include "PTL/TaskGroup.hh" #include "PTL/ThreadPool.hh" #include #include #include #include #include namespace PTL { //======================================================================================// class TaskManager { public: using this_type = TaskManager; using size_type = ThreadPool::size_type; public: // Constructor and Destructors explicit TaskManager(ThreadPool*, bool _manage_pool = true); virtual ~TaskManager() noexcept(false); TaskManager(const TaskManager&) = delete; TaskManager(TaskManager&&) = default; TaskManager& operator=(const TaskManager&) = delete; TaskManager& operator=(TaskManager&&) = default; public: /// get the singleton pointer static TaskManager* GetInstance(); static TaskManager* GetInstanceIfExists(); static unsigned ncores() { return std::thread::hardware_concurrency(); } public: //------------------------------------------------------------------------// // return the thread pool inline ThreadPool* thread_pool() const { return m_pool; } //------------------------------------------------------------------------// // return the number of threads in the thread pool inline size_type size() const { return (m_pool) ? m_pool->size() : 0; } //------------------------------------------------------------------------// // kill all the threads inline void finalize() { if(m_is_finalized) return; m_is_finalized = true; if(m_pool) m_pool->destroy_threadpool(); } //------------------------------------------------------------------------// public: //------------------------------------------------------------------------// // direct insertion of a task //------------------------------------------------------------------------// template void exec(Task* _task) { if(!m_pool) throw std::runtime_error("Nullptr to thread-pool"); m_pool->add_task(_task); } //------------------------------------------------------------------------// // direct insertion of a packaged_task //------------------------------------------------------------------------// template std::shared_ptr> async(FuncT&& func, Args&&... args) { using task_type = PackagedTask; if(!m_pool) throw std::runtime_error("Nullptr to thread-pool"); auto _ptask = std::make_shared(std::forward(func), std::forward(args)...); m_pool->add_task(_ptask); return _ptask; } //------------------------------------------------------------------------// template std::shared_ptr> async(FuncT&& func) { using task_type = PackagedTask; if(!m_pool) throw std::runtime_error("Nullptr to thread-pool"); auto _ptask = std::make_shared(std::forward(func)); m_pool->add_task(_ptask); return _ptask; } //------------------------------------------------------------------------// template auto async(FuncT&& func, Args... args) -> std::shared_ptr, Args...>> { using RetT = decay_t; using task_type = PackagedTask; if(!m_pool) throw std::runtime_error("Nullptr to thread-pool"); auto _ptask = std::make_shared(std::forward(func), std::forward(args)...); m_pool->add_task(_ptask); return _ptask; } //------------------------------------------------------------------------// public: //------------------------------------------------------------------------// // public wrap functions //------------------------------------------------------------------------// template std::shared_ptr> wrap(TaskGroup& tg, FuncT&& func, Args&&... args) { return tg.wrap(std::forward(func), std::forward(args)...); } //------------------------------------------------------------------------// template std::shared_ptr> wrap(TaskGroup& tg, FuncT&& func) { return tg.wrap(std::forward(func)); } public: //------------------------------------------------------------------------// // public exec functions //------------------------------------------------------------------------// template void exec(TaskGroup& tg, FuncT&& func, Args&&... args) { tg.exec(std::forward(func), std::forward(args)...); } //------------------------------------------------------------------------// template void exec(TaskGroup& tg, FuncT&& func) { tg.exec(std::forward(func)); } //------------------------------------------------------------------------// template void rexec(TaskGroup& tg, FuncT&& func, Args&&... args) { tg.exec(std::forward(func), std::forward(args)...); } //------------------------------------------------------------------------// template void rexec(TaskGroup& tg, FuncT&& func) { tg.exec(std::forward(func)); } //------------------------------------------------------------------------// // public exec functions (void specializations) //------------------------------------------------------------------------// template void rexec(TaskGroup& tg, FuncT&& func, Args&&... args) { tg.exec(std::forward(func), std::forward(args)...); } //------------------------------------------------------------------------// template void rexec(TaskGroup& tg, FuncT&& func) { tg.exec(std::forward(func)); } //------------------------------------------------------------------------// protected: // Protected variables ThreadPool* m_pool = nullptr; bool m_is_finalized = false; private: static TaskManager*& fgInstance(); }; } // namespace PTL //======================================================================================// #include "TaskRunManager.hh" //--------------------------------------------------------------------------------------// inline PTL::TaskManager*& PTL::TaskManager::fgInstance() { static thread_local TaskManager* _instance = nullptr; return _instance; } //--------------------------------------------------------------------------------------// inline PTL::TaskManager* PTL::TaskManager::GetInstance() { if(!fgInstance()) { auto nthreads = std::thread::hardware_concurrency(); std::cout << "Allocating mad::TaskManager with " << nthreads << " thread(s)..." << std::endl; new TaskManager(TaskRunManager::GetMasterRunManager()->GetThreadPool()); } return fgInstance(); } //--------------------------------------------------------------------------------------// inline PTL::TaskManager* PTL::TaskManager::GetInstanceIfExists() { return fgInstance(); } //--------------------------------------------------------------------------------------// inline PTL::TaskManager::TaskManager(ThreadPool* _pool, bool _manage_pool) : m_pool(_pool) , m_is_finalized(!_manage_pool) { if(!fgInstance()) fgInstance() = this; } //--------------------------------------------------------------------------------------// inline PTL::TaskManager::~TaskManager() noexcept(false) { finalize(); if(fgInstance() == this) fgInstance() = nullptr; } //======================================================================================//