Ive been playing around with multithreaded game engine architecture and thread pools lately. Now ive implemented a basic Kernel
class. This class has an std::vector<std::thread>
, which represents the threadpool. Now, the following function is run by a single thread in the pool:
while(m_IsRunning)
{
std::unique_lock<std::mutex> kernelstateLocker(m_KernelStateMutex);
m_KernelStateCond.wait(kernelstateLocker);
if(m_KernelState == KernelState::KernelShutdown || m_KernelState == KernelState::KernelTerminate)
{
kernelstateLocker.unlock();
//std::cout << "Worker #" << _workerID << std::endl console log here
break;
}
else if(m_KernelState == KernelState::KernelWorkAvailable)
{
...
}
As you can see, a thread wakes up if the KernelState
variable changes. This can happen when a Task is added to the queue, or when the Kernel shuts down. The kernel shutdown condition variable gets called by the main program thread, via m_KernelStateCond.notify_all()
. However, as i added cout
's as seen in the comment, only one of at times up to 8 worker threads would print its name and id, indicating that the others never terminated. Does anybody know why this is, and how i can terminate all of the threads in my pool? In case it matters, my platform is TDM-GCC-64 5.1 on Windows 10 64-bit.
Update:
As per comment request and SO rules, here is the code that calls the condition variable.
std::unique_lock<std::mutex> shutdownLocker(m_IsRunningMutex);
m_ShutdownCond.wait(shutdownLocker, [this](){ return !m_IsRunning; });
if(!m_IsRunning)
{
shutdownLocker.unlock();
m_KernelStateMutex.lock();
m_KernelState = KernelState::KernelShutdown;
m_KernelStateMutex.unlock();
m_KernelStateCond.notify_all();
}
Im pretty sure this part of my code is working, since at least one of the thread workers actually closes. And for completeness, here is my full Kernel
class:
class Kernel : public Singleton<Kernel>
{
public:
void boot(unsigned int _workerCount);
void run();
void shutdown();
void addTask(std::shared_ptr<Task> _task);
private:
friend class Singleton<Kernel>;
Kernel();
~Kernel();
bool m_IsRunning;
KernelState m_KernelState;
std::vector<std::thread> m_Workers;
std::queue<std::shared_ptr<Task>> m_Tasks;
std::vector<std::shared_ptr<Task>> m_LoopTasks;
std::condition_variable m_KernelStateCond;
std::mutex m_KernelStateMutex;
void workTask(unsigned int _workerID);
};