std :: unique_lock <mutex>和conditional_variable cond

时间:2015-06-13 23:30:42

标签: 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赢得了我发现的解决方案的必要性是通过实施std::unique_lock<mutex> locker(_mu);,是它的用途是什么?

3。)我仍然非常好奇disabled,如果另一个线程到达那行代码并且它当前被锁定了会发生什么?它会忽略下面的每一行,只是继续前进,直到该代码块超出范围?还是它停在那条线上并等到它解锁?

1 个答案:

答案 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的线程锁定。这意味着在必要时阻止和等待。