Reputation: 3373
I found the following example for condition variable on www.cppreference.com, http://en.cppreference.com/w/cpp/thread/condition_variable. The call to cv.notify_one() is placed outside the lock. My question is if the call should be made while holding the lock to guarantee that waiting threads are in fact in waiting state and will receive the notify signal.
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}
Should the notify_one() call be moved inside the lock to guarantee waiting threads receive the notify signal,
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
cv.notify_one();
std::cout << "main() signals data ready for processing\n";
}
Upvotes: 16
Views: 8467
Reputation: 303
There is a scenario where it is crucial that the lock is held while notify_all is called: when the condition_variable is destroyed after waiting, a spurious wake-up can cause the wait to be ended and the condition_variable destroyed before notify_all is called on the already destroyed object.
Upvotes: 0
Reputation: 26486
if I understand your question correctly, it's equivilant to "should the notifier thread lock the mutex while trying to notify some CV in other thread"
no, it is not mandatory and even does some counter-effect.
when condition_variable
is notified from another thread it tries to-relock the mutex on which it was put to sleep. locking that mutex from its working thread will block the other thread which trying to lock it, untill the that lock-wrapper gets out of scope.
PS
if you do remove the locking from the function that send data to the worker threads, ready
and processed
should at least be atomics. currently they are synchronized by the lock , but when you remove the lock they cease to be thread-safe
Upvotes: 8
Reputation: 62583
You do not need to notify under lock. However, since notify is logically happening when the actual value is changed (otherwise, why would you notify?) and that change must happen under lock, it is often done within the lock.
There would be no practical observable difference.
Upvotes: 10
Reputation: 807
If you do not wait on a condition variable then the notification is lost. It does not matter if you are holding any locks. A condition variable is a synchronization primitive and do not need a lock for protection.
You can miss signals with and without lock. The mutex protects only normal data like ready
or processed
.
Upvotes: -5