in the below code I am waiting inside function waitingForWork()
on a condition variable, butdoTheCleanUp()
is never called.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool stop=false;
void stopTheWait()
{
sleep(5);
printf("stopping the wait.. \n\n");
std::lock_guard<std::mutex> lck(mtx);
stop = true;
cv.notify_all();
}
void doTheCleanUp()/* is never called*/ {
printf("clean up... \n\n");
}
void waitingForWork(){
printf("wait for ever... \n\n");
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, []{ return stop;});
doTheCleanUp();
printf("clean Up Done, now end wait... \n\n");
}
int main()
{
printf("in main... \n");
std::unique_lock<std::mutex> lck(mtx);
std::thread t1(stopTheWait);
waitingForWork();
printf("exiting main...\n");
sleep(1);
return 0;
}
main()
is locking the std::mutex
and then calling waitingForWork()
in the same thread, which tries to lock the std::mutex
again. This is undefined behavior:
If
lock
is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. An implementation that can detect the invalid usage is encouraged to throw astd::system_error
with error conditionresource_deadlock_would_occur
instead of deadlocking.
There is no good reason for main()
to obtain that initial lock, get rid of it:
int main()
{
printf("in main... \n");
//std::unique_lock<std::mutex> lck(mtx); // <-- HERE
std::thread t1(stopTheWait);
waitingForWork();
printf("exiting main...\n");
sleep(1);
return 0;
}
Note that in general, if you must lock a mutex multiple times in the same thread, you need to use std::recursive_mutex
instead:
A calling thread owns a
recursive_mutex
for a period of time that starts when it successfully calls eitherlock
ortry_lock
. During this period, the thread may make additional calls tolock
ortry_lock
. The period of ownership ends when the thread makes a matching number of calls tounlock
.
Also note that you need to call t1.join()
or t1.detach()
before t1
goes out of scope and is destroyed, otherwise its destructor will abortively terminate the calling process:
If
*this
has an associated thread (joinable() == true
),std::terminate()
is called.