فهرست منبع

Remove custom implementation of threadpool from rmg in favor of TBB

Ivan Savenko 8 ماه پیش
والد
کامیت
33468f21ff

+ 2 - 4
lib/CMakeLists.txt

@@ -217,7 +217,7 @@ set(lib_MAIN_SRCS
 	rmg/modificators/ObstaclePlacer.cpp
 	rmg/modificators/RiverPlacer.cpp
 	rmg/modificators/TerrainPainter.cpp
-	rmg/threadpool/MapProxy.cpp
+	rmg/MapProxy.cpp
 
 	serializer/BinaryDeserializer.cpp
 	serializer/BinarySerializer.cpp
@@ -633,9 +633,7 @@ set(lib_MAIN_HEADERS
 	rmg/modificators/ObstaclePlacer.h
 	rmg/modificators/RiverPlacer.h
 	rmg/modificators/TerrainPainter.h
-	rmg/threadpool/BlockingQueue.h
-	rmg/threadpool/ThreadPool.h
-	rmg/threadpool/MapProxy.h
+	rmg/MapProxy.h
 
 	serializer/BinaryDeserializer.h
 	serializer/BinarySerializer.h

+ 6 - 11
lib/rmg/CMapGenerator.cpp

@@ -29,7 +29,6 @@
 #include "Zone.h"
 #include "Functions.h"
 #include "RmgMap.h"
-#include "threadpool/ThreadPool.h"
 #include "modificators/ObjectManager.h"
 #include "modificators/TreasurePlacer.h"
 #include "modificators/RoadPlacer.h"
@@ -37,6 +36,8 @@
 #include <vstd/RNG.h>
 #include <vcmi/HeroTypeService.h>
 
+#include <tbb/task_group.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 CMapGenerator::CMapGenerator(CMapGenOptions& mapGenOptions, IGameCallback * cb, int RandomSeed) :
@@ -395,10 +396,7 @@ void CMapGenerator::fillZones()
 	}
 	else
 	{
-		ThreadPool pool;
-		std::vector<boost::future<void>> futures;
-		//At most one Modificator can run for every zone
-		pool.init(std::min<int>(boost::thread::hardware_concurrency(), numZones));
+		tbb::task_group pool;
 
 		while (!allJobs.empty())
 		{
@@ -412,12 +410,12 @@ void CMapGenerator::fillZones()
 				else if ((*it)->isReady())
 				{
 					auto jobCopy = *it;
-					futures.emplace_back(pool.async([this, jobCopy]() -> void
+					pool.run([this, jobCopy]() -> void
 						{
 							jobCopy->run();
 							Progress::Progress::step(); //Update progress bar
 						}
-					));
+					);
 					it = allJobs.erase(it);
 				}
 				else
@@ -428,10 +426,7 @@ void CMapGenerator::fillZones()
 		}
 
 		//Wait for all the tasks
-		for (auto& fut : futures)
-		{
-			fut.get();
-		}
+		pool.wait();
 	}
 
 	for (const auto& it : map->getZones())

+ 2 - 2
lib/rmg/threadpool/MapProxy.cpp → lib/rmg/MapProxy.cpp

@@ -9,8 +9,8 @@
  */
 
 #include "MapProxy.h"
-#include "../../TerrainHandler.h"
-#include "../../GameLibrary.h"
+#include "../TerrainHandler.h"
+#include "../GameLibrary.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 

+ 3 - 3
lib/rmg/threadpool/MapProxy.h → lib/rmg/MapProxy.h

@@ -11,9 +11,9 @@
 #pragma once
 
 #include "StdInc.h"
-#include "../../mapping/CMap.h"
-#include "../RmgMap.h"
-#include "../../mapping/CMapEditManager.h"
+#include "../mapping/CMap.h"
+#include "RmgMap.h"
+#include "../mapping/CMapEditManager.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 

+ 1 - 1
lib/rmg/RmgMap.h

@@ -11,7 +11,7 @@
 #pragma once
 #include "../int3.h"
 #include "../GameConstants.h"
-#include "threadpool/MapProxy.h"
+#include "MapProxy.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 

+ 2 - 2
lib/rmg/modificators/Modificator.h

@@ -13,7 +13,7 @@
 #include "../../GameConstants.h"
 #include "../../int3.h"
 #include "../Zone.h"
-#include "../threadpool/MapProxy.h"
+#include "../MapProxy.h"
 
 class RmgMap;
 class CMapGenerator;
@@ -78,4 +78,4 @@ private:
 	void dump();
 };
 
-VCMI_LIB_NAMESPACE_END
+VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/rmg/modificators/RoadPlacer.cpp

@@ -15,7 +15,7 @@
 #include "RockFiller.h"
 #include "../Functions.h"
 #include "../CMapGenerator.h"
-#include "../threadpool/MapProxy.h"
+#include "../MapProxy.h"
 #include "../../mapping/CMapEditManager.h"
 #include "../../mapObjects/CGObjectInstance.h"
 #include "../../modding/IdentifierStorage.h"

+ 1 - 1
lib/rmg/modificators/RockFiller.cpp

@@ -21,7 +21,7 @@
 #include "../../TerrainHandler.h"
 #include "../lib/mapping/CMapEditManager.h"
 #include "../TileInfo.h"
-#include "../threadpool/MapProxy.h"
+#include "../MapProxy.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 

+ 0 - 91
lib/rmg/threadpool/BlockingQueue.h

@@ -1,91 +0,0 @@
-/*
- * BlockingQueue.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 "StdInc.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-//Credit to https://github.com/Liam0205/toy-threadpool/tree/master/yuuki
-
-template <typename T>
-class DLL_LINKAGE BlockingQueue : protected std::queue<T>
-{
-	using WriteLock = std::unique_lock<std::shared_mutex>;
-	using Readlock = std::shared_lock<std::shared_mutex>;
-
-public:
-	BlockingQueue() = default;
-	~BlockingQueue()
-	{
-		clear();
-  	}
-	BlockingQueue(const BlockingQueue&) = delete;
-	BlockingQueue(BlockingQueue&&) = delete;
-	BlockingQueue& operator=(const BlockingQueue&) = delete;
-	BlockingQueue& operator=(BlockingQueue&&) = delete;
-
-public:
-	bool empty() const
-	{
-		Readlock lock(mx);
-		return std::queue<T>::empty();
-	}
-
-	size_t size() const
-	{
-		Readlock lock(mx);
-		return std::queue<T>::size();
-	}
-
-public:
-	void clear()
-	{
-		WriteLock lock(mx);
-		while (!std::queue<T>::empty())
-		{
-			std::queue<T>::pop();
-		}
-	}
-
-	void push(const T& obj)
-	{
-		WriteLock lock(mx);
-		std::queue<T>::push(obj);
-	}
-
-	template <typename... Args>
-	void emplace(Args&&... args)
-	{
-		WriteLock lock(mx);
-		std::queue<T>::emplace(std::forward<Args>(args)...);
-	}
-
-	bool pop(T& holder)
-	{
-		WriteLock lock(mx);
-		if (std::queue<T>::empty())
-		{
-			return false;
-		}
-		else
-		{
-			holder = std::move(std::queue<T>::front());
-			std::queue<T>::pop();
-			return true;
-		}
-	}
-
-private:
-	mutable std::shared_mutex mx;
-};
-
-VCMI_LIB_NAMESPACE_END

+ 0 - 191
lib/rmg/threadpool/ThreadPool.h

@@ -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