c++ - Relationship of std::unique_lock<mutex> and conditional_variable cond -


here code:

class

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 executing"<<std::endl;             //notif     cond.wait(locker);                                  //wait       x--;                                                //process food     std::cout<<"eating food.."<<std::endl;       cout<<"food left: "<<x<<endl;     locker.unlock();  }    }; 

function aka thread one

void create(carl& carl){ for(int i=0;i>-100;i--){        //create 100 times    carl.createfood();  }     carl.donecreating  = true;      //done creating 100 food  } 

main

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 if class done creating food 100 times  c.eatfood();                              }  t1.join();  return 0; } 

output:

i executing creating food... food count: 1 eating food.. food left: 0 

i trying trace code , here understanding far , need clarifications

1.) upon compile, main thread(consumer) faster producer thread fired first , put sleep cond.wait(locker); prevent eating because no food made yet. before cond.wait(locker); there std::unique_lock<mutex> locker(_mu);, automatically unlocked other thread can access while waiting?

2.) if ever createfood fired first(because threads processor based? it's possible right?), send cond.notify_one(); if there 1 , if not go on creating food , sleep. other thread start processing because mutex unlocked reach cond.wait(locker); there food sleep won't necessary solution found out implementing spurious wake, for?

3.) i'm still curious std::unique_lock<mutex> locker(_mu); happens if other thread reached line of code , it's locked? ignore every line below , move on until block of code gets out of scope? or stops on line , wait until gets unlocked?

to start with, code has data race (and hence undefined behavior) since if(x == 0) in createfood() accesses x unprotected. every access x, both reads , writes, must protected mutex.

is automatically unlocked other thread can access while waiting?

yes, wait() unlocks mutex before blocking on condition variable, , locks mutex again before returns.

the other thread start processing because mutex unlocked reach cond.wait(locker); there food sleep won't necessary solution found out implementing spurious wake, for?

no, spurious wakeup not have control over. code has 2 problems:

  • it can miss notification, observe.
  • the wait in eatfood() can end spuriously, in case there isn't food eat, don't handle case either.

the solution run wait in loop, until there food available. equivalent running version of wait taking predicate:

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

or

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

i'm still curious std::unique_lock<mutex> locker(_mu); happens if other thread reached line of code , it's locked? ignore every line below , move on until block of code gets out of scope? or stops on line , wait until gets unlocked?

the latter. after line, mutex locked thread constructing locker. means blocking , waiting if necessary.


Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -