ThreadPool onJobFailed onComplete callbacks
This commit is contained in:
@@ -9,7 +9,7 @@ using namespace debug;
|
|||||||
std::ofstream Logger::file;
|
std::ofstream Logger::file;
|
||||||
std::mutex Logger::mutex;
|
std::mutex Logger::mutex;
|
||||||
std::string Logger::utcOffset = "";
|
std::string Logger::utcOffset = "";
|
||||||
unsigned Logger::moduleLen = 16;
|
unsigned Logger::moduleLen = 20;
|
||||||
|
|
||||||
LogMessage::~LogMessage() {
|
LogMessage::~LogMessage() {
|
||||||
logger->log(level, ss.str());
|
logger->log(level, ss.str());
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ ChunksRenderer::ChunksRenderer(
|
|||||||
const EngineSettings& settings
|
const EngineSettings& settings
|
||||||
) : level(level),
|
) : level(level),
|
||||||
threadPool(
|
threadPool(
|
||||||
|
"chunks-render-pool",
|
||||||
[=](){return std::make_shared<RendererWorker>(level, cache, settings);},
|
[=](){return std::make_shared<RendererWorker>(level, cache, settings);},
|
||||||
[=](RendererResult& mesh){
|
[=](RendererResult& mesh){
|
||||||
meshes[mesh.key] = std::shared_ptr<Mesh>(mesh.renderer->createMesh());
|
meshes[mesh.key].reset(mesh.renderer->createMesh());
|
||||||
inwork.erase(mesh.key);
|
inwork.erase(mesh.key);
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
|||||||
+54
-15
@@ -2,11 +2,14 @@
|
|||||||
#define UTIL_THREAD_POOL_H_
|
#define UTIL_THREAD_POOL_H_
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <iostream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
|
||||||
#include "../delegates.h"
|
#include "../delegates.h"
|
||||||
|
#include "../debug/Logger.h"
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
@@ -28,15 +31,19 @@ public:
|
|||||||
|
|
||||||
template<class T, class R>
|
template<class T, class R>
|
||||||
class ThreadPool {
|
class ThreadPool {
|
||||||
|
debug::Logger logger;
|
||||||
std::queue<T> jobs;
|
std::queue<T> jobs;
|
||||||
std::queue<ThreadPoolResult<R>> results;
|
std::queue<ThreadPoolResult<R>> results;
|
||||||
|
std::mutex resultsMutex;
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
std::condition_variable jobsMutexCondition;
|
std::condition_variable jobsMutexCondition;
|
||||||
std::mutex jobsMutex;
|
std::mutex jobsMutex;
|
||||||
bool working = true;
|
|
||||||
std::vector<std::unique_lock<std::mutex>> workersBlocked;
|
std::vector<std::unique_lock<std::mutex>> workersBlocked;
|
||||||
consumer<R&> resultConsumer;
|
consumer<R&> resultConsumer;
|
||||||
std::mutex resultsMutex;
|
consumer<T&> onJobFailed = nullptr;
|
||||||
|
runnable onComplete = nullptr;
|
||||||
|
std::atomic<int> busyWorkers = 0;
|
||||||
|
bool working = true;
|
||||||
|
|
||||||
void threadLoop(int index, std::shared_ptr<Worker<T, R>> worker) {
|
void threadLoop(int index, std::shared_ptr<Worker<T, R>> worker) {
|
||||||
std::condition_variable variable;
|
std::condition_variable variable;
|
||||||
@@ -54,27 +61,37 @@ class ThreadPool {
|
|||||||
}
|
}
|
||||||
job = jobs.front();
|
job = jobs.front();
|
||||||
jobs.pop();
|
jobs.pop();
|
||||||
|
|
||||||
|
busyWorkers++;
|
||||||
}
|
}
|
||||||
R result = (*worker)(job);
|
try {
|
||||||
{
|
R result = (*worker)(job);
|
||||||
resultsMutex.lock();
|
{
|
||||||
results.push(ThreadPoolResult<R> {variable, index, locked, result});
|
std::lock_guard<std::mutex> lock(resultsMutex);
|
||||||
locked = true;
|
results.push(ThreadPoolResult<R> {variable, index, locked, result});
|
||||||
resultsMutex.unlock();
|
locked = true;
|
||||||
}
|
busyWorkers--;
|
||||||
{
|
}
|
||||||
std::unique_lock<std::mutex> lock(mutex);
|
{
|
||||||
variable.wait(lock, [&] {
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
return !working || !locked;
|
variable.wait(lock, [&] {
|
||||||
});
|
return !working || !locked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (std::exception& err) {
|
||||||
|
if (onJobFailed) {
|
||||||
|
onJobFailed(job);
|
||||||
|
}
|
||||||
|
logger.error() << "uncaught exception: " << err.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
ThreadPool(
|
ThreadPool(
|
||||||
|
std::string name,
|
||||||
supplier<std::shared_ptr<Worker<T, R>>> workersSupplier,
|
supplier<std::shared_ptr<Worker<T, R>>> workersSupplier,
|
||||||
consumer<R&> resultConsumer
|
consumer<R&> resultConsumer
|
||||||
) : resultConsumer(resultConsumer) {
|
) : logger(name), resultConsumer(resultConsumer) {
|
||||||
const uint num_threads = std::thread::hardware_concurrency();
|
const uint num_threads = std::thread::hardware_concurrency();
|
||||||
for (uint i = 0; i < num_threads; i++) {
|
for (uint i = 0; i < num_threads; i++) {
|
||||||
threads.emplace_back(&ThreadPool<T,R>::threadLoop, this, i, workersSupplier());
|
threads.emplace_back(&ThreadPool<T,R>::threadLoop, this, i, workersSupplier());
|
||||||
@@ -82,6 +99,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
~ThreadPool(){
|
~ThreadPool(){
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminate() {
|
||||||
|
if (!working) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(jobsMutex);
|
std::lock_guard<std::mutex> lock(jobsMutex);
|
||||||
working = false;
|
working = false;
|
||||||
@@ -113,6 +137,13 @@ public:
|
|||||||
entry.locked = false;
|
entry.locked = false;
|
||||||
entry.variable.notify_all();
|
entry.variable.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onComplete && busyWorkers == 0) {
|
||||||
|
std::lock_guard<std::mutex> lock(jobsMutex);
|
||||||
|
if (jobs.empty()) {
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enqueueJob(T job) {
|
void enqueueJob(T job) {
|
||||||
@@ -122,6 +153,14 @@ public:
|
|||||||
}
|
}
|
||||||
jobsMutexCondition.notify_one();
|
jobsMutexCondition.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setOnJobFailed(consumer<T&> callback) {
|
||||||
|
this->onJobFailed = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOnComplete(runnable callback) {
|
||||||
|
this->onComplete = callback;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|||||||
Reference in New Issue
Block a user