2025-09-26 13:17:02 +02:00
|
|
|
#include "thread_pool.hpp"
|
|
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
#define DEBUG false
|
|
|
|
|
#if DEBUG
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-09-26 13:17:02 +02:00
|
|
|
ThreadPool::ThreadPool(size_t num_threads) {
|
2025-09-30 16:20:03 +02:00
|
|
|
mutexes = new std::mutex[num_threads];
|
|
|
|
|
tasks = new std::queue<std::function<void()>>[num_threads];
|
|
|
|
|
cvs = new std::condition_variable[num_threads];
|
2025-09-26 13:17:02 +02:00
|
|
|
for (auto i = 0; i < num_threads; ++i) {
|
|
|
|
|
threads.emplace_back([this, i] {
|
2025-09-30 16:20:03 +02:00
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Thread " << i << " started" << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-09-26 13:17:02 +02:00
|
|
|
while (true) {
|
|
|
|
|
std::function<void()> task;
|
2025-09-30 16:20:03 +02:00
|
|
|
{
|
|
|
|
|
std::unique_lock<std::mutex> lock(mutexes[i]);
|
2025-09-26 13:17:02 +02:00
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Thread " << i << " waiting for task. Queue " << tasks[i].size() << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
cvs[i].wait(lock, [i,this] { return !tasks[i].empty() || stop; });
|
2025-09-26 13:17:02 +02:00
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
if (tasks[i].empty() && stop) {
|
|
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Thread " << i << " finished. Stop " << stop << ", queue size " << tasks[i].size() << std::endl;
|
|
|
|
|
#endif
|
2025-09-26 13:17:02 +02:00
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2025-09-26 13:17:02 +02:00
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
if (!tasks[i].empty()) {
|
|
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Thread " << i << " task acquired" << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
task = std::move(tasks[i].front());
|
|
|
|
|
tasks[i].pop();
|
|
|
|
|
} else {
|
|
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Thread " << i << " spontaneous wakeup. Continueing" << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-09-26 13:17:02 +02:00
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
}
|
|
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Thread " << i << " executing task" << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
active_workers.fetch_add(1);
|
2025-09-26 13:17:02 +02:00
|
|
|
task();
|
2025-09-30 16:20:03 +02:00
|
|
|
active_workers.fetch_sub(1);
|
|
|
|
|
remaining_tasks.fetch_sub(1);
|
|
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Remaining tasks " << remaining_tasks.load() << std::endl;
|
|
|
|
|
#endif
|
2025-09-26 13:17:02 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThreadPool::~ThreadPool() {
|
|
|
|
|
stop = true;
|
2025-09-30 16:20:03 +02:00
|
|
|
for (auto i = 0; i < threads.size(); ++i) {
|
|
|
|
|
cvs[i].notify_one();
|
|
|
|
|
}
|
2025-09-26 13:17:02 +02:00
|
|
|
|
|
|
|
|
for (auto& thread : threads) {
|
|
|
|
|
thread.join();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ThreadPool::add(std::function<void()> task) {
|
2025-09-30 16:20:03 +02:00
|
|
|
size_t idx = current.fetch_add(1) % threads.size();
|
|
|
|
|
{
|
|
|
|
|
std::unique_lock<std::mutex> lock(mutexes[idx]);
|
|
|
|
|
tasks[idx].emplace(std::move(task));
|
|
|
|
|
}
|
|
|
|
|
remaining_tasks.fetch_add(1);
|
|
|
|
|
#if DEBUG
|
|
|
|
|
std::cerr << "Adding task to thread " << current << ". Total remaining " << remaining_tasks.load() << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
cvs[idx].notify_one();
|
2025-09-26 13:17:02 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-30 16:20:03 +02:00
|
|
|
uint32_t ThreadPool::size() {
|
|
|
|
|
return remaining_tasks.load();
|
|
|
|
|
}
|
2025-09-26 13:17:02 +02:00
|
|
|
bool ThreadPool::isWorking() {
|
2025-09-30 16:20:03 +02:00
|
|
|
return active_workers.load() > 0;
|
2025-09-26 13:17:02 +02:00
|
|
|
}
|