TICS Coding Standard Viewer 
TIOBE Software Quality Framework
Print-friendly version
©TIOBE Software www.tiobe.com
 
C++ Coding Standard
Search

Rule:  CFL#026Checked automatically with code checker

Synopsis:Use conditions to avoid spurious wakes
Language:C++
Severity Level:3
Category:Control Flow


Description:

A spurious wakeup happens when a thread wakes up from waiting on a condition variable that is been signaled, only to discover that the condition it was waiting for isn't satisfied. It is called spurious because the thread has seemingly been awakened for no reason. But spurious wakeups don't happen for no reason, they usually happen because in between the time when the condition variable was signaled and when the waiting thread finally ran, another thread ran and changed the condition. There was a race condition between the threads, with the typical result that sometimes, the thread waking up on the condition variable runs first, winning the race, and sometimes it runs second, losing the race.

Spurious wakes can cause some unfortunate bugs, which are hard to track down due to the unpredictability of spurious wakes. These problems can be avoided by using a predicate that is packaged as a function or function object, using the predicated overloads of wait(), wait_for() and wait_until().

Wrong example:

std::condition_variable cv; std::mutex cv_m; int i = 0; void waits() { std::unique_lock lk(cv_m); std::cerr << "Waiting... \n"; cv.wait(lk); std::cerr << "...finished waiting. i == 1\n"; } void signals() { std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard lk(cv_m); std::cerr << "Notifying...\n"; } cv.notify_all(); std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard lk(cv_m); i = 1; std::cerr << "Notifying again...\n"; } cv.notify_all(); }

The wait call should have one extra predicate argument:

std::condition_variable cv; std::mutex cv_m; int i = 0; void waits() { std::unique_lock lk(cv_m); std::cerr << "Waiting... \n"; cv.wait(lk, []{return i == 1;}); std::cerr << "...finished waiting. i == 1\n"; } void signals() { std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard lk(cv_m); std::cerr << "Notifying...\n"; } cv.notify_all(); std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard lk(cv_m); i = 1; std::cerr << "Notifying again...\n"; } cv.notify_all(); }



Literature References:
Dalvander