Skip to content

Commit

Permalink
#5107: Add option to ThreadedDefLoader to invoke a function when the …
Browse files Browse the repository at this point in the history
…actual worker thread is done (or as good as done).
  • Loading branch information
codereader committed Jun 25, 2021
1 parent fd30a03 commit 3d9251d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
39 changes: 38 additions & 1 deletion libs/ThreadedDefLoader.h
Expand Up @@ -23,15 +23,22 @@ class ThreadedDefLoader
typedef std::function<ReturnType()> LoadFunction;

LoadFunction _loadFunc;
std::function<void()> _finishedFunc;

std::shared_future<ReturnType> _result;
std::shared_future<void> _finisher;
std::mutex _mutex;

bool _loadingStarted;

public:
ThreadedDefLoader(const LoadFunction& loadFunc) :
ThreadedDefLoader(loadFunc, std::function<void()>())
{}

ThreadedDefLoader(const LoadFunction& loadFunc, const std::function<void()>& finishedFunc) :
_loadFunc(loadFunc),
_finishedFunc(finishedFunc),
_loadingStarted(false)
{}

Expand Down Expand Up @@ -84,19 +91,49 @@ class ThreadedDefLoader
_result.get();
}

if (_finisher.valid())
{
_finisher.get();
}

_result = std::shared_future<ReturnType>();
_finisher = std::shared_future<void>();
}
}

private:
struct FinishFunctionCaller
{
std::function<void()> _function;
std::shared_future<void>& _targetFuture;

FinishFunctionCaller(const std::function<void()>& function, std::shared_future<void>& targetFuture) :
_function(function),
_targetFuture(targetFuture)
{}

~FinishFunctionCaller()
{
if (_function)
{
_targetFuture = std::async(std::launch::async, _function);
}
}
};

void ensureLoaderStarted()
{
std::lock_guard<std::mutex> lock(_mutex);

if (!_loadingStarted)
{
_loadingStarted = true;
_result = std::async(std::launch::async, _loadFunc);
_result = std::async(std::launch::async, [&]()
{
// When going out of scope, this instance invokes the finished callback in a separate thread
FinishFunctionCaller finisher(_finishedFunc, _finisher);
return _loadFunc();
});
}
}
};
Expand Down
18 changes: 16 additions & 2 deletions radiantcore/eclass/EClassManager.cpp
Expand Up @@ -24,7 +24,8 @@ namespace eclass {
// Constructor
EClassManager::EClassManager() :
_realised(false),
_defLoader(std::bind(&EClassManager::loadDefAndResolveInheritance, this)),
_defLoader(std::bind(&EClassManager::loadDefAndResolveInheritance, this),
std::bind(&EClassManager::onDefLoadingCompleted, this)),
_curParseStamp(0)
{}

Expand Down Expand Up @@ -192,7 +193,7 @@ void EClassManager::loadDefAndResolveInheritance()
resolveInheritance();
applyColours();

_defsLoadedSignal.emit();
// The loaded signal will be invoked in the onDefLoadingCompleted() method
}

void EClassManager::applyColours()
Expand Down Expand Up @@ -348,6 +349,7 @@ void EClassManager::shutdownModule()

// Don't notify anyone anymore
_defsReloadedSignal.clear();
_changeNotificationQueue.clear();

// Clear member structures
_entityClasses.clear();
Expand Down Expand Up @@ -511,6 +513,18 @@ void EClassManager::parseFile(const vfs::FileInfo& fileInfo)
}
}

void EClassManager::onDefLoadingCompleted()
{
for (auto& eclass : _changeNotificationQueue)
{
eclass.get().emitChangedSignal();
}

_changeNotificationQueue.clear();

_defsLoadedSignal.emit();
}

// Static module instance
module::StaticModule<EClassManager> eclassModule;

Expand Down
3 changes: 3 additions & 0 deletions radiantcore/eclass/EClassManager.h
Expand Up @@ -104,6 +104,9 @@ class EClassManager :
// Worker function usually done in a separate thread
void loadDefAndResolveInheritance();

// Invokes the change notifications that have been buffered during parsing
void onDefLoadingCompleted();

// Applies possible colour overrides to all affected eclasses
void applyColours();

Expand Down

0 comments on commit 3d9251d

Please sign in to comment.