I have written a mathy simulation and introduced parallel computing using the available cpu cores - based on a simple thread pool written in C++/11.
At the very start it seemed to work, but then it starts to freeze reproducable after some frames - but sometimes it works just fine.
But i have absolutly no clue why it wont work... Can someone can look into that? Its not that much code.
I looking at the code since hours and cannot figure out what is wrong...
Here is the code:
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <deque>
#include <atomic>
struct ThreadPoolTask {
size_t startIndex;
size_t endIndex;
float deltaTime;
uint8_t padding0[4];
std::function<void(const size_t, const size_t, const float)> func;
};
struct ThreadPool {
std::atomic<bool> stopped;
std::vector<std::thread> threads;
std::atomic<int> pendingCount;
std::deque<ThreadPoolTask> queue;
std::mutex queueMutex;
std::mutex completeMutex;
std::condition_variable queueSignal;
std::condition_variable completeSignal;
ThreadPool(const size_t threadCount = std::thread::hardware_concurrency());
~ThreadPool();
void AddTask(const ThreadPoolTask &task);
void WaitUntilDone();
void WorkerThreadProc();
void CreateTasks(const size_t itemCount, const std::function<void(const size_t, const size_t, const float)> &function, const float deltaTime);
};
ThreadPool::ThreadPool(const size_t threadCount) :
stopped(false),
pendingCount(0) {
for (size_t workerIndex = 0; workerIndex < threadCount; ++workerIndex) {
threads.push_back(std::thread(&ThreadPool::WorkerThreadProc, this));
}
}
ThreadPool::~ThreadPool() {
stopped = true;
queueSignal.notify_all();
for (size_t workerIndex = 0; workerIndex < threads.size(); ++workerIndex)
threads[workerIndex].join();
}
void ThreadPool::AddWork(const ThreadPoolTask &entry) {
{
std::unique_lock<std::mutex> lock(queueMutex);
queue.push_back(entry);
}
pendingCount++;
}
void ThreadPool::WaitUntilDone() {
queueSignal.notify_all();
std::unique_lock<std::mutex> lock(completeMutex);
while (pendingCount > 0) {
completeSignal.wait(lock);
}
}
void ThreadPool::WorkerThreadProc() {
ThreadPoolTask group;
while (!stopped) {
{
std::unique_lock<std::mutex> lock(queueMutex);
while (queue.empty()) {
queueSignal.wait(lock);
}
group = queue.front();
queue.pop_front();
}
group.func(group.startIndex, group.endIndex, group.deltaTime);
if (--pendingCount == 0) {
completeSignal.notify_one();
}
}
}
void ThreadPool::CreateTasks(const size_t itemCount, const std::function<void(const size_t, const size_t, const float)> &function, const float deltaTime) {
if (itemCount > 0) {
const size_t itemsPerTask = std::max((size_t)1, itemCount / threads.size());
ThreadPoolTask task = {};
task.func = function;
task.deltaTime = deltaTime;
for (size_t itemIndex = 0; itemIndex < itemCount; itemIndex += itemsPerTask) {
task.startIndex = itemIndex;
task.endIndex = std::min(itemIndex + itemsPerTask - 1, itemCount - 1);
AddTask(task);
}
}
}
void main() {
workerPool.CreateTasks(itemCount, [=](const size_t startIndex, const size_t endIndex, const float deltaTime) {
this->DoingSomeMathyWork(startIndex, endIndex, deltaTime);
}, deltaTime);
workerPool.WaitUntilDone();
}
↧