2023-09-20 00:25:38 +00:00
|
|
|
#include "taskmanager.h"
|
|
|
|
|
|
|
|
TaskManager::TaskManager() :
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
stopping = true;
|
|
|
|
lock.unlock();
|
|
|
|
|
|
|
|
loopConditional.notify_all();
|
|
|
|
for (std::thread& thread : threads)
|
|
|
|
thread.join();
|
|
|
|
|
|
|
|
threads.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TaskManager::loop() {
|
|
|
|
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)
|
|
|
|
return;
|
|
|
|
|
|
|
|
++activeThreads;
|
2023-09-25 20:15:24 +00:00
|
|
|
task = tasks.front();
|
|
|
|
tasks.pop();
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2023-09-20 00:25:38 +00:00
|
|
|
while (activeThreads != 0)
|
|
|
|
waitConditional.wait(lock);
|
|
|
|
}
|