Explorar o código

Thread pool kinda works.

Tomasz Zieliński %!s(int64=2) %!d(string=hai) anos
pai
achega
a58094aefe
Modificáronse 6 ficheiros con 287 adicións e 88 borrados
  1. 31 34
      lib/rmg/CMapGenerator.cpp
  2. 1 5
      lib/rmg/CMapGenerator.h
  3. 159 0
      lib/rmg/Modificator.cpp
  4. 80 0
      lib/rmg/Modificator.h
  5. 9 44
      lib/rmg/Zone.cpp
  6. 7 5
      lib/rmg/Zone.h

+ 31 - 34
lib/rmg/CMapGenerator.cpp

@@ -309,7 +309,7 @@ void CMapGenerator::fillZones()
 	}
 
 	//TODO: multiply by the number of modificators
-	Load::Progress::setupStepsTill(numZones, 240);
+
 	std::vector<std::shared_ptr<Zone>> treasureZones;
 
 	ThreadPool pool;
@@ -318,17 +318,38 @@ void CMapGenerator::fillZones()
 	//At most one Modificator can run for every zone
 	pool.init(std::min<int>(std::thread::hardware_concurrency(), numZones));
 
-	while (hasJobs())
+	TModificators allJobs;
+	for (auto & it : map->getZones())
 	{
-		auto job = getNextJob();
-		if (job)
+		allJobs.splice(allJobs.end(), it.second->getModificators());
+	}
+
+	Load::Progress::setupStepsTill(allJobs.size(), 240);
+
+	while (!allJobs.empty())
+	{
+		for (auto it = allJobs.begin(); it != allJobs.end();)
 		{
-			futures.push_back(pool.async([this, job]() -> void
-				{
-					job.value()();
-					Progress::Progress::step(); //Update progress bar
-				}
-			));
+			if ((*it)->isFinished())
+			{
+				it = allJobs.erase(it);
+				Progress::Progress::step();
+			}
+			else if ((*it)->isReady())
+			{
+				auto jobCopy = *it;
+				futures.emplace_back(pool.async([this, jobCopy]() -> void
+					{
+						jobCopy->run();
+						Progress::Progress::step(); //Update progress bar
+					}
+				));
+				it = allJobs.erase(it);
+			}
+			else
+			{
+				++it;
+			}
 		}
 	}
 
@@ -441,28 +462,4 @@ Zone * CMapGenerator::getZoneWater() const
 	return nullptr;
 }
 
-bool CMapGenerator::hasJobs()
-{
-	for (auto zone : map->getZones())
-	{
-		if (zone.second->hasJobs())
-		{
-			return true;
-		}
-	}
-	return false;
-}
-
-TRMGJob CMapGenerator::getNextJob()
-{
-	for (auto zone : map->getZones())
-	{
-		if (zone.second->hasJobs())
-		{
-			return zone.second->getNextJob();
-		}
-	}
-	return TRMGJob();
-}
-
 VCMI_LIB_NAMESPACE_END

+ 1 - 5
lib/rmg/CMapGenerator.h

@@ -31,7 +31,7 @@ class CZonePlacer;
 using JsonVector = std::vector<JsonNode>;
 
 /// The map generator creates a map randomly.
-class DLL_LINKAGE CMapGenerator: public Load::Progress, public IJobProvider
+class DLL_LINKAGE CMapGenerator: public Load::Progress
 {
 public:
 	struct Config
@@ -98,10 +98,6 @@ private:
 	void addHeaderInfo();
 	void genZones();
 	void fillZones();
-
-	TRMGJob getNextJob() override;
-	bool hasJobs() override;
-
 };
 
 VCMI_LIB_NAMESPACE_END

+ 159 - 0
lib/rmg/Modificator.cpp

@@ -0,0 +1,159 @@
+/*
+ * Modificator.cpp, 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
+ *
+ */
+
+#include "Modificator.h"
+#include "Functions.h"
+#include "CMapGenerator.h"
+#include "RmgMap.h"
+#include "../CStopWatch.h"
+#include "../mapping/CMap.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+Modificator::Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator) : zone(zone), map(map), generator(generator)
+{
+}
+
+void Modificator::setName(const std::string & n)
+{
+	name = n;
+}
+
+const std::string & Modificator::getName() const
+{
+	return name;
+}
+
+bool Modificator::isReady()
+{
+	Lock lock(mx, boost::try_to_lock_t{});
+	if (!lock.owns_lock())
+	{
+		return false;
+	}
+	else
+	{
+		//Check prerequisites
+		for (auto it = preceeders.begin(); it != preceeders.end();)
+		{
+			if ((*it)->isFinished()) //OK
+			{
+				it = preceeders.erase(it);
+			}
+			else if (!(*it)->isReady())
+			{
+				return false;
+			}
+			else
+			{
+				++it;
+			}
+		}
+
+		return !finished;
+	}
+}
+
+bool Modificator::isFinished()
+{
+	Lock lock(mx, boost::try_to_lock_t{});
+	if (!lock.owns_lock())
+	{
+		return false;
+	}
+	else
+	{
+		return finished;
+	}
+}
+
+void Modificator::run()
+{
+	Lock lock(mx);
+
+	if(!finished)
+	{
+		logGlobal->info("Modificator zone %d - %s - started", zone.getId(), getName());
+		CStopWatch processTime;
+		try
+		{
+			process();
+		}
+		catch(rmgException &e)
+		{
+			logGlobal->error("Modificator %s, exception: %s", getName(), e.what());
+		}
+#ifdef RMG_DUMP
+		dump();
+#endif
+		finished = true;
+		logGlobal->info("Modificator zone %d - %s - done (%d ms)", zone.getId(), getName(), processTime.getDiff());
+	}
+}
+
+void Modificator::dependency(Modificator * modificator)
+{
+	if(modificator && modificator != this)
+	{
+		if(std::find(preceeders.begin(), preceeders.end(), modificator) == preceeders.end())
+			preceeders.push_back(modificator);
+	}
+}
+
+void Modificator::postfunction(Modificator * modificator)
+{
+	if(modificator && modificator != this)
+	{
+		if(std::find(modificator->preceeders.begin(), modificator->preceeders.end(), this) == modificator->preceeders.end())
+			modificator->preceeders.push_back(this);
+	}
+}
+
+void Modificator::dump()
+{
+	std::ofstream out(boost::to_string(boost::format("seed_%d_modzone_%d_%s.txt") % generator.getRandomSeed() % zone.getId() % getName()));
+	auto & mapInstance = map.map();
+	int levels = mapInstance.levels();
+	int width =  mapInstance.width;
+	int height = mapInstance.height;
+	for(int z = 0; z < levels; z++)
+	{
+		for(int j=0; j<height; j++)
+		{
+			for(int i=0; i<width; i++)
+			{
+				out << dump(int3(i, j, z));
+			}
+			out << std::endl;
+		}
+		out << std::endl;
+	}
+	out << std::endl;
+}
+
+char Modificator::dump(const int3 & t)
+{
+	if(zone.freePaths().contains(t))
+		return '.'; //free path
+	if(zone.areaPossible().contains(t))
+		return ' '; //possible
+	if(zone.areaUsed().contains(t))
+		return 'U'; //used
+	if(zone.area().contains(t))
+	{
+		if(map.shouldBeBlocked(t))
+			return '#'; //obstacle
+		else
+			return '^'; //visitable points?
+	}
+	return '?';
+}
+
+VCMI_LIB_NAMESPACE_END

+ 80 - 0
lib/rmg/Modificator.h

@@ -0,0 +1,80 @@
+/*
+ * Modificator.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 "../GameConstants.h"
+#include "../int3.h"
+#include "threadpool/JobProvider.h"
+#include "Zone.h"
+
+class RmgMap;
+class CMapGenerator;
+class Zone;
+
+
+
+#define MODIFICATOR(x) x(Zone & z, RmgMap & m, CMapGenerator & g): Modificator(z, m, g) {setName(#x);}
+#define DEPENDENCY(x) 		dependency(zone.getModificator<x>());
+#define POSTFUNCTION(x)		postfunction(zone.getModificator<x>());
+#define DEPENDENCY_ALL(x) 	for(auto & z : map.getZones()) \
+							{ \
+								dependency(z.second->getModificator<x>()); \
+							}
+#define POSTFUNCTION_ALL(x) for(auto & z : map.getZones()) \
+							{ \
+								postfunction(z.second->getModificator<x>()); \
+							}
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class Modificator
+{
+public:
+	Modificator() = delete;
+	Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator);
+	
+	virtual void init() {/*override to add dependencies*/}
+	virtual char dump(const int3 &);
+	virtual ~Modificator() = default;
+
+	void setName(const std::string & n);
+	const std::string & getName() const;
+
+	bool isReady();
+	bool isFinished();
+	
+	void run();
+	void dependency(Modificator * modificator);
+	void postfunction(Modificator * modificator);
+
+protected:
+	RmgMap & map;
+	CMapGenerator & generator;
+	Zone & zone;
+
+	bool finished = false;
+	
+	//bool wasStarted() const;
+private:
+	virtual void process() = 0;
+
+	std::string name;
+	//bool started = false;
+
+	std::list<Modificator*> preceeders; //must be ordered container
+
+	mutable boost::shared_mutex mx;
+	using Lock = boost::unique_lock<boost::shared_mutex>;
+
+	void dump();
+};
+
+VCMI_LIB_NAMESPACE_END

+ 9 - 44
lib/rmg/Zone.cpp

@@ -24,7 +24,8 @@ std::function<bool(const int3 &)> AREA_NO_FILTER = [](const int3 & t)
 };
 
 Zone::Zone(RmgMap & map, CMapGenerator & generator)
-	: townType(ETownType::NEUTRAL)
+	: finished(false)
+	, townType(ETownType::NEUTRAL)
 	, terrainType(ETerrainId::GRASS)
 	, map(map)
 	, generator(generator)
@@ -152,12 +153,12 @@ rmg::Path Zone::searchPath(const rmg::Area & src, bool onlyStraight, const std::
 			return 2;
 		return 3;
 	};
-	
+
 	auto area = (dAreaPossible + dAreaFree).getSubarea(areafilter);
 	rmg::Path freePath(area);
 	rmg::Path resultPath(area);
 	freePath.connect(dAreaFree);
-	
+
 	//connect to all pieces
 	auto goals = connectedAreas(src, onlyStraight);
 	for(auto & goal : goals)
@@ -165,42 +166,23 @@ rmg::Path Zone::searchPath(const rmg::Area & src, bool onlyStraight, const std::
 		auto path = freePath.search(goal, onlyStraight, movementCost);
 		if(path.getPathArea().empty())
 			return rmg::Path::invalid();
-		
+
 		freePath.connect(path.getPathArea());
 		resultPath.connect(path.getPathArea());
 	}
-	
+
 	return resultPath;
 }
 
 rmg::Path Zone::searchPath(const int3 & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter) const
 ///connect current tile to any other free tile within zone
 {
-	return searchPath(rmg::Area({src}), onlyStraight, areafilter);
-}
-
-TRMGJob Zone::getNextJob()
-{
-	for (auto& modificator : modificators)
-	{
-		if (modificator->hasJobs())
-		{
-			return modificator->getNextJob();
-		}
-	}
-	return TRMGJob();
+	return searchPath(rmg::Area({ src }), onlyStraight, areafilter);
 }
 
-bool Zone::hasJobs()
+TModificators Zone::getModificators()
 {
-	for (auto& modificator : modificators)
-	{
-		if (modificator->hasJobs())
-		{
-			return true;
-		}
-	}
-	return false;
+	return modificators;
 }
 
 void Zone::connectPath(const rmg::Path & path)
@@ -303,21 +285,4 @@ void Zone::initModificators()
 	logGlobal->info("Zone %d modificators initialized", getId());
 }
 
-void Zone::processModificators()
-{
-	for(auto & modificator : modificators)
-	{
-		try
-		{
-			modificator->run();
-		}
-		catch (const rmgException & e)
-		{
-			logGlobal->info("Zone %d, modificator %s - FAILED: %s", getId(), e.what());
-			throw e;
-		}
-	}
-	logGlobal->info("Zone %d filled successfully", getId());
-}
-
 VCMI_LIB_NAMESPACE_END

+ 7 - 5
lib/rmg/Zone.h

@@ -31,7 +31,9 @@ class Modificator;
 
 extern std::function<bool(const int3 &)> AREA_NO_FILTER;
 
-class Zone : public rmg::ZoneOptions, public IJobProvider
+typedef std::list<std::shared_ptr<Modificator>> TModificators;
+
+class Zone : public rmg::ZoneOptions
 {
 public:
 	Zone(RmgMap & map, CMapGenerator & generator);
@@ -64,8 +66,8 @@ public:
 	rmg::Path searchPath(const rmg::Area & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter = AREA_NO_FILTER) const;
 	rmg::Path searchPath(const int3 & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter = AREA_NO_FILTER) const;
 
-	TRMGJob getNextJob() override;
-	bool hasJobs() override;
+	//std::vector<std:> & getAllJobs() const;
+	TModificators getModificators();
 
 	template<class T>
 	T* getModificator()
@@ -85,12 +87,12 @@ public:
 	}
 	
 	void initModificators();
-	void processModificators();
 	
 protected:
 	CMapGenerator & generator;
 	RmgMap & map;
-	std::list<std::unique_ptr<Modificator>> modificators;
+	TModificators modificators;
+	bool finished;
 	
 	//placement info
 	int3 pos;