C++条件变量学习
1、概述
你知道条件变量"虚假唤醒"问题么,下面代码有问题么
void CFileTaskThread::Run()
{while (!m_bStop){CFileItemRequest* pFileItem;{std::unique_lock<std::mutex> guard(m_mtItems);if (m_Filelist.empty()){if (m_bStop)return;// 等待条件满足m_cvItems.wait(guard);}pFileItem = m_Filelist.front();m_Filelist.pop_front();}// do something}
}
2、分析
上述代码,当列表 m_Filelist
为空时,调用 wait
进入阻塞状态,等待条件变量被触发。一旦其他线程通过 notify_one()
或 notify_all()
发出通知,wait
函数解除阻塞并返回。随后,从列表头部取出一个任务继续执行。
虚假唤醒:
一个线程正在调用std::condition_variable::wait()等待,没有任何线程调用notify_one()或notify_all情况下,wait函数解除阻塞并返回了。
如果是虚假唤醒场景,那么上述代码就会有问题,当wait函数返回后,准备从列表头部取出一个任务,而此时列表是空的,程序就崩溃了。
正确写法
循环中使用 while
检查条件可以防止虚假唤醒。即使线程被意外唤醒,while
会再次检查列表是否为空。如果列表仍然为空,线程会继续调用 wait
并保持等待状态,直到条件真正满足。
void CFileTaskThread::Run()
{while (!m_bStop){CFileItemRequest* pFileItem;{std::unique_lock<std::mutex> guard(m_mtItems);// 注意注意,这里用whilewhile (m_Filelist.empty()){if (m_bStop)return;// 等待条件满足m_cvItems.wait(guard);}pFileItem = m_Filelist.front();m_Filelist.pop_front();}// do something}
}
学习链接:https://github.com/0voice