我最近一直在玩多线程游戏引擎架构和线程池。现在我已经实现了一个基本的Kernel
课程。该类有一个std::vector<std::thread>
,代表线程池。现在,以下函数由池中的单个线程运行:
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)
{
...
}
如您所见,如果KernelState
变量发生变化,则线程会被唤醒。将任务添加到队列或内核关闭时,可能会发生这种情况。内核关闭条件变量由主程序线程通过m_KernelStateCond.notify_all()
调用。但是,正如我在评论中看到的cout
一样,只有一个有时最多8个工作线程会打印其名称和ID,表明其他线程从未终止。有谁知道这是为什么,以及如何终止我池中的所有线程?如果重要,我的平台是Windows 10 64位上的TDM-GCC-64 5.1。
根据评论请求和SO规则,这里是调用条件变量的代码。
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();
}
我很确定我的代码中的这部分工作正常,因为至少有一个线程工作者实际关闭了。为了完整起见,这是我的完整Kernel
课程:
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);
};
答案 0 :(得分:0)
我想出了问题。我的线程池实现本身并不是问题,但它与内核关闭时仍有任务到达的事实有关。因此,一些工作线程永远不会关闭,因此内核卡住了。为任务添加约束解决了这一问题。