/** This file is a part of rexy's general purpose library Copyright (C) 2020 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef REXY_THREADPOOL_HPP #define REXY_THREADPOOL_HPP #include #include #include #include //unique_lock, scoped_lock #include //shared_mutex, shared_lock #include //atomic_bool #include //shared_ptr #include //future, packaged_task #include //function, bind #include //move, forward namespace rexy{ class threadpool { private: using mutex_t = std::shared_mutex; using write_lock_t = std::unique_lock; using read_lock_t = std::shared_lock; private: mutable read_lock_t m_ctor_lock; mutable std::condition_variable_any m_qcv; mutable mutex_t m_qlk; std::vector m_workers; std::queue> m_jobs; std::atomic_bool m_valid = true; public: explicit threadpool(int numthreads = std::thread::hardware_concurrency()); threadpool(const threadpool&); threadpool(threadpool&&); ~threadpool(void); threadpool& operator=(const threadpool&) = delete; threadpool& operator=(threadpool&&) = delete; void invalidate(void); template auto add_job(Func&& f, Args&&... args) -> std::future(f)(std::forward(args)...))>; private: void worker_loop(void); }; template auto threadpool::add_job(Func&& f, Args&&... args) -> std::future(f)(std::forward(args)...))>{ using return_t = decltype(std::forward(f)(std::forward(args)...)); using task_t = std::packaged_task; //shared pointer to a packaged task which takes no arguments in operator() std::shared_ptr task_ptr = std::make_shared(std::bind(std::forward(f), std::forward(args)...)); { write_lock_t lk(m_qlk); //make a copy of the shared pointer by capturing by-value m_jobs.emplace([task_ptr]{(*task_ptr)();}); } //wakeup a worker to run the job m_qcv.notify_one(); return task_ptr->get_future(); } } #endif