#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; 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