Use of mutex after condition variable has been notified - c++

What is the reason for a notified condition variable to re-lock the mutex after being notified.
The following piece of code deadlock if unique_lock is not scoped or if mutex is not explicitely unlocked
#include <future>
#include <mutex>
#include <iostream>
using namespace std;
int main()
{
std::mutex mtx;
std::condition_variable cv;
//simulate another working thread sending notification
auto as = std::async([&cv](){ std::this_thread::sleep_for(std::chrono::seconds(2));
cv.notify_all();});
//uncomment scoping (or unlock below) to prevent deadlock
//{
std::unique_lock<std::mutex> lk(mtx);
//Spurious Wake-Up Prevention not adressed in this short sample
//UNLESS it is part of the answer / reason to lock again
cv.wait(lk);
//}
std::cout << "CV notified\n" << std::flush;
//uncomment unlock (or scoping above) to prevent deadlock
//mtx.unlock();
mtx.lock();
//do something
mtx.unlock();
std::cout << "End may never be reached\n" << std::flush;
return 0;
}
Even re-reading some documentation and examples I still do not find this obvious.
Most examples that can be found over the net are small code samples that have inherent scoping of the unique_lock.
Shall we use different mutex to deal with critical sections (mutex 1) and condition variables wait and notify (mutex 2) ?
Note: Debug shows that after end of the waiting phase, the "internal" "mutex count" (I think field __count of structure __pthread_mutex_s ) goes from 1 to 2. It reaches back 0 after unlock

You're trying to lock the mutex twice. Once with the unique_lock and again with the explicit mutex.lock() call. For non-recursive mutex, it will deadlock on a re-lock attempt to let you know you have a bug.
std::unique_lock<std::mutex> lk(mtx); // This locks for the lifetime of the unique_lock object
cv.wait(lk); // this will unlock while waiting, but relock on return
std::cout << "CV notified\n" << std::flush;
mtx.lock(); // This attempts to lock the mutex again, but will deadlock since unique_lock has already invoked mutex.lock() in its constructor.
The fix is pretty close to what you have with those curly braces uncommented. Just make sure you only have one lock active at a time on the mutex.
Also, as you have it, your code is prone to spurious wake-up. Here's some adjustments for you. You should always stay in the wait loop until the condition or state (usually guarded by the mutex itself) has actually occurred. For a simple notification, a bool will do.
int main()
{
std::mutex mtx;
std::condition_variable cv;
bool conditon = false;
//simulate another working thread sending notification
auto as = std::async([&cv, &mtx, &condition](){
std::this_thread::sleep_for(std::chrono::seconds(2));
mtx.lock();
condition = true;
mtx.unlock();
cv.notify_all();});
std::unique_lock<std::mutex> lk(mtx); // acquire the mutex lock
while (!condition)
{
cv.wait(lk);
}
std::cout << "CV notified\n" << std::flush;
//do something - while still under the lock
return 0;
}

Because the condition wait might return for reasons besides being notified such as a signal, or just because someone else wrote onto the same 64-byte cache line. Or it might have been notified but the condition is no longer true because another thread handled it.
So the mutex is locked so that your code can check its condition variable while holding the mutex. Maybe that's just a boolean value saying it's ready to go.
Do NOT skip that part. If you do, you will regret it.

Let's temporarily imagine that the mutex is not locked on return from wait:
Thread 1:
Locks mutex, checks predicate (whatever that may be), and upon finding the predicate not in an acceptable form, waits for some other thread to put it in an acceptable form. The wait atomically puts thread 1 to sleep and unlocks the mutex. With the mutex unlocked, some other thread will have permission to put the predicate in the acceptable state (the predicate is not naturally thread safe).
Thread 2:
Simultaneously, this thread is trying to lock the mutex and put the predicate in a state that is acceptable for thread 1 to continue past its wait. It must do this with the mutex locked. The mutex protects the predicate from being accessed (either read or written) by more than one thread at a time.
Once thread 2 puts the mutex in an acceptable state, it notifies the condition_variable and unlocks the mutex (the order of these two actions is not relevant to this argument).
Thread 1:
Now thread 1 has been notified and we presume the hypothetical that the mutex isn't locked on return from wait. The first thing thread 1 has to do is check the predicate to see if it is actually acceptable (this could be a spurious wakeup). But it shouldn't check the predicate without the mutex being locked. Otherwise some other thread could change the predicate right after this thread checks it, invalidating the result of that check.
So the very first thing this thread has to do upon waking is lock the mutex, and then check the predicate.
So it is really more of a convenience that the mutex is locked upon return from wait. Otherwise the waiting thread would have to manually lock it 100% of the time.
Let's look again at the events as thread 1 is entering the wait: I said that the sleep and the unlock happen atomically. This is very important. Imagine if thread 1 has to manually unlock the mutex and then call wait: In this hypothetical scenario, thread 1 could unlock the mutex, and then be interrupted while another thread obtains the mutex, changes the predicate, unlocks the mutex and signals the condition_variable, all before thread 1 calls wait. Now thread 1 sleeps forever, because no thread is going to see that the predicate needs changing, and the condition_variable needs signaling.
So it is imperative that the unlock/enter-wait happen atomically. And it makes the API easier to use if the lock/exit-wait also happens atomically.

