这是我的代码:
类
class carl{
public:
int x = 0;
std::mutex _mu;
std::condition_variable cond;
bool donecreating = false;
void createFood(){
if(x == 0){
std::unique_lock<mutex> locker(_mu);
x++;
std::cout<<"creating food.."<<std::endl;
cout<<"Food count: "<<x<<endl;
locker.unlock();
cond.notify_one(); //notify
std::this_thread::sleep_for(chrono::seconds(1)); //sleep
}
}
void eatFood(){
std::unique_lock<mutex> locker(_mu); //lock
std::cout<<"i am executing"<<std::endl; //notif
cond.wait(locker); //wait
x--; //process food
std::cout<<"eating food.."<<std::endl;
cout<<"Food left: "<<x<<endl;
locker.unlock();
}
};
功能又称线程
void create(carl& carl){
for(int i=0;i>-100;i--){ //create 100 times
carl.createFood();
}
carl.donecreating = true; //done creating 100 food
}
主要
int main(int argc, char** argv) {
carl c; //init object
std::thread t1(create,std::ref(c)); //init thread
while(c.donecreating != true){ //exit condition is if the class is done creating food 100 times
c.eatFood();
}
t1.join();
return 0;
}
输出:
i am executing
creating food...
Food count: 1
eating food..
Food left: 0
我正在尝试跟踪我的代码,这是我迄今为止的理解,我需要一些澄清
1。)编译时,主线程(消费者)比生产者线程更快,因此它首先被激活并被cond.wait(locker);
置于睡眠状态以防止它进食,因为还没有食物。但在cond.wait(locker);
之前有std::unique_lock<mutex> locker(_mu);
,是否会自动解锁,以便其他线程可以在等待时访问它?
2.。)如果createFood
首先被激活(因为线程是基于处理器的?它可能是对的吗?),如果有cond.notify_one();
,它将发送sleep
然后它只是继续创造一种食物然后mutex
。另一个线程将开始处理,因为cond.wait(locker);
将被解锁,然后它将到达sleep
但是已经有食物,所以spurious wake
赢得了我发现的解决方案的必要性是通过实施std::unique_lock<mutex> locker(_mu);
,是它的用途是什么?
3。)我仍然非常好奇disabled
,如果另一个线程到达那行代码并且它当前被锁定了会发生什么?它会忽略下面的每一行,只是继续前进,直到该代码块超出范围?还是它停在那条线上并等到它解锁?
答案 0 :(得分:2)
首先,您的代码具有数据竞争(因此未定义的行为),因为if(x == 0)
中的createFood()
访问x
未受保护。每次访问x
,包括读取和写入,都必须受到互斥锁的保护。
是否自动解锁,以便其他线程可以访问它 在等待的时候?
是的,wait()
在阻塞条件变量之前解锁互斥锁,然后在它返回之前再次锁定互斥锁。
另一个线程将开始处理,因为互斥锁将是 解锁然后它会到达
cond.wait(locker);
但是有食物 已经如此睡眠将不是我发现的解决方案 通过实施虚假唤醒,这是什么意思?
不,虚假的唤醒不是你可以控制的。您的代码有两个问题:
eatFood()
中的等待可以虚假地结束,在这种情况下实际上没有任何食物可以吃,但你也不处理这种情况。解决方案是在循环中运行wait
,直到有可用的食物。这相当于运行带有谓词的wait
版本:
while(x == 0) cond.wait(locker);
或
cond.wait(locker, [this](){ return x > 0; });
我仍然对
std::unique_lock<mutex> locker(_mu);
感到好奇 就像其他线程到达那行代码时真正发生的事情一样 它目前被锁定了吗?它是否会忽略下面的每一行和 继续前进,直到该代码块超出范围?或者它 在那条线上停下来等待它解锁?
后者。在该行之后,互斥锁被构造locker
的线程锁定。这意味着在必要时阻止和等待。