C++ 多个条件变量:线程不同步问题
我有一个线程正在做“工作”,当条件变量通知它时,它应该报告进度。此线程正在等待条件变量 另一个线程等待x毫秒,然后通知条件变量继续 我有5个条件变量(这是学校的一个练习),一旦每个变量都得到通知,就应该报告工作进度: 我遇到的问题是,线程2(应该通知线程1的线程)通过所有5个检查点,最后只通知一次。因此,我最终会遇到这样一种情况,即最终进度为20%,线程1正在等待另一个通知,而线程2已经完成了所有通知 我的逻辑实现中的缺陷在哪里? 代码如下:C++ 多个条件变量:线程不同步问题,c++,multithreading,C++,Multithreading,我有一个线程正在做“工作”,当条件变量通知它时,它应该报告进度。此线程正在等待条件变量 另一个线程等待x毫秒,然后通知条件变量继续 我有5个条件变量(这是学校的一个练习),一旦每个变量都得到通知,就应该报告工作进度: 我遇到的问题是,线程2(应该通知线程1的线程)通过所有5个检查点,最后只通知一次。因此,我最终会遇到这样一种情况,即最终进度为20%,线程1正在等待另一个通知,而线程2已经完成了所有通知 我的逻辑实现中的缺陷在哪里? 代码如下: #include <condition_var
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
class Program {
public:
Program() {
m_progress = 0;
m_check = false;
}
bool isWorkReady() { return m_check; }
void loopWork() {
cout << "Working ... : " << endl;
work(m_cv1);
work(m_cv2);
work(m_cv3);
work(m_cv4);
work(m_cv5);
cout << "\nFinished!" << endl;
}
void work(condition_variable &cv) {
unique_lock<mutex> mlock(m_mutex);
cv.wait(mlock, bind(&Program::isWorkReady, this));
m_progress++;
cout << " ... " << m_progress * 20 << "%" << endl;
m_check = false;
}
void checkPoint(condition_variable &cv) {
lock_guard<mutex> guard(m_mutex);
cout << " < Checking >" << m_progress << endl;
this_thread::sleep_for(chrono::milliseconds(300));
m_check = true;
cv.notify_one();
}
void loopCheckPoints() {
checkPoint(m_cv1);
checkPoint(m_cv2);
checkPoint(m_cv3);
checkPoint(m_cv4);
checkPoint(m_cv5);
}
private:
mutex m_mutex;
condition_variable m_cv1, m_cv2, m_cv3, m_cv4, m_cv5;
int m_progress;
bool m_check;
};
int main() {
Program program;
thread t1(&Program::loopWork, &program);
thread t2(&Program::loopCheckPoints, &program);
t1.join();
t2.join();
return 0;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
班级计划{
公众:
程序(){
m_进度=0;
m_check=假;
}
bool isWorkReady(){返回m_check;}
无效循环工作(){
库特
我的逻辑实现中的缺陷在哪里
cv.notify_one
不要求cv.wait(mlock,bind(&Program::isWorkReady,this));
之后的代码立即继续,因此在cv.wait
之后的代码继续之前执行多个检查点是完全有效的
但是在您执行cv.wait
之后,您将m\u check=false;
设置为false
,因此如果没有进一步的checkPoint
执行剩余,那么将设置m\u check=true;
,您的工作
功能将被卡住
您可以考虑将其设置为计数器,而不是mu check
作为bool
,它在checkPoint
中递增,在work
中递减loopCheckPoints()
线程持有锁一段时间,设置mu-check
然后释放锁并立即继续再次抓取锁。loopWork()
线程可能没有在这段时间内醒来以对mu-check
更改作出反应
- 不要长时间持有锁。要尽快。如果不添加
sleep
s程序就无法运行,那么您就有问题了
解决此问题的一种方法是检查工作人员是否已将m_check
设置回false
:
void work(condition_variable& cv) {
{ // lock scope
unique_lock<mutex> mlock(m_mutex);
cv.wait(mlock, [this] { return m_check; });
m_progress++;
cout << " ... " << m_progress * 20 << "%" << endl;
m_check = false;
}
// there's no need to hold the lock when notifying
cv.notify_one(); // notify that we set it back to false
}
无效工作(条件变量和cv){
{//锁定范围
唯一锁定锁定(m_互斥);
等待(mlock,[this]{返回m_check;});
m_progress++;
cout.非常感谢!我对条件变量有了更好的理解,而且我以前从未使用过额外的花括号来创建作用域!这似乎很好,至少在这种情况下是这样。@Jeekim,不客气!我很少使用这样的花括号,通常创建一个函数来提供作用域-但是在处理ve时我倾向于认为它更容易阅读、理解和维护。线程足够复杂:-)谢谢你的回复。我现在明白了为什么它不能像我想要的那样工作。我最终实现了Ted建议的解决方案,它感觉更直观-使用m_检查在线程之间切换
void checkPoint(condition_variable& cv) {
// if you are going to sleep, do it without holding the lock
// this_thread::sleep_for(chrono::milliseconds(300));
{ // lock scope
lock_guard<mutex> guard(m_mutex);
cout << "<Checking> " << m_progress << endl;
m_check = true;
}
cv.notify_one(); // no need to hold the lock here
{
// Check that m_check is set back to false
unique_lock<mutex> mlock(m_mutex);
cv.wait(mlock, [this] { return not m_check; });
}
}