I am currently trying to learn how to use a condition_variable for thread synchronization. For testing, I have made the demo application shown below. When I start it, it runs into a dead lock. I know the location where this happens, but I'm unable to understand why the deadlock occurs.
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true, so the main thread should not be blocked in the second pass. But it is just this what happens.
Could anybody explain why?
#include <thread>
#include <condition_variable>
#include <iostream>
bool flag = false;
std::mutex g_mutex;
std::condition_variable cv;
void threadProc()
{
std::unique_lock<std::mutex> lck(g_mutex);
while (true)
{
static int count = 0;
std::cout << "wait for flag" << ++count << std::endl;
cv.wait(lck, []() {return flag; }); // !!!It will blocked at the second round
std::cout << "flag is true " << count << std::endl;
flag = false;
lck.unlock();
}
}
int main(int argc, char *argv[])
{
std::thread t(threadProc);
while (true)
{
static int count = 0;
{
std::lock_guard<std::mutex> guard(g_mutex); // !!!It will blocked at the second round
flag = true;
std::cout << "set flag " << ++count << std::endl;
}
cv.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
t.join();
return 0;
}
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true.
Um..., yes..., Just to be absolutely clear, cv.wait(lck, f) does this:
while(! f()) {
cv.wait(lck);
}
And each call to cv.wait(lck) will;
unlock lck,
wait until some other thread calls cv.notify_one() or cv.notify_all(),
re-lock lck, and then
return.
You can fix the problem by moving the unique_lock(...) statement inside the while loop. As it is now, you're attempting to unlock lck on round 2 but it was not in a locked state, since, after round 1 you never locked it again.
Related
I am working with condition_variable on Visual studio 2019. The condition_variable.wait_for() function returns std::cv_status::no_timeout without any notification.
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
std::condition_variable cv;
std::mutex mtx;
bool called = false;
void printThread()
{
std::unique_lock<std::mutex> lck(mtx);
while (std::cv_status::timeout == cv.wait_for(lck, std::chrono::seconds(1)))
{
std::cout << "*";
}
std::cout << "thread exits" << std::endl;
}
int main()
{
std::thread th(printThread);
th.join();
std::cout << "program exits" << std::endl;
}
I think the code will never exit and keep printing *, but it exits after printing some *.
Here is the output:
********************************************************************thread exits
program exits
Why does this happen? Is it the so-called "spurious wakeups"?
Yes, it's a "spurious wakeup". This is explained on cppreference.com's reference page for wait_for:
It may also be unblocked spuriously. When unblocked, regardless of the
reason, lock is reacquired and wait_for() exits.
Translation: there are gremlins in your computer. They get grumpy, occasionally. And if they do get grumpy, wait_for returns before the requested timeout expires. And when that happens:
Return value
std::cv_status::timeout if the relative timeout specified by
rel_time expired, std::cv_status::no_timeout otherwise.
And that seems to be exactly what you're seeing. The C++ standard permits a C++ implementation to return from wait_for prematurely, for arbitrary reasons, and unless you do return from wait_for when the timeout expires, no_timeout is what you get.
You might be wondering why wait_for (and several other similar functions) may decide to throw up their hands and return "spuriously". But that would be a different question...
As already explained, it is waking up due spurious wakeup. Such thing make the function wait_for completely useless. The solution is to use the wait_until saving the current time before entering the wait loop:
int count = 1;
std::mutex mutex;
std::condition_variable condition_variable;
void wait() {
std::unique_lock<std::mutex> lock(mutex);
count--;
int timeout = 1000; // 1 second
std::chrono::time_point<std::chrono::system_clock> timenow =
std::chrono::system_clock::now();
while(count < 0) {
std::cv_status status = condition_variable.wait_until(
lock,
timenow + std::chrono::duration<double,std::ratio<1,1000>>(timeout));
if ( std::cv_status::timeout == status) {
count++;
break;
}
}
}
I have a thread that is doing "work", it is supposed to report progress when conditional variable notifies it. This thread is waiting for conditional variables.
Other thread is waiting for a x amount of milliseconds and then notifies conditional variable to proceed.
I have 5 conditional variables (this is an exercise for school) and once each gets notified work progress is supposed to be reported:
Problem im having is that thread 2, the one that is supposed to notify thread 1, goes through all 5 checkPoints and notifies only once in the end. So I end up in a situation where progress is at 20% in the end and thread 1 is waiting for another notify but thread 2 has finished all notifies.
Where is flaw in my implementation of this logic?
Code below:
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
class Program {
public:
Program() {
m_progress = 0;
m_check = false;
}
bool isWorkReady() { return m_check; }
void loopWork() {
cout << "Working ... : " << endl;
work(m_cv1);
work(m_cv2);
work(m_cv3);
work(m_cv4);
work(m_cv5);
cout << "\nFinished!" << endl;
}
void work(condition_variable &cv) {
unique_lock<mutex> mlock(m_mutex);
cv.wait(mlock, bind(&Program::isWorkReady, this));
m_progress++;
cout << " ... " << m_progress * 20 << "%" << endl;
m_check = false;
}
void checkPoint(condition_variable &cv) {
lock_guard<mutex> guard(m_mutex);
cout << " < Checking >" << m_progress << endl;
this_thread::sleep_for(chrono::milliseconds(300));
m_check = true;
cv.notify_one();
}
void loopCheckPoints() {
checkPoint(m_cv1);
checkPoint(m_cv2);
checkPoint(m_cv3);
checkPoint(m_cv4);
checkPoint(m_cv5);
}
private:
mutex m_mutex;
condition_variable m_cv1, m_cv2, m_cv3, m_cv4, m_cv5;
int m_progress;
bool m_check;
};
int main() {
Program program;
thread t1(&Program::loopWork, &program);
thread t2(&Program::loopCheckPoints, &program);
t1.join();
t2.join();
return 0;
}
The loopCheckPoints() thread holds a lock for some time, sets m_check then releases the lock and immediately goes on to grab the lock again. The loopWork() thread may not have woken up in between to react to the m_check change.
Never hold locks for long times. Be as quick as possible. If you can't get the program to work without adding sleeps, you have a problem.
One way to fix this would be to check that the worker has actually set m_check back to false:
void work(condition_variable& cv) {
{ // lock scope
unique_lock<mutex> mlock(m_mutex);
cv.wait(mlock, [this] { return m_check; });
m_progress++;
cout << " ... " << m_progress * 20 << "%" << endl;
m_check = false;
}
// there's no need to hold the lock when notifying
cv.notify_one(); // notify that we set it back to false
}
void checkPoint(condition_variable& cv) {
// if you are going to sleep, do it without holding the lock
// this_thread::sleep_for(chrono::milliseconds(300));
{ // lock scope
lock_guard<mutex> guard(m_mutex);
cout << "<Checking> " << m_progress << endl;
m_check = true;
}
cv.notify_one(); // no need to hold the lock here
{
// Check that m_check is set back to false
unique_lock<mutex> mlock(m_mutex);
cv.wait(mlock, [this] { return not m_check; });
}
}
Where is flaw in my implementation of this logic?
cv.notify_one does not require, that the code after cv.wait(mlock, bind(&Program::isWorkReady, this)); continues immediatly, so it is perfectly valid that multiple checkPoint are exectued, before the code continues after cv.wait.
But after you the cv.wait you set m_check = false; to false, so if there is no further checkPoint execution remaining, that will set m_check = true;, your work function becomes stuck.
Instead of m_check being a bool you could think about making it a counter, that is incremented in checkPoint and decremented in work.
I ran into this interesting behavior of spurious wake-ups. Consider this simple demo code:
#include <iostream>
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
using namespace std; // I know
using namespace std::chrono;
using namespace std::chrono_literals;
mutex mtx; // used for cv and synchronized access to counter
condition_variable cv;
int counter = 0; // (1)
bool keep_running = true; // flag for signaling an exit condition
int main()
{
// thread that decrements counter every time it is woken up and the counter is > 0
thread t([&] {
while (keep_running)
{
unique_lock<mutex> lock(mtx);
cv.wait(lock, [&] {
cout << "Woken up" << endl;
return !keep_running || counter > 0;
});
if (!keep_running) { // check for exit condition
break;
}
--counter;
}
});
this_thread::sleep_for(1s); // some work
unique_lock<mutex> lock(mtx);
counter = 5; // set the counter
cout << "Notifying" << endl;
lock.unlock();
cv.notify_one(); // wake the thread up
this_thread::sleep_for(1s); // some more work
cout << "Exiting" << endl;
lock.lock();
keep_running = false; // ask the thread to exit
lock.unlock();
cv.notify_one(); // wake up one last time
t.join(); // join and exit
cout << "Counter: " << counter << endl;
}
Compiling with g++ cv_test.cpp -o cv_test -pthread and executing produces the following output:
Woken up
Notifying
Woken up
Woken up
Woken up
Woken up
Woken up
Woken up
Exiting
Woken up
Counter: 0
Notice that I call notify_one only once, but the thread is woken up continuously until the predicate returns false. No matter what the counter is initialized to, the thread is woken up until it goes to 0 (which is the predicate).
Even at the beginning of the execution, the thread is woken up once as if to "check" that the predicate returns false. Consequently, if I initialize the counter to a positive value: int counter = 3; // (1), the spurious wake-ups seem to "ensure" the predicate returns false even before the first notify_one is called.
My question is, is this really a feature and can it be relied upon? Is there any documentation on this behavior?
PS. I know this worker thread can be fixed by a simple check for the counter (read: work queue length) before waiting on the condition_variable, but this kind of predictable behavior of the spurious wake-ups intrigued me.
I realized immediately after I posted this question that this overload of condition_variable::wait (as described here) is equivalent to:
while (!pred()) {
wait(lock);
}
I was imagining it being equivalent to a do while instead. So really there are no spurious wake-ups here. Just that it wasn't waiting at all until the predicate returned false.
I got code like below:
std::mutex mutex;
std::condition_variable condition_variable;
bool finish = false;
void test() {
while (true) {
std::unique_lock<std::mutex> lock(mutex);
condition_variable.wait(lock);
if (finish){
std::cout << "finish detected" << std::endl;
return;
}
}
}
int main() {
std::thread t(test);
std::unique_lock<std::mutex> lock(mutex);
finish = true;
lock.unlock();
//sleep(1);
condition_variable.notify_all();
std::cout << "notify_all" << std::endl;
t.join();
}
and the code will not terminate when running, the notify_all log will print, but the finish detected log will not. If I use debug mode, the code will terminate successfully, so I cannot provide a clear clue about the status of the running code, but if I release the sleep(1), the code will works.
So can anyone help what's wrong with my code?
Condition variables have no state, so that when you signal it and there are no waiters the signal is lost. It happens in your code when condition_variable.notify_all() executes before condition_variable.wait(lock);.
The code doesn't use correct method to wait on the condition variable. The correct method is:
Lock the mutex.
Check the condition (finish here).
If the condition is not satisfied, wait on the condition variable. The condition variable can be woken up spuriously. Goto 2.
Fix:
void test() {
std::unique_lock<std::mutex> lock(mutex);
while(!finish)
condition_variable.wait(lock);
std::cout << "finish detected" << std::endl;
}
There is another overload of condition_variable::wait that does the while loop for you:
void test() {
std::unique_lock<std::mutex> lock(mutex);
condition_variable.wait(lock, [&finish]{ return finish; });
std::cout << "finish detected" << std::endl;
}
I'm trying to run a thread with a function from a class member and use conditional variable to wait until the main thread signals and add the times the thread got signaled. Here is the code:
// Example program
#include <iostream>
#include <string>
#include <atomic>
#include <thread>
#include <unistd.h>
#include <mutex>
#include <condition_variable>
std::mutex m_mutex;
std::condition_variable m_condVar;
char stop =0;
class dummclass
{
std::thread dummclass_thread;
int alarms;
public:
dummclass() :
alarms(0),
dummclass_thread(std::thread(&dummclass::dummclassThreadProc, this))
{
}
~dummclass()
{
std::cout<<"Alarms: "<<alarms<<"\n";
//signal thread before joining
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
stop=1;
}
m_condVar.notify_one();
dummclass_thread.join();
}
private:
void dummclassThreadProc()
{
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout<<"thread waiting\n";
m_condVar.wait(mlock);
std::cout<<"thread done waiting\n";
}
sleep(1);
std::unique_lock<std::mutex> mlock(m_mutex);
while (!stop)//!stop_dummclass.load())
{
std::cout<<"got mutex\n";
m_condVar.wait(mlock);
std::cout<<"wait done\n";
{
std::cout<<"got one\n";
alarms++;
}
}
std::cout<<"end loop\n";
}
};
int main()
{
dummclass *x = new dummclass;
sleep(3);
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
}
m_condVar.notify_one();
std::cout<<"done waiting\n";
sleep(3);
for(int i=0;i<13;i++)
{
{
std::cout<<"signal "<<i<<"\n";
std::lock_guard<std::mutex> lock_guard(m_mutex);
}
m_condVar.notify_one();
}
delete x;
}
The weird part is that the initial waiting and signaling that are outside of the loops actually work ok. I don't understand what mistake I do so that the while loop inside the class thread doesn't catch any signal from the main thread but it catches a signal from the destructor of the dummyclass when I delete it. This is the output:
thread waiting
done waiting
thread done waiting
got mutex
signal 0 signal 1 signal 2 signal 3 signal 4 signal 5 signal 6 signal 7 signal
8 signal 9 signal 10 signal 11 signal 12
Alarms: 0
wait done
got one end loop
EDIT: It seems that adding a 1 second sleep in the main() for loop solves the problem. Is it possible that the for loop gets the mutex before wait() manages to wake and lock the mutex ?
for(int i=0;i<13;i++)
{
{std::cout<<"signal "<<i<<"\n";
std::lock_guard<std::mutex> lock_guard(m_mutex);}
m_condVar.notify_one();
sleep(1);
}
Can someone please show me what is wrong ?
Thanks.
The object doing the waiting gets deleted before it processes the signal. Since the delete happens on a known to be running thread it has a fair chance to get executed first. In particular it is also likely to reacquire the lock again: Since the notify_one() is done while the mutex is locked the wait()ing thread cannot acquire it and will go back to sleep, waiting for the mutex to be released. That gives the signalling thread an opportunity to reacquire the lock. The only forced synchronizqtion causing the signalling thread to wait is the join() and it does give the waiting thread a chance to execute.
Note that signals of condition variables are not something delivered to the waiting thread. They are essentially wake-up calls. The waiting thread will wake up eventually once a signal is delivered. However, many signals can be delivered before it actually does so.
I don't understand what mistake I do so that the while loop inside the
class thread doesn't catch any signal from the main thread
Even though multiple notifications are sent the thread may only receive a single notification.
The notify_one() call does
not mean that the current thread will stop and wait for another thread.
It just means that the other thread must wake up at some point because something may have happened that it would be interested in.
Also note that std::condition_variable::wait could experience a spurious wakeup, so it might not even have anything to do or have received a 'real' signal.
The solution is to provide a predicate as a parameter to the wait() call. The predicate can then check if there is a signal (via a variable provided for this purpose and only changed under lock) and may also check if the program has been stopped.
In the updated program below I've added a predicate to the wait and made some minor changes. The program only notifies under lock, but you might choose not to.
// Example program - modified
#include <iostream>
#include <string>
#include <atomic>
#include <thread>
//#include <unistd.h>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex m_mutex;
std::condition_variable m_condVar;
bool signal_waiting{false};
bool stop{false};
class dummclass
{
int alarms{};
std::thread dummclass_thread{[this](){dummclassThreadProc(); }};
public:
~dummclass()
{
std::cout << "Alarms: " << alarms << "\n";
//signal thread before joining
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
stop = 1;
m_condVar.notify_one();
}
dummclass_thread.join();
}
private:
void dummclassThreadProc()
{
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout << "thread waiting\n";
m_condVar.wait(mlock);
std::cout << "thread done waiting\n";
}
std::this_thread::sleep_for(std::chrono::seconds{1});
while(!stop)//!stop_dummclass.load())
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout << "got mutex\n";
//m_condVar.wait(mlock);
m_condVar.wait(mlock, [](){return signal_waiting || stop; });
if(stop)
break;
std::cout << "wait done\n";
std::cout << "got one\n";
alarms++;
signal_waiting = false;
m_condVar.notify_one();
}
std::cout << "end loop\n";
}
};
int main()
{
dummclass *x = new dummclass;
//sleep(3);
std::this_thread::sleep_for(std::chrono::seconds{1});
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
m_condVar.notify_one();
}
std::cout << "done waiting\n";
//sleep(3);
std::this_thread::sleep_for(std::chrono::seconds{1});
for(int i = 0; i<13; i++)
{
{
std::cout << "signal " << i << "\n";
std::unique_lock<std::mutex> lock(m_mutex);
m_condVar.wait(lock, [](){return !signal_waiting ; });
signal_waiting = true;
m_condVar.notify_one();
}
}
delete x;
}