1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Thread pool kinda works.

This commit is contained in:
Tomasz Zieliński 2023-05-07 07:48:12 +02:00
parent 3d25c2c6dc
commit a58094aefe
6 changed files with 287 additions and 88 deletions

View File

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

View File

@ -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
lib/rmg/Modificator.cpp Normal file
View File

@ -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
lib/rmg/Modificator.h Normal file
View File

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

View File

@ -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);
return searchPath(rmg::Area({ src }), onlyStraight, areafilter);
}
TRMGJob Zone::getNextJob()
TModificators Zone::getModificators()
{
for (auto& modificator : modificators)
{
if (modificator->hasJobs())
{
return modificator->getNextJob();
}
}
return TRMGJob();
}
bool Zone::hasJobs()
{
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

View File

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