Why the condition variable is stuck on waiting if it was notified in worker_thread? What am I missing here?
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
std::mutex m;
std::condition_variable cv;
void worker_thread()
{
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
std::cout << "Start waiting..." << std::endl;
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
std::cout << "Finished waiting..." << std::endl;
worker.join();
getchar();
}
Your problem is that cv.notify_one() only wakes threads that are currently waiting. cv doesn't remember you notified it, and someone later comes along and waits.
Your worker thread is outpacing your main thread. So the notify happens before the main thread.
This is just a symptom of your real problem; you are using a condition variable wrong. Barring extremely advanced use, all use of condition variable should be in a triple.
A std::condition_variable.
A std::mutex.
A payload.
Your code is missing the payload.
To signal, you:
std::unique_lock<std::mutex> l(m);
payload = /* move it to a 'set' or 'non-empty' state */;
cv.notify_one(); // or all
to listen you:
std::unique_lock<std::mutex> l(m);
cv.wait(l, [&]{ return /* payload is in a set or non-empty state */; });
// while locked, consume one "unit" of payload from the payload.
with minor variations for wait_for and the like.
Following this cargo-cult pattern is important, as it avoids a number of pitfalls. It deals with both spurious wakeups with the wait happening after the notification.
Your code is missing a payload. So your code is vulnerable to both the waiting thread outrunning the signaling thread, and spurious wakeups.
Note that getting "clever" here is highly discouraged. For example, deciding that "I'll use an atomic variable to avoid using a mutex when signaling" actually doesn't work. Either follow the above recipe dogmatically, or go and spend a few months learning the threading and memory model of C++ well enough to improvise.
notify_one will unblock a waiting thread if there is one. If there are no waiting threads, nothing happens. A condition_variable does not have a state to remember how many threads should be notified when it is waited on.
Related
I had three initial ideas about this
Firstly some kind of counter? (Maybe using mutex?)
Some kind of semophore? (I don't know much about these) OR perhaps a promise/future combination
Some other kind of signal/slot mechanism, similar to that of the signal created by CTRL-C (SIGINT etc)
I'm working on some software which makes use of detached threads to do some work. Unfortunatly the threads don't clean up nicely, they just quit at the end of execution. This is fine for communication in one direction (ie; main() can quit first), but won't work the other way around - at the moment there is no way for main() to know when the threads have finished working and to exit gracefully.
To expand on those bullet points...
My initial idea was to have a protected region of variables - could be a counter or an array of flags, one for each thread, and to access these using a mutex. The mutex might not even be necessary if using one variable per detached thread to signal the end of the thread working, because main() will "poll" these variables, which is a read-only operation. Only the detached threads themselves need write access. If more than one detached thread uses the same counter/variable then a mutex would be required.
The next idea I had was to use a semophore (which is something I really know nothing about) or promise/future combinations, which I think would work as a possible option.
The final thought was some kind of signals mechanism, like possibly "stealing" a SIGxyz signal (like SIGINT) and using that to some how communicate the end of a thread execution. I'm not confident about this one however.
My question is really - how is this supposed to be done? What would the typical engineering solution to this problem be?
(Final thought: Using a file, or a pipe? Seems a bit complicated though?)
Perhaps I overlooked the question but I think you could use an atomic variable as a flag in order to notify the detached thread's termination.
Something like the following example:
#include <thread>
#include <iostream>
#include <atomic>
int main()
{
// Define a flag to notify detached thread's termination
std::atomic_bool term_flag;
// Define some function to run concurrently
auto func = [&term_flag](){
std::this_thread::sleep_for(std::chrono::seconds(2));
term_flag = true;
};
// Run and detach the thread
term_flag = false;
std::thread t(func);
t.detach();
// Wait until detached thread termination
while(!term_flag)
std::this_thread::yield();
std::cout << "Detached Thread has terminated properly" << std::endl;
return 0;
}
Output:
Detached Thread has terminated properly
EDIT:
As Hans Passant mentioned, you could also use a condition variable associated with a mutex to do it.
This would be a better solution (but a bit less readable in my humble opinion) since we have more control over how much to wait.
The basic example above could then be rewritten as:
#include <thread>
#include <iostream>
#include <mutex>
#include <condition_variable>
int main()
{
// Define the mutex and the condition variable to notify the detached thread's termination
std::mutex m;
std::condition_variable cv;
// Define some function to run concurrently
auto func = [&cv](){
std::this_thread::sleep_for(std::chrono::seconds(2));
cv.notify_one();
};
// Run and detach the thread
std::thread t(func);
t.detach();
// Wait until detached thread termination
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
}
std::cout << "Detached Thread has terminated properly" << std::endl;
return 0;
}
I have two threads. One thread acts as a timer thread which at regular intervals of time needs to send a notification to another thread. I intend to use C++ condition variables. (There is a good article on how to use C++ condition variables along with its traps and pitfalls in the following link)
I have the following constraints/conditions :-
The notifying thread need not lock on to a mutex
The notified (or the receiver) thread does some useful section but there is no critical section
The receiver thread is allowed to miss a notification if and only if it is doing useful work
There should be no spurious wakeups.
Using the above link as a guideline I put together the following piece of code
// conditionVariableAtomic.cpp
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <thread>
#include <iostream> // std::cout, std::endl
#include <thread> // std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
std::mutex mutex_;
std::condition_variable condVar;
std::atomic<bool> dataReady{false};
void waitingForWork(){
int i = 0;
while (i++ < 10)
{
std::cout << "Waiting " << std::endl;
{
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, []{ return dataReady.load(); }); // (1)
dataReady = false;
}
std::cout << "Running " << std::endl;
// Do useful work but no critical section.
}
}
void setDataReady(){
int i = 0;
while (i++ < 10)
{
std::this_thread::sleep_for (std::chrono::seconds(1));
dataReady = true;
std::cout << "Data prepared" << std::endl;
condVar.notify_one();
}
}
int main(){
std::cout << std::endl;
std::thread t1(waitingForWork);
std::thread t2(setDataReady);
t1.join();
t2.join();
std::cout << std::endl;
}
I use an atomic predicate to avoid spurious wakeups, but don't use a lock_guard in the notifying thread.
My question is:
does the above piece of code satisfy the constraints/conditions listed above?
I understand that the receiver thread cannot avoid a mutex, hence the need to use std::unique_lock<std::mutex> lck(mutex_); in the receiver. I have however limited the scope of std::unique_lock<std::mutex> lck(mutex_); i.e. put the following section of code
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, []{ return dataReady.load(); }); // (1)
dataReady = false;
inside a scope block aka { .... } so that the mutex is unlocked as soon as the wait condition is over (the receiver then does some useful work but since there is no critical section, it does not need to hold on to the mutex for the entire while loop). Could there still be consequences/side effects of this limited scoping in this context ? Or does the unique_lock<std::mutex> need to be locked for the entire while loop?
Your code has a race condition. Between checking the value of dataReady in your wait predicate and actually starting the wait, the other thread can set dataReady and call notify_one. In your example this isn't critical as you'll just miss one notify and wake up a second later on the next one.
Another race condition is that you can set dataReady to true in one thread, set dataReady back to false in the other thread and then call notify_one in the first thread, again this will cause the wait to block for longer than you intended.
You should hold the mutex in both threads when setting dataReady and using the condition variable to avoid these races.
You could avoid the second race condition by using an atomic counter instead of a boolean, incrementing it on one thread then decrementing on the other and in the predicate checking if it is non-zero.
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!!
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.
I found that std::condition_variable is very difficult to use due to spurious wakeups. So sometimes I need to set a flags such as:
atomic<bool> is_ready;
I set is_ready to true before I call notify (notify_one() or notify_all()), and then I wait:
some_condition_variable.wait(some_unique_lock, [&is_ready]{
return bool(is_ready);
});
Is there any reason that I shouldn't just do this: (Edit: Ok, this is really a bad idea.)
while(!is_ready) {
this_thread::wait_for(some_duration); //Edit: changed from this_thread::yield();
}
And if condition_variable had chosen a waiting duration (I don't know whether this is true or not), I prefer choose it myself.
You can code this either way:
Using atomics and a polling loop.
Using a condition_variable.
I've coded it both ways for you below. On my system I can monitor in real time how much cpu any given process is using.
First with the polling loop:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
std::atomic<bool> is_ready(false);
void
test()
{
std::this_thread::sleep_for(std::chrono::seconds(30));
is_ready.store(true);
}
int
main()
{
std::thread t(test);
while (!is_ready.load())
std::this_thread::yield();
t.join();
}
For me this takes 30 seconds to execute, and while executing the process takes about 99.6% of a cpu.
Alternatively with a condition_variable:
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
bool is_ready(false);
std::mutex m;
std::condition_variable cv;
void
test()
{
std::this_thread::sleep_for(std::chrono::seconds(30));
std::unique_lock<std::mutex> lk(m);
is_ready = true;
cv.notify_one();
}
int
main()
{
std::thread t(test);
std::unique_lock<std::mutex> lk(m);
while (!is_ready)
{
cv.wait(lk);
if (!is_ready)
std::cout << "Spurious wake up!\n";
}
t.join();
}
This has the exact same behavior except that during the 30 second execution, the process is taking 0.0% cpu. If you're writing an app that might execute on a battery powered device, the latter is nearly infinitely easier on the battery.
Now admittedly, if you had a very poor implementation of std::condition_variable, it could have the same inefficiency as the polling loop. However in practice such a vendor ought to go out of business fairly quickly.
Update
For grins I augmented my condition_variable wait loop with a spurious wakeup detector. I ran it again, and it did not print out anything. Not one spurious wakeup. That is of course not guaranteed. But it does demonstrate what a quality implementation can achieve.
The purpose of std::condition_variable is to wait for some condition to become true. It is not designed to be just a receiver of a notify. You might use it, for example, when a consumer thread needs to wait for a queue to become non-empty.
T get_from_queue() {
std::unique_lock l(the_mutex);
while (the_queue.empty()) {
the_condition_variable.wait(l);
}
// the above loop is _exactly_ equivalent to the_condition_variable.wait(l, [&the_queue](){ return !the_queue.empty(); }
// now we have the mutex and the invariant (that the_queue be non-empty) is true
T retval = the_queue.top();
the_queue.pop();
return retval;
}
put_in_queue(T& v) {
std::unique_lock l(the_mutex);
the_queue.push(v);
the_condition_variable.notify_one(); // the queue is non-empty now, so wake up one of the blocked consumers (if there is one) so they can retest.
}
The consumer (get_from_queue) is not waiting for the condition variable, they are waiting for the condition the_queue.empty(). The condition variable gives you the way to put them to sleep while they are waiting, simultaneously releasing the mutex and doing so in a way that avoids race conditions where you miss wake ups.
The condition you are waiting on should be protected by a mutex (the one you release when you wait on the condition variable.) This means that the condition rarely (if ever) needs to be an atomic. You are always accessing it from within a mutex.