c++ - std::unique_lock<mutex> 和 conditional_variable cond 的关系

标签 c++ multithreading c++11

这是我的代码:

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 , 这就是它的用途吗?

3.) 我还是很好奇 std::unique_lock<mutex> locker(_mu);就像如果另一个线程到达那行代码并且它当前被锁定会发生什么?它会忽略下面的每一行并继续前进直到该代码块超出范围吗?还是停在那条线上等待解锁?

最佳答案

首先,自 if(x == 0) 以来,您的代码存在数据竞争(因此存在未定义的行为)在createFood()访问 x不 protected 。每次访问 x ,读取和写入都必须受互斥锁保护。

is it automatically unlocked so that the other thread can access it while waiting?

是的,wait()在阻塞条件变量之前解锁互斥锁,然后在它返回之前再次锁定互斥锁。

The other thread will start processing because the mutex will be unlocked then it will reach cond.wait(locker); but there is a food already so sleep won't be necessary the solution that i found out is by implementing spurious wake, is that what it is for?

不,虚假唤醒不是您可以控制的。您的代码有两个问题:

  • 如您所见,它可能会错过通知。
  • 等待eatFood()可以虚假结束,在这种情况下实际上没有任何食物可吃,但您也不会处理这种情况。

解决方案是运行wait循环,直到有食物可用。这相当于运行 wait 的版本取一个谓词:

while(x == 0) cond.wait(locker); 

cond.wait(locker, [this](){ return x > 0; });

I'm still really curious about std::unique_lock<mutex> locker(_mu); like what really happens if the other thread reached that line of code and it's currently locked? does it ignore every line below that and just move on until that block of code gets out of scope? or does it stops on that line and wait until it gets unlocked?

后者。在该行之后,互斥体被构造locker的线程锁定。 .这意味着在必要时进行阻塞和等待。

关于c++ - std::unique_lock<mutex> 和 conditional_variable cond 的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30824578/

相关文章:

c++在派生函数中启动OMP线程

c++ - 从文本文件读取结构

c++ - constexpr 替换数学常量,如 M_PI

c++ std::enable_if 约束变体和问题

c++ - C++:使用参数包显式调用函数重载

java - 类似于 Java 中的 Rendez-Vous,但不起作用

c++ - 析构函数隐藏在这段代码的什么地方?

c++ - 为什么不允许将 this 的指针用作函数的默认参数?

c++ - 对 `RPositionServer::RPositionServer()` 的 undefined reference

ios - CoreData多线程_违规调试