[英](boost) overhead of a unique_lock when used with a conditional_variable
[英]Relationship of std::unique_lock<mutex> and conditional_variable cond
这是我的代码:
类
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);
防止因为没有食物而无法进食。 但在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
,这是为了什么?
3.)我仍然对std::unique_lock<mutex> locker(_mu);
很好奇std::unique_lock<mutex> locker(_mu);
例如,如果另一个线程到达该行代码并且当前处于锁定状态,该怎么办? 它会忽略下面的每一行,而是继续前进直到该代码块超出范围吗? 还是停在那条线上,等到解锁?
首先,由于createFood()
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);
很好奇std::unique_lock<mutex> locker(_mu);
例如,如果另一个线程到达该行代码并且当前处于锁定状态,该怎么办? 它会忽略下面的每一行,而是继续前进直到该代码块超出范围吗? 还是停在那条线上,等到解锁?
后者。 在该行之后,互斥锁被线程构造locker
。 这意味着需要阻塞并等待。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.