Related

Why is this printing 1,3,2? [duplicate]

For simplicity, let's assume that we have only one conditional variable to match a single condition that is reflected by a boolean.
1) Why does std::condition_variable::wait(...) locks the mutex again after a "notify" has been sent to un-sleep it?
2) Seeing the behaviour in "1)", does that mean that when you do std::condition_variable::notify_all it only makes it so that all of the waiting threads are unblocked/woken up... but in order instead of all at once? If so, what can be done to do it all at once?
3) If I only care about threads sleeping until a condition is met and not care a single bit for any mutex acquisition, what can I do? Is there an alternative or should current std::condition_variable::wait(...) approach(es) be hacked around this?
If "hackery" is to be used, will this function work for unblocking all waiting threads on a condition and can it be called from any(per thread) threads:
//declared somehwere and modified before sending "notify"(ies)
std::atomic<bool> global_shared_condition_atomic_bool;
//the single(for simplicity in our case) condition variable matched with the above boolean result
std::condition_variable global_shared_condition_variable;
static void MyClass:wait()
{
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
while (!global_shared_condition_atomic_bool) global_shared_condition_variable.wait(lock);
}
it would have been called from random "waiting" threads like so:
void random_thread_run()
{
while(someLoopControlValue)
{
//random code...
MyClass:wait(); //wait for whatever condition the class+method is for.
//more random code...
}
}
Edit:
Gate class
#ifndef Gate_Header
#define Gate_Header
#include <mutex>
#include <condition_variable>
class Gate
{
public:
Gate()
{
gate_open = false;
}
void open()
{
m.lock();
gate_open = true;
m.unlock();
cv.notify_all();
}
void wait()
{
std::unique_lock<std::mutex> lock(m);
while (!gate_open) cv.wait(lock);
}
void close()
{
m.lock();
gate_open = false;
m.unlock();
}
private:
std::mutex m;
std::condition_variable cv;
bool gate_open;
};
#endif
Condition variables wake things up spuriously.
You must have a mutex and it must guard a message of some kind for them to work, or you have zero guarantee that any such wakeup occurred.
This was done, presumably, because efficient implementations of a non-spurious version end up being implemeneted in terms of such a spurious version anyhow.
If you fail to guard the message editing with a mutex (ie, no synchronization on it, the state of the message is undefined behavior. This can cause compilers to optimize the read from memory to skip it after the first read.
Even excluding that undefined behavior (imagine you use atomics), there are race conditions where a message is set, a notification occurs, and nobody waiting on the notification sees the message being set if you fail to have the mutex acquired in the time between the variable being set and the condition variable being notified.
Barring extreme cases, you usually want to use the lambda version of wait.
Auditing condition variable code is not possible unless you audit both the notification code and the wait code.
struct gate {
bool gate_open = false;
mutable std::condition_variable cv;
mutable std::mutex m;
void open_gate() {
std::unique_lock<std::mutex> lock(m);
gate_open=true;
cv.notify_all();
}
void wait_at_gate() const {
std::unique_lock<std::mutex> lock(m);
cv.wait( lock, [this]{ return gate_open; } );
}
};
or
void open_gate() {
{
std::unique_lock<std::mutex> lock(m);
gate_open=true;
}
cv.notify_all();
}
No, your code will not work.
The mutex protects modifications to the shared variable. As such, all of the waiting threads and the signaling thread must lock that specific mutex instance. With what you've written, each thread has its own mutex instance.
The main reason for all of this mutex stuff is due to the concept of spurious wakeup, an unfortunate aspect of OS implementations of condition variables. Threads waiting on them sometimes just start running even though the condition hasn't been satisfied yet.
The mutex-bound check of the actual variable allows the thread to test whether it was spuriously awoken or not.
wait atomically releases the mutex and starts waiting on the condition. When wait exits, the mutex is atomically reacquired as part of the wakeup process. Now, consider a race between a spurious wakeup and the notifying thread. The notifying thread can be in one of 2 states: about to modify the variable, or after modifying it and about to notify everyone to wake up.
If the spurious wakeup happens when the notifying thread is about to modify the varaible, then one of them will get to the mutex first. So the spuriously awoken thread will either see the old value or the new value. If it sees the new, then it has been notified and will go do its business. If it sees the old, then it will wait on the condition again. But if it saw the old, then it blocked the notifying thread from modifying that variable, so it had to wait until the spurious thread went back to sleep.
Why does std::condition_variable::wait(...) locks the mutex again after a "notify" has been sent to un-sleep it?
Because the mutex locks access to the condition variable. And the first thing you have to do after waking up from a wait call is to check the condition variable. As such, that must be done under the protection of the mutex.
The signalling thread must be prevented from modifying the variable while other threads are reading it. That's what the mutex is for.
Seeing the behaviour in "1)", does that mean that when you do std::condition_variable::notify_all it only makes it so that all of the waiting threads are unblocked/woken up... but in order instead of all at once?
The order they wake up in is not specified. However, by the time notify_all returns, all threads are guaranteed to have been unblocked.
If I only care about threads sleeping until a condition is met and not care a single bit for any mutex acquisition, what can I do?
Nothing. condition_variable requires that access to the actual variable you're checking is controlled via a mutex.

Is my wait - notify mechanism using std::mutex correct?

I started using std::mutexes to stop a thread and wait for another thread to resume it. It works like this:
Thread 1
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
// Locks it again to pause this thread
myWaitMutex.lock();
Thread 2
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
However I am not sure if this is correct and will work without problems on all platforms. If this is not correct, what is the correct way to implement this in C++11?
The problems with the code
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
.try_lock() tries to aquire the lock and returns true if successful, i.e., the code says "if we aquire the lock then retry to lock it again and again until we fail". We can never "fail" as we currently own the lock ourselves that we are waiting on, and so this will be an infinite loop. Also, attempting to lock using a std::mutex that the caller have already aquired a lock on is UB, so this is guaranteed to be UB. If not successful, .try_lock() will return false and the while loop will be exited. In other words, this will not ensure that the mutex will be locked.
The correct way to ensure the mutex will be locked is simply:
myWaitMutex.lock();
This will cause the current thread to block (indefinitely) until it can aquire the lock.
Next, the other thread tries to unlock a mutex it does not have a lock on.
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
This won't work as it's UB to .unlock() on a std::mutex that you don't already have a lock on.
Using locks
When using mutex locks, it's easier to use a RAII ownership-wrapper object such as std::lock_guard. The usage pattern of std::mutex is always: "Lock -> do something in critical section -> unlock". A std::lock_guard will lock the mutex in its constructor, and unlock it in its destructor. No need to worry about when to lock and unlock and such low-level stuff.
std::mutex m;
{
std::lock_guard<std::mutex> lk{m};
/* We have the lock until we exit scope. */
} // Here 'lk' is destroyed and will release lock.
A simple lock might not be the best tool for the job
If what you want is to be able to signal a thread to wake up, then there's the wait and notify structure using std::condition_variable. The std::condition_variable allows any caller to send a signal to waiting threads without holding any locks.
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std::literals;
int main() {
std::mutex m;
std::condition_variable cond;
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
cond.wait(lk); // Will block until 'cond' is notified.
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
cond.notify_all(); // Notify all waiting threads.
t.join(); // Remember to join thread before exit.
}
However, to further complicate things there's this thing called spurious wakeups that mean that any waiting threads may wake up at any time for unknown reasons. This is a fact on most systems and has to do with the inner workings of thread scheduling. Also, we probably need to check that waiting is really needed as we're dealing with concurrency. If, for example, the notifying thread happens to notify before we start waiting, then we might wait forever unless we have a way to first check this.
To handle this we need to add a while loop and a predicate that tells when we need to wait and when we're done waiting.
int main() {
std::mutex m;
std::condition_variable cond;
bool done = false; // Flag for indicating when done waiting.
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
while (!done) { // Wait inside loop to handle spurious wakeups etc.
cond.wait(lk);
}
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
{ // Aquire lock to avoid data race on 'done'.
std::lock_guard<std::mutex> lk{m};
done = true; // Set 'done' to true before notifying.
}
cond.notify_all();
t.join();
}
There are additional reasons why it's a good idea to wait inside a loop and use a predicate such as "stolen wakeups" as mentioned in the comments by #David Schwartz.
It sounds to me that you are looking for condition variable. In the end there should always be a way to make it work through mutexes, but condition variable is the current C++ idiomatic way to handle the `block and wait until something happens' scenario.
The behavior of a mutex when a thread that holds it attempts to lock it is undefined. The behavior of a mutex when a thread that doesn't hold it attempts to unlock it is undefined. So your code might do anything at all on various platforms.
Instead, use a mutex together with a condition variable and a predicate boolean. In pseudo-code:
To block:
Acquire the mutex.
While the predicate is false, block on the condition variable.
If you want to re-arm here, set the predicate to false.
Release the mutex.
To release:
Acquire the mutex.
Set the predicate to true.
Signal the condition variable.
Release the mutex.
To rearm:
Acquire the mutex.
Set the predicate to false.
Release the mutex.
Please check this code....
std::mutex m_mutex;
std::condition_variable m_cond_var;
void threadOne(){
std::unique_lock<std::mutex> lck(mtx);
while (!ready){
m_cond_var.wait(lck);
}
m_cond_var.notify_all();
}
void threadTwo(){
std::unique_lock<std::mutex> lck(mtx);
read = true;
m_cond_var.notify_all();
}
I hope you will get the solution. And it is very proper!!

Using std::conditional_variable to wait on a condition

For simplicity, let's assume that we have only one conditional variable to match a single condition that is reflected by a boolean.
1) Why does std::condition_variable::wait(...) locks the mutex again after a "notify" has been sent to un-sleep it?
2) Seeing the behaviour in "1)", does that mean that when you do std::condition_variable::notify_all it only makes it so that all of the waiting threads are unblocked/woken up... but in order instead of all at once? If so, what can be done to do it all at once?
3) If I only care about threads sleeping until a condition is met and not care a single bit for any mutex acquisition, what can I do? Is there an alternative or should current std::condition_variable::wait(...) approach(es) be hacked around this?
If "hackery" is to be used, will this function work for unblocking all waiting threads on a condition and can it be called from any(per thread) threads:
//declared somehwere and modified before sending "notify"(ies)
std::atomic<bool> global_shared_condition_atomic_bool;
//the single(for simplicity in our case) condition variable matched with the above boolean result
std::condition_variable global_shared_condition_variable;
static void MyClass:wait()
{
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
while (!global_shared_condition_atomic_bool) global_shared_condition_variable.wait(lock);
}
it would have been called from random "waiting" threads like so:
void random_thread_run()
{
while(someLoopControlValue)
{
//random code...
MyClass:wait(); //wait for whatever condition the class+method is for.
//more random code...
}
}
Edit:
Gate class
#ifndef Gate_Header
#define Gate_Header
#include <mutex>
#include <condition_variable>
class Gate
{
public:
Gate()
{
gate_open = false;
}
void open()
{
m.lock();
gate_open = true;
m.unlock();
cv.notify_all();
}
void wait()
{
std::unique_lock<std::mutex> lock(m);
while (!gate_open) cv.wait(lock);
}
void close()
{
m.lock();
gate_open = false;
m.unlock();
}
private:
std::mutex m;
std::condition_variable cv;
bool gate_open;
};
#endif
Condition variables wake things up spuriously.
You must have a mutex and it must guard a message of some kind for them to work, or you have zero guarantee that any such wakeup occurred.
This was done, presumably, because efficient implementations of a non-spurious version end up being implemeneted in terms of such a spurious version anyhow.
If you fail to guard the message editing with a mutex (ie, no synchronization on it, the state of the message is undefined behavior. This can cause compilers to optimize the read from memory to skip it after the first read.
Even excluding that undefined behavior (imagine you use atomics), there are race conditions where a message is set, a notification occurs, and nobody waiting on the notification sees the message being set if you fail to have the mutex acquired in the time between the variable being set and the condition variable being notified.
Barring extreme cases, you usually want to use the lambda version of wait.
Auditing condition variable code is not possible unless you audit both the notification code and the wait code.
struct gate {
bool gate_open = false;
mutable std::condition_variable cv;
mutable std::mutex m;
void open_gate() {
std::unique_lock<std::mutex> lock(m);
gate_open=true;
cv.notify_all();
}
void wait_at_gate() const {
std::unique_lock<std::mutex> lock(m);
cv.wait( lock, [this]{ return gate_open; } );
}
};
or
void open_gate() {
{
std::unique_lock<std::mutex> lock(m);
gate_open=true;
}
cv.notify_all();
}
No, your code will not work.
The mutex protects modifications to the shared variable. As such, all of the waiting threads and the signaling thread must lock that specific mutex instance. With what you've written, each thread has its own mutex instance.
The main reason for all of this mutex stuff is due to the concept of spurious wakeup, an unfortunate aspect of OS implementations of condition variables. Threads waiting on them sometimes just start running even though the condition hasn't been satisfied yet.
The mutex-bound check of the actual variable allows the thread to test whether it was spuriously awoken or not.
wait atomically releases the mutex and starts waiting on the condition. When wait exits, the mutex is atomically reacquired as part of the wakeup process. Now, consider a race between a spurious wakeup and the notifying thread. The notifying thread can be in one of 2 states: about to modify the variable, or after modifying it and about to notify everyone to wake up.
If the spurious wakeup happens when the notifying thread is about to modify the varaible, then one of them will get to the mutex first. So the spuriously awoken thread will either see the old value or the new value. If it sees the new, then it has been notified and will go do its business. If it sees the old, then it will wait on the condition again. But if it saw the old, then it blocked the notifying thread from modifying that variable, so it had to wait until the spurious thread went back to sleep.
Why does std::condition_variable::wait(...) locks the mutex again after a "notify" has been sent to un-sleep it?
Because the mutex locks access to the condition variable. And the first thing you have to do after waking up from a wait call is to check the condition variable. As such, that must be done under the protection of the mutex.
The signalling thread must be prevented from modifying the variable while other threads are reading it. That's what the mutex is for.
Seeing the behaviour in "1)", does that mean that when you do std::condition_variable::notify_all it only makes it so that all of the waiting threads are unblocked/woken up... but in order instead of all at once?
The order they wake up in is not specified. However, by the time notify_all returns, all threads are guaranteed to have been unblocked.
If I only care about threads sleeping until a condition is met and not care a single bit for any mutex acquisition, what can I do?
Nothing. condition_variable requires that access to the actual variable you're checking is controlled via a mutex.

How do std::unique_lock and std::condition_variable work

I need to be clarified how lock and condition_variable work.
In the -slightly modified- code from here cplusplusreference
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);
std::this_thread::sleep_for(std::chrono::seconds(1));
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();
}
The thing that I was confused with was how main thread could lock the mutex if worker_thread had already locked it.
From this answer I saw that it is because cv.wait unlocks the mutex.
But now I am confused with this: So why do we need to lock it at all, if cv.wait will unlock it?
For example, could I do this?
std::unique_lock<std::mutex> lk(m, std::defer_lock);
So, I create the lock object because cv needs it, but I do not lock it when I create.
Is there any difference now?
I did not see why I get "runtime error" here in that case.
Quoted from std::condition_variable::wait() :
Calling this function if lock.mutex() is not locked by the current thread is undefined behavior.
I will try to add a bit more explanation as to WHY condition variables require a lock.
You have to have a lock because your code needs to check that the condition predicate is true. The predicate is some value or combination of values that has to be true in order to continue. It could be a pointer that is NULL or points to a completed data structure ready for use.
You have to lock it AND CHECK the predicate before waiting because by the time you start waiting for the condition another thread might have already set it.
The condition notify and the wait returning does NOT mean that the condition is true. It only means that the condition WAS true at some time. It might even have been true, then false, then true again. It might also mean that your thread had been in an unrelated signal handler that caused the condition wait to break out. Your code does not even know how many times the condition notify has been called.
So once the condition wait returns it LOCKS the mutex. Now your code can check the condition while safely in the lock. If true then the code can update what it needs to update and release the lock. If it wasn't true it just goes back to the condition wait to try again. For example, it could take that data structure pointer and copy it into a vector, then set the lock protected pointer back to NULL.
Think of a condition as a way to make a polling loop more efficient. Your code still has to do all of the things it would do running in a loop waiting, except that it can go to sleep instead of non-stop spinning.
I think your misunderstanding stems from a deeper misunderstanding of what locks are and how they interact with condition variables.
The basic reason a lock exists is to provide mutual exclusion. Mutual exclusion guarantees that certain parts of the code are only executed by a single thread. This is why you can't just wait with the lock until later - you need it locked to have your guarantees.
This causes problems when you want some other parts of the code to execute but still need to have mutual exclusion while the current piece of code executes. This is where condition variables come in handy: they provide a structured way to release the lock and be guaranteed that when you wake up again you will have it back. This is why the lock is unlocked while in the wait function.

Do I have to acquire lock before calling condition_variable.notify_one()?

I am a bit confused about the use of std::condition_variable. I understand I have to create a unique_lock on a mutex before calling condition_variable.wait(). What I cannot find is whether I should also acquire a unique lock before calling notify_one() or notify_all().
Examples on cppreference.com are conflicting. For example, the notify_one page gives this example:
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cout << "...finished waiting. i == 1\n";
done = true;
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Notifying...\n";
cv.notify_one();
std::unique_lock<std::mutex> lk(cv_m);
i = 1;
while (!done) {
lk.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
lk.lock();
std::cerr << "Notifying again...\n";
cv.notify_one();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join(); t2.join();
}
Here the lock is not acquired for the first notify_one(), but is acquired for the second notify_one(). Looking though other pages with examples I see different things, mostly not acquiring the lock.
Can I choose myself to lock the mutex before calling notify_one(), and why would I choose to lock it?
In the example given, why is there no lock for the first notify_one(), but there is for subsequent calls. Is this example wrong or is there some rationale?
You do not need to be holding a lock when calling condition_variable::notify_one(), but it's not wrong in the sense that it's still well defined behavior and not an error.
However, it might be a "pessimization" since whatever waiting thread is made runnable (if any) will immediately try to acquire the lock that the notifying thread holds. I think it's a good rule of thumb to avoid holding the lock associated with a condition variable while calling notify_one() or notify_all(). See Pthread Mutex: pthread_mutex_unlock() consumes lots of time for an example where releasing a lock before calling the pthread equivalent of notify_one() improved performance measurably.
Keep in mind that the lock() call in the while loop is necessary at some point, because the lock needs to be held during the while (!done) loop condition check. But it doesn't need to be held for the call to notify_one().
2016-02-27: Large update to address some questions in the comments about whether there's a race condition if the lock isn't held for the notify_one() call. I know this update is late because the question was asked almost two years ago, but I'd like to address #Cookie's question about a possible race condition if the producer (signals() in this example) calls notify_one() just before the consumer (waits() in this example) is able to call wait().
The key is what happens to i - that's the object that actually indicates whether or not the consumer has "work" to do. The condition_variable is just a mechanism to let the consumer efficiently wait for a change to i.
The producer needs to hold the lock when updating i, and the consumer must hold the lock while checking i and calling condition_variable::wait() (if it needs to wait at all). In this case, the key is that it must be the same instance of holding the lock (often called a critical section) when the consumer does this check-and-wait. Since the critical section is held when the producer updates i and when the consumer checks-and-waits on i, there is no opportunity for i to change between when the consumer checks i and when it calls condition_variable::wait(). This is the crux for a proper use of condition variables.
The C++ standard says that condition_variable::wait() behaves like the following when called with a predicate (as in this case):
while (!pred())
wait(lock);
There are two situations that can occur when the consumer checks i:
if i is 0 then the consumer calls cv.wait(), then i will still be 0 when the wait(lock) part of the implementation is called - the proper use of the locks ensures that. In this case the producer has no opportunity to call the condition_variable::notify_one() in its while loop until after the consumer has called cv.wait(lk, []{return i == 1;}) (and the wait() call has done everything it needs to do to properly 'catch' a notify - wait() won't release the lock until it has done that). So in this case, the consumer cannot miss the notification.
if i is already 1 when the consumer calls cv.wait(), the wait(lock) part of the implementation will never be called because the while (!pred()) test will cause the internal loop to terminate. In this situation it doesn't matter when the call to notify_one() occurs - the consumer will not block.
The example here does have the additional complexity of using the done variable to signal back to the producer thread that the consumer has recognized that i == 1, but I don't think this changes the analysis at all because all of the access to done (for both reading and modifying) are done while in the same critical sections that involve i and the condition_variable.
If you look at the question that #eh9 pointed to, Sync is unreliable using std::atomic and std::condition_variable, you will see a race condition. However, the code posted in that question violates one of the fundamental rules of using a condition variable: It does not hold a single critical section when performing a check-and-wait.
In that example, the code looks like:
if (--f->counter == 0) // (1)
// we have zeroed this fence's counter, wake up everyone that waits
f->resume.notify_all(); // (2)
else
{
unique_lock<mutex> lock(f->resume_mutex);
f->resume.wait(lock); // (3)
}
You will notice that the wait() at #3 is performed while holding f->resume_mutex. But the check for whether or not the wait() is necessary at step #1 is not done while holding that lock at all (much less continuously for the check-and-wait), which is a requirement for proper use of condition variables). I believe that the person who has the problem with that code snippet thought that since f->counter was a std::atomic type this would fulfill the requirement. However, the atomicity provided by std::atomic doesn't extend to the subsequent call to f->resume.wait(lock). In this example, there is a race between when f->counter is checked (step #1) and when the wait() is called (step #3).
That race does not exist in this question's example.
As others have pointed out, you do not need to be holding the lock when calling notify_one(), in terms of race conditions and threading-related issues. However, in some cases, holding the lock may be required to prevent the condition_variable from getting destroyed before notify_one() is called. Consider the following example:
thread t;
void foo() {
std::mutex m;
std::condition_variable cv;
bool done = false;
t = std::thread([&]() {
{
std::lock_guard<std::mutex> l(m); // (1)
done = true; // (2)
} // (3)
cv.notify_one(); // (4)
}); // (5)
std::unique_lock<std::mutex> lock(m); // (6)
cv.wait(lock, [&done]() { return done; }); // (7)
}
void main() {
foo(); // (8)
t.join(); // (9)
}
Assume there is a context switch to the newly created thread t after we created it but before we start waiting on the condition variable (somewhere between (5) and (6)). The thread t acquires the lock (1), sets the predicate variable (2) and then releases the lock (3). Assume there is another context switch right at this point before notify_one() (4) is executed. The main thread acquires the lock (6) and executes line (7), at which point the predicate returns true and there is no reason to wait, so it releases the lock and continues. foo returns (8) and the variables in its scope (including cv) are destroyed. Before thread t could join the main thread (9), it has to finish its execution, so it continues from where it left off to execute cv.notify_one() (4), at which point cv is already destroyed!
The possible fix in this case is to keep holding the lock when calling notify_one (i.e. remove the scope ending in line (3)). By doing so, we ensure that thread t calls notify_one before cv.wait can check the newly set predicate variable and continue, since it would need to acquire the lock, which t is currently holding, to do the check. So, we ensure that cv is not accessed by thread t after foo returns.
To summarize, the problem in this specific case is not really about threading, but about the lifetimes of the variables captured by reference. cv is captured by reference via thread t, hence you have to make sure cv stays alive for the duration of the thread's execution. The other examples presented here do not suffer from this issue, because condition_variable and mutex objects are defined in the global scope, hence they are guaranteed to be kept alive until the program exits.
Situation
Using vc10 and Boost 1.56 I implemented a concurrent queue pretty much like this blog post suggests. The author unlocks the mutex to minimize contention, i.e., notify_one() is called with the mutex unlocked:
void push(const T& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(item);
mlock.unlock(); // unlock before notificiation to minimize mutex contention
cond_.notify_one(); // notify one waiting thread
}
Unlocking the mutex is backed by an example in the Boost documentation:
void prepare_data_for_processing()
{
retrieve_data();
prepare_data();
{
boost::lock_guard<boost::mutex> lock(mut);
data_ready=true;
}
cond.notify_one();
}
Problem
Still this led to the following erratic behaviour:
while notify_one() has not been called yet cond_.wait() can still be interrupted via boost::thread::interrupt()
once notify_one() was called for the first time cond_.wait() deadlocks; the wait cannot be ended by boost::thread::interrupt() or boost::condition_variable::notify_*() anymore.
Solution
Removing the line mlock.unlock() made the code work as expected (notifications and interrupts end the wait). Note that notify_one() is called with the mutex still locked, it is unlocked right afterwards when leaving the scope:
void push(const T& item)
{
std::lock_guard<std::mutex> mlock(mutex_);
queue_.push(item);
cond_.notify_one(); // notify one waiting thread
}
That means that at least with my particular thread implementation the mutex must not be unlocked before calling boost::condition_variable::notify_one(), although both ways seem correct.
#Michael Burr is correct. condition_variable::notify_one does not require a lock on the variable. Nothing prevents you to use a lock in that situation though, as the example illustrates it.
In the given example, the lock is motivated by the concurrent use of the variable i. Because the signals thread modifies the variable, it needs to ensure that no other thread is access it during that time.
Locks are used for any situation requiring synchronization, I don't think we can state it in a more general way.
In some case, when the cv may be occupied(locked) by other threads. You needs to get lock and release it before notify_*().
If not, the notify_*() maybe not executed at all.
Just adding this answer because I think the accepted answer might be misleading. In all cases you will need to lock the mutex, prior to calling notify_one() somewhere for your code to be thread-safe, although you might unlock it again before actually calling notify_*().
To clarify, you MUST take the lock before entering wait(lk) because wait() unlocks lk and it would be Undefined Behavior if the lock wasn't locked. This is not the case with notify_one(), but you need to make sure you won't call notify_*() before entering wait() and having that call unlock the mutex; which obviously only can be done by locking that same mutex before you call notify_*().
For example, consider the following case:
std::atomic_int count;
std::mutex cancel_mutex;
std::condition_variable cancel_cv;
void stop()
{
if (count.fetch_sub(1) == -999) // Reached -1000 ?
cv.notify_one();
}
bool start()
{
if (count.fetch_add(1) >= 0)
return true;
// Failure.
stop();
return false;
}
void cancel()
{
if (count.fetch_sub(1000) == 0) // Reached -1000?
return;
// Wait till count reached -1000.
std::unique_lock<std::mutex> lk(cancel_mutex);
cancel_cv.wait(lk);
}
Warning: this code contains a bug.
The idea is the following: threads call start() and stop() in pairs, but only as long as start() returned true. For example:
if (start())
{
// Do stuff
stop();
}
One (other) thread at some point will call cancel() and after returning from cancel() will destroy objects that are needed at 'Do stuff'. However, cancel() is supposed not to return while there are threads between start() and stop(), and once cancel() executed its first line, start() will always return false, so no new threads will enter the 'Do stuff' area.
Works right?
The reasoning is as follows:
1) If any thread successfully executes the first line of start() (and therefore will return true) then no thread did execute the first line of cancel() yet (we assume that the total number of threads is much smaller than 1000 by the way).
2) Also, while a thread successfully executed the first line of start(), but not yet the first line of stop() then it is impossible that any thread will successfully execute the first line of cancel() (note that only one thread ever calls cancel()): the value returned by fetch_sub(1000) will be larger than 0.
3) Once a thread executed the first line of cancel(), the first line of start() will always return false and a thread calling start() will not enter the 'Do stuff' area anymore.
4) The number of calls to start() and stop() are always balanced, so after the first line of cancel() is unsuccessfully executed, there will always be a moment where a (the last) call to stop() causes count to reach -1000 and therefore notify_one() to be called. Note that can only ever happen when the first line of cancel resulted in that thread to fall through.
Apart from a starvation problem where so many threads are calling start()/stop() that count never reaches -1000 and cancel() never returns, which one might accept as "unlikely and never lasting long", there is another bug:
It is possible that there is one thread inside the 'Do stuff' area, lets say it is just calling stop(); at that moment a thread executes the first line of cancel() reading the value 1 with the fetch_sub(1000) and falling through. But before it takes the mutex and/or does the call to wait(lk), the first thread executes the first line of stop(), reads -999 and calls cv.notify_one()!
Then this call to notify_one() is done BEFORE we are wait()-ing on the condition variable! And the program would indefinitely dead-lock.
For this reason we should not be able to call notify_one() until we called wait(). Note that the power of a condition variable lies there in that it is able to atomically unlock the mutex, check if a call to notify_one() happened and go to sleep or not. You can't fool it, but you do need to keep the mutex locked whenever you make changes to variables that might change the condition from false to true and keep it locked while calling notify_one() because of race conditions like described here.
In this example there is no condition however. Why didn't I use as condition 'count == -1000'? Because that isn't interesting at all here: as soon as -1000 is reached at all, we are sure that no new thread will enter the 'Do stuff' area. Moreover, threads can still call start() and will increment count (to -999 and -998 etc) but we don't care about that. The only thing that matters is that -1000 was reached - so that we know for sure that there are no threads anymore in the 'Do stuff' area. We are sure that this is the case when notify_one() is being called, but how to make sure we don't call notify_one() before cancel() locked its mutex? Just locking cancel_mutex shortly prior to notify_one() isn't going to help of course.
The problem is that, despite that we're not waiting for a condition, there still is a condition, and we need to lock the mutex
1) before that condition is reached
2) before we call notify_one.
The correct code therefore becomes:
void stop()
{
if (count.fetch_sub(1) == -999) // Reached -1000 ?
{
cancel_mutex.lock();
cancel_mutex.unlock();
cv.notify_one();
}
}
[...same start()...]
void cancel()
{
std::unique_lock<std::mutex> lk(cancel_mutex);
if (count.fetch_sub(1000) == 0)
return;
cancel_cv.wait(lk);
}
Of course this is just one example but other cases are very much alike; in almost all cases where you use a conditional variable you will need to have that mutex locked (shortly) before calling notify_one(), or else it is possible that you call it before calling wait().
Note that I unlocked the mutex prior to calling notify_one() in this case, because otherwise there is the (small) chance that the call to notify_one() wakes up the thread waiting for the condition variable which then will try to take the mutex and block, before we release the mutex again. That's just slightly slower than needed.
This example was kinda special in that the line that changes the condition is executed by the same thread that calls wait().
More usual is the case where one thread simply wait's for a condition to become true and another thread takes the lock before changing the variables involved in that condition (causing it to possibly become true). In that case the mutex is locked immediately before (and after) the condition became true - so it is totally ok to just unlock the mutex before calling notify_*() in that case.
As I understand notify_one calls pthread_cond_signal.
If so, then what do think about this?
For predictable scheduling behavior and to prevent lost wake-ups, the mutex should be held when signaling a condition variable.
https://www.unix.com/man-page/hpux/3T/pthread_cond_signal/
All of the threads waiting on the condition variable are suspended until another thread uses the signal function:
pthread_cond_signal(&myConVar);
In this case the mutex has to be locked before calling the function and unlocked after it.
https://www.i-programmer.info/programming/cc/12288-fundamental-c-condition-variables.html
I personally had cases when notifications were missed because notify_one was called without locking the mutex.