Reputation: 550
We know that condition variables a subject to spurious wake ups. Let's assume we have a 1-producer-1-consumer queue synchronized with a mutex and condition variable. The consumer thread gets a spurious wake up. The question is - will the consumer thread miss the notify signal from the producer? I understand it's extremely unlikely.. but is it still possible to lose the last element in the queue with such implementation?
Upvotes: 2
Views: 377
Reputation: 76315
If the code that calls wait()
isn't written right, it could, indeed, miss a wake up. But that would be a bit perverse. The usual idiom is:
lock the mutex
while the condition is not satisfied
wait on the condition variable
the signaling thread should lock the mutex before signaling:
lock the mutex
signal the condition variable
Waiting on the condition variable unlocks the mutex for the duration of the wait. When the wait call returns, though, the mutex will be locked. So on a spurious wake up, the waiting thread will hold the mutex until it resumes waiting. While the waiting thread holds the mutex, the signaling thread can't signal the condition variable. When the waiting thread actually waits, the mutex gets unlocked and the signaling thread can go ahead and signal; the waiting thread will get the signal, and once the signaling thread releases the mutex, the waiting thread will resume execution.
So, no, proper code won't miss a signal. But if the waiting thread releases the mutex and reacquires it in the course of checking its condition, the signal could occur before the waiting thread calls wait, and the signal will be lost. Don't do that. <g>
Upvotes: 3
Reputation: 1099
Spurious wake up means it might wake up spuriously and then have to continue waiting.
It does not refer at all to the possibility of missing an event, for it would be useless if that were true.
This link provides a detailed explanation of cv and the wait method:
https://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables
// print a starting message
{
std::unique_lock<std::mutex> locker(g_lockprint);
std::cout << "[logger]\trunning..." << std::endl;
}
// loop until end is signaled
while(!g_done)
{
std::unique_lock<std::mutex> locker(g_lockqueue);
g_queuecheck.wait(locker, [&](){return !g_codes.empty();});
// if there are error codes in the queue process them
while(!g_codes.empty())
{
std::unique_lock<std::mutex> locker(g_lockprint);
std::cout << "[logger]\tprocessing error: " << g_codes.front() << std::endl;
g_codes.pop();
}
}
Upvotes: 1