mason/src/taskmanager.cpp

121 lines
2.6 KiB
C++
Raw Normal View History

2023-09-20 00:25:38 +00:00
#include "taskmanager.h"
TaskManager::TaskManager(const std::shared_ptr<Logger>& logger) :
Loggable(logger),
2023-09-20 00:25:38 +00:00
running(false),
stopping(false),
maxThreads(std::thread::hardware_concurrency()),
activeThreads(0),
2023-09-25 20:15:24 +00:00
tasks(),
2023-09-20 19:45:22 +00:00
mutex(),
2023-09-20 00:25:38 +00:00
loopConditional(),
waitConditional(),
threads()
{
threads.reserve(maxThreads);
}
TaskManager::~TaskManager() {
stop();
}
2023-09-20 19:45:22 +00:00
void TaskManager::queue(const Job& job) {
std::unique_lock lock(mutex);
2023-09-25 20:15:24 +00:00
tasks.emplace(job, std::nullopt);
2023-09-20 19:45:22 +00:00
lock.unlock();
loopConditional.notify_one();
}
2023-09-25 20:15:24 +00:00
void TaskManager::queue(const Job& job, const Result& result) {
std::unique_lock lock(mutex);
tasks.emplace(job, result);
lock.unlock();
loopConditional.notify_one();
}
2023-09-20 00:25:38 +00:00
void TaskManager::start() {
2023-09-20 19:45:22 +00:00
std::lock_guard lock(mutex);
2023-09-20 00:25:38 +00:00
if (running)
return;
debug("Starting " + std::to_string(maxThreads) + " threads");
2023-09-20 00:25:38 +00:00
for (uint32_t i = 0; i < maxThreads; ++i)
threads.emplace_back(&TaskManager::loop, this);
running = true;
}
void TaskManager::stop() {
2023-09-20 19:45:22 +00:00
std::unique_lock lock(mutex);
2023-09-20 00:25:38 +00:00
if (!running)
return;
debug("Stopping task manager");
2023-09-20 00:25:38 +00:00
stopping = true;
lock.unlock();
loopConditional.notify_all();
for (std::thread& thread : threads)
thread.join();
threads.clear();
running = false;
2023-09-20 00:25:38 +00:00
}
void TaskManager::loop() {
//debug("Thread " + std::to_string(std::this_thread::get_id()) + " entered the loop");
debug("Thread entered the loop");
2023-09-20 00:25:38 +00:00
while (true) {
2023-09-25 20:15:24 +00:00
Task task;
2023-09-20 19:45:22 +00:00
std::unique_lock lock(mutex);
2023-09-25 20:15:24 +00:00
while (!stopping && tasks.empty())
2023-09-20 00:25:38 +00:00
loopConditional.wait(lock);
if (stopping)
break;
2023-09-20 00:25:38 +00:00
++activeThreads;
2023-09-25 20:15:24 +00:00
task = tasks.front();
tasks.pop();
//debug("Thread took a task");
2023-09-20 00:25:38 +00:00
lock.unlock();
2023-09-25 20:15:24 +00:00
executeTask(task);
2023-09-20 00:25:38 +00:00
lock.lock();
--activeThreads;
lock.unlock();
waitConditional.notify_all();
}
debug("Thread left the loop");
2023-09-20 00:25:38 +00:00
}
2023-09-25 20:15:24 +00:00
void TaskManager::executeTask(const Task& task) const {
try {
task.first();
} catch (const std::exception& e) {
if (task.second.has_value())
task.second.value()(&e);
return;
2023-09-25 20:15:24 +00:00
}
try {
if (task.second.has_value())
task.second.value()(std::nullopt);
} catch (...) {}
}
2023-09-20 19:45:22 +00:00
bool TaskManager::busy() const {
std::lock_guard lock(mutex);
2023-09-20 00:25:38 +00:00
return activeThreads == 0;
}
2023-09-20 19:45:22 +00:00
void TaskManager::wait() const {
std::unique_lock lock(mutex);
while (activeThreads != 0 || !tasks.empty())
2023-09-20 00:25:38 +00:00
waitConditional.wait(lock);
}