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
Post a Comment