For a detached thread we can't use joinable() and using bool variables seems to be not the correct way. Is there a way to check if the detached thread is still alive and running?
There are a few ways to tackle this. If you're set on threads, then you can use a std::future<void> to detect when it has exited:
std::promise<void> promised_thread_exit;
std::future<void> thread_exited = promised_thread_exit.get_future();
std::thread(
[] (std::promise<void> promised_thread_exit)
{
promised_thread_exit.set_value_at_thread_exit();
DoBackgroundWork();
},
std::move(promised_thread_exit));
thread.detach();
// later...
thread_exited.get();
However, this seems like lot of work. A std::thread is quite a low level primitive. If the goal is just to perform some work in the background, then std::async is a better option:
std::future<void> work_complete = std::async(std::launch::async, DoBackgroundWork());
// later...
work_complete.get();
In either case, if you need to check on the work's state without blocking, you can do so by waiting on the future with a timeout of 0:
using namespace std::chrono_literals;
//...
if (work_complete.wait_for(0s) == std::future_status::ready)
{
// work has finished
}
That being said, checking the state like this is rarely necessary. If it seems to be, then you should consider if there's a simpler alternative.
You can use a std::condition_variable to notify your main thread when the detached one is finished:
#include <iostream>
#include <mutex>
#include <thread>
int main()
{
std::mutex mutex;
std::condition_variable cv;
std::thread t([&]() {
std::cout << "Wait" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(mutex);
std::cout << "Thread end" << std::endl;
cv.notify_all();
});
t.detach();
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
std::cout << "Main end" << std::endl;
return 0;
}
Related
I am learning C++ threads and i don't understand unique_lock mechanism very well. I reed This Link with Conditional variable, and more examples here but still I have my confusions:
1- So my question clearly is, doesn't unique_lock protect the mutual exclusion? I see in some examples when we use it on a shared mutex, the second thread cannot enter to that area which what I expect. But in this example as you see the output, all the threads can pass this line: std::unique_lockstd::mutex lck(mtx); is it just declaration or mutex gets locked as it declared?
2- why does the .lock() cause abort error? If I comment out that line all the threads starts in a row as you see in the screen shot output. I expect only thread0 pass the std::unique_lock<std::mutex> lck(mtx); it should be locked for other threads
Thanks
#include <mutex>
using namespace std;
condition_variable cv;
bool ready = false;
mutex mtx;
void print_id(int id) {
// why all the threads can pass this line?
std::unique_lock<std::mutex> lck(mtx);
//i knew about the concept of two times locking, just thought there
//is something wrong with the constructor or i dont understand
lck.lock(); // Having this line gives me abort.
std::cout << "thread Starts: " << id << '\n';
while (!ready)
cv.wait(lck);
// ...
std::cout << "thread Ends: " << id << '\n';
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}
void main()
{
std::thread threads[5];
// spawn 10 threads:
for (int i = 0; i < 5; ++i)
{
this_thread::sleep_for(chrono::milliseconds(2000));
threads[i] = std::thread(print_id, i);
}
std::cout << "10 threads ready to race...\n";
go(); // go!
for (auto& th : threads) th.join();
}
std::unique_lock is an RAII type. When an object of that type is constructed, it locks the mutex that was passed to it, and upon destruction it unlocks the mutex, so you have scope level locking and unlocking.
All that means is that when you do lck.lock(); you are trying to lock a mutex you have already locked by creating lck. std::unique_lock::lock() will throw an exception when you do this, and it is that uncaught exception that is causing abort() to be called.
I was trying to figure out the data race theme, and I made this code. Here we work with the shared element wnd. I thought that by putting lock in the while loop, I would prohibit the th1 thread from working with wnd, but this did not happen and I see an unobstructed output of the th1 thread.
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
int main()
{
bool wnd = true;
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
std::thread th1([&]() {
int i = 0;
while (true)
{
++i;
if (wnd)
std::cout << i << " WND TRUE" << std::endl;
else
std::cout << i << " WND FALSE" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
while (true)
{
lock.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
if (wnd)
wnd = false;
else
wnd = true;
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
th1.join();
return 0;
}
To tell the truth, I was hoping to see that the th1 thread stops printing for 2+-seconds at a time when the main thread is inside the lock section.
You are not using the mutex and specially std::unique_lock properly.
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
int main()
{
bool wnd = true;
std::mutex mutex;
std::thread th1{[&]() {
for (int i = 0; i<10000; ++i)
{ std::unique_lock<std::mutex> lock(mutex);
std::cout << i << "\tWND\t " << std::boolalpha << wnd << std::endl;
};
}};
for (int i = 0; i<30; ++i)
{ std::unique_lock<std::mutex> lock(mutex);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
wnd = !wnd;
};
th1.join();
}
std::unique_lock uses its constructor operand as a resource whose acquisition is lock and release is unlock. It is designed to use RAII as a means of guaranteeing correct lock/unlock sequences on mutexes. a defered lock only means the mutex is not locked at the begining of lifespan of the std::unique_lock and it is not the usual use case. You can manually lock/unlock the mutex, but that generally leads to less maintainable, more error-prone code.
Keep in mind that if the threads involved are not racing over the ownership of the mutex, neither waits for the other; in your original prorgram, the worker thread did not touch the mutex. But in the program above, both threads are competing to lock the mutex; winner gets a chance to continue what he wants, and the loser has to wait until the mutex is unlocked - so that he can take its ownership.
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.
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;
}
Typical usages of condition variables look like this (see code below): http://en.cppreference.com/w/cpp/thread/condition_variable.
However, it seems that the main thread could potentially call notify_one before the worker thread calls wait, which would result in a deadlock. Am I mistaken? If not, what is the usual workaround for this?
#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();
}
Note the definition of wait that uses a condition (the only wait you should ever be using):
while (!pred()) {
wait(lock);
}
if notify was already fired it means the condition is already true (that was sequenced before notify_one in the signalling thread). So when the receiver takes the mutex and looks at pred(), it will be true and it will proceed.