How to use the variable_condition to really wait_ no longer for a specific duration

As it turns out , condition_variable::wait_for really needs to be called condition_variable::wait_for_or_possibly_indefinitely_longer_than , because it needs to re-lock the lock before it really runs out of time and returns.

See this program for a demonstration.

Is there a way to express: “Listen, I really only have two seconds. If myPredicate() is still false at this time and / or the lock is still locked, I don't care, just go ahead and give me a way to detect this.”

Something like:

 bool myPredicate(); auto sec = std::chrono::seconds(1); bool pred; std::condition_variable::cv_status timedOut; std::tie( pred, timedOut ) = cv.really_wait_for_no_longer_than( lck, 2*sec, myPredicate ); if( lck.owns_lock() ) { // Can use mutexed resource. // ... lck.unlock(); } else { // Cannot use mutexed resource. Deal with it. }; 
+8
c ++ multithreading c ++ 11 condition-variable
source share
3 answers

I think you are using condition_variable lock incorrectly. This is only to protect the condition, and not to protect the laborious work.

Your example can be easily eliminated by dividing mutex into two — one for the critical section and one for protecting modifications to the ready condition. Here is the edited snippet:

 typedef std::unique_lock<std::mutex> lock_type; auto sec = std::chrono::seconds(1); std::mutex mtx_work; std::mutex mtx_ready; std::condition_variable cv; bool ready = false; void task1() { log("Starting task 1. Waiting on cv for 2 secs."); lock_type lck(mtx_ready); bool done = cv.wait_for(lck, 2*sec, []{log("Checking condition..."); return ready;}); std::stringstream ss; ss << "Task 1 finished, done==" << (done?"true":"false") << ", " << (lck.owns_lock()?"lock owned":"lock not owned"); log(ss.str()); } void task2() { // Allow task1 to go first std::this_thread::sleep_for(1*sec); log("Starting task 2. Locking and sleeping 2 secs."); lock_type lck1(mtx_work); std::this_thread::sleep_for(2*sec); lock_type lck2(mtx_ready); ready = true; // This happens around 3s into the program log("OK, task 2 unlocking..."); lck2.unlock(); cv.notify_one(); } 

Exit:

 @2 ms: Starting task 1. Waiting on cv for 2 secs. @2 ms: Checking condition... @1002 ms: Starting task 2. Locking and sleeping 2 secs. @2002 ms: Checking condition... @2002 ms: Task 1 finished, done==false, lock owned @3002 ms: OK, task 2 unlocking... 
+5
source share

Is there a way to express: “Listen, I really only have two seconds. MyPredicate () is still false at this time and / or the lock is still locked, I don’t care, just go on no matter ...”

Yes, there is a way, but, unfortunately, in the case of wait_for it must be manual. wait_for waits indefinitely due to Spurious Wakeup . Imagine your loop as follows:

 while(!myPredicate()) cv.wait_for(lock, std::chrono::duration::seconds(2); 

Fake awakening can happen at any time on an arbitrary platform. Imagine that in your case this happens within 200 ms. In this regard, without any external notification of wait_for() , awakening and checking for myPredicate() in the loop condition will occur.

As expected, the condition will be false, so the loop will be true, and again it will execute cv.wait_for(..) with a fresh 2 seconds. So it will work endlessly.

Either you control this update duration yourself, or use wait_until() , which is ultimately called in wait_for() .

0
source share

Actually, condition_variable::wait_for does exactly what you want. The problem with your example is that you blocked the 2-second sleep with the assignment ready = true , which makes it impossible for the condition variable to even evaluate the predicate until the deadline is reached.

Put this line std::this_thread::sleep_for(2*sec); outside the castle and see for yourself.

0
source share

All Articles