|
@@ -1,191 +0,0 @@
|
|
|
-/*
|
|
|
|
|
- * ThreadPool.h, part of VCMI engine
|
|
|
|
|
- *
|
|
|
|
|
- * Authors: listed in file AUTHORS in main folder
|
|
|
|
|
- *
|
|
|
|
|
- * License: GNU General Public License v2.0 or later
|
|
|
|
|
- * Full text of license available in license.txt file, in main folder
|
|
|
|
|
- *
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
-#pragma once
|
|
|
|
|
-
|
|
|
|
|
-#include "BlockingQueue.h"
|
|
|
|
|
-#include <boost/thread/future.hpp>
|
|
|
|
|
-#include <boost/thread/condition_variable.hpp>
|
|
|
|
|
-
|
|
|
|
|
-VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
-
|
|
|
|
|
-typedef std::function<void()> TRMGfunction ;
|
|
|
|
|
-typedef std::optional<TRMGfunction> TRMGJob;
|
|
|
|
|
-
|
|
|
|
|
-//Credit to https://github.com/Liam0205/toy-threadpool/tree/master/yuuki
|
|
|
|
|
-
|
|
|
|
|
-class DLL_LINKAGE ThreadPool
|
|
|
|
|
-{
|
|
|
|
|
-private:
|
|
|
|
|
- using Lock = std::unique_lock<std::shared_mutex>;
|
|
|
|
|
- mutable std::shared_mutex mx;
|
|
|
|
|
- mutable std::condition_variable_any cv;
|
|
|
|
|
- mutable std::once_flag once;
|
|
|
|
|
-
|
|
|
|
|
- bool isInitialized = false;
|
|
|
|
|
- bool stopping = false;
|
|
|
|
|
- bool canceling = false;
|
|
|
|
|
-public:
|
|
|
|
|
- ThreadPool();
|
|
|
|
|
- ~ThreadPool();
|
|
|
|
|
-
|
|
|
|
|
- void init(size_t numThreads);
|
|
|
|
|
- void spawn();
|
|
|
|
|
- void terminate();
|
|
|
|
|
- void cancel();
|
|
|
|
|
-
|
|
|
|
|
-public:
|
|
|
|
|
- bool initialized() const;
|
|
|
|
|
- bool running() const;
|
|
|
|
|
- int size() const;
|
|
|
|
|
-private:
|
|
|
|
|
- bool isRunning() const;
|
|
|
|
|
-
|
|
|
|
|
-public:
|
|
|
|
|
- auto async(std::function<void()>&& f) const -> boost::future<void>;
|
|
|
|
|
-
|
|
|
|
|
-private:
|
|
|
|
|
- std::vector<boost::thread> workers;
|
|
|
|
|
- mutable BlockingQueue<TRMGfunction> tasks;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-ThreadPool::ThreadPool()
|
|
|
|
|
-{};
|
|
|
|
|
-
|
|
|
|
|
-ThreadPool::~ThreadPool()
|
|
|
|
|
-{
|
|
|
|
|
- terminate();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline void ThreadPool::init(size_t numThreads)
|
|
|
|
|
-{
|
|
|
|
|
- std::call_once(once, [this, numThreads]()
|
|
|
|
|
- {
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- stopping = false;
|
|
|
|
|
- canceling = false;
|
|
|
|
|
- workers.reserve(numThreads);
|
|
|
|
|
- for (size_t i = 0; i < numThreads; ++i)
|
|
|
|
|
- {
|
|
|
|
|
- workers.emplace_back(std::bind(&ThreadPool::spawn, this));
|
|
|
|
|
- }
|
|
|
|
|
- isInitialized = true;
|
|
|
|
|
- });
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-bool ThreadPool::isRunning() const
|
|
|
|
|
-{
|
|
|
|
|
- return isInitialized && !stopping && !canceling;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline bool ThreadPool::initialized() const
|
|
|
|
|
-{
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- return isInitialized;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline bool ThreadPool::running() const
|
|
|
|
|
-{
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- return isRunning();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline int ThreadPool::size() const
|
|
|
|
|
-{
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- return workers.size();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline void ThreadPool::spawn()
|
|
|
|
|
-{
|
|
|
|
|
- while(true)
|
|
|
|
|
- {
|
|
|
|
|
- bool pop = false;
|
|
|
|
|
- TRMGfunction task;
|
|
|
|
|
- {
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- cv.wait(lock, [this, &pop, &task]
|
|
|
|
|
- {
|
|
|
|
|
- pop = tasks.pop(task);
|
|
|
|
|
- return canceling || stopping || pop;
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- if (canceling || (stopping && !pop))
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- task();
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline void ThreadPool::terminate()
|
|
|
|
|
-{
|
|
|
|
|
- {
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- if (isRunning())
|
|
|
|
|
- {
|
|
|
|
|
- stopping = true;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- cv.notify_all();
|
|
|
|
|
- for (auto& worker : workers)
|
|
|
|
|
- {
|
|
|
|
|
- worker.join();
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline void ThreadPool::cancel()
|
|
|
|
|
-{
|
|
|
|
|
- {
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- if (running())
|
|
|
|
|
- {
|
|
|
|
|
- canceling = true;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- tasks.clear();
|
|
|
|
|
- cv.notify_all();
|
|
|
|
|
- for (auto& worker : workers)
|
|
|
|
|
- {
|
|
|
|
|
- worker.join();
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-auto ThreadPool::async(std::function<void()>&& f) const -> boost::future<void>
|
|
|
|
|
-{
|
|
|
|
|
- using TaskT = boost::packaged_task<void>;
|
|
|
|
|
-
|
|
|
|
|
- {
|
|
|
|
|
- Lock lock(mx);
|
|
|
|
|
- if (stopping || canceling)
|
|
|
|
|
- {
|
|
|
|
|
- throw std::runtime_error("Delegating task to a threadpool that has been terminated or canceled.");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- auto task = std::make_shared<TaskT>(f);
|
|
|
|
|
- boost::future<void> fut = task->get_future();
|
|
|
|
|
- tasks.emplace([task]() -> void
|
|
|
|
|
- {
|
|
|
|
|
- (*task)();
|
|
|
|
|
- });
|
|
|
|
|
- cv.notify_one();
|
|
|
|
|
- return fut;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-VCMI_LIB_NAMESPACE_END
|
|
|