I'm confused about conditions_variables and how to use them (safely). In my application I've a class that makes a gui-thread but while the gui is constructed by the gui-thread, the main thread needs to wait.
The situation is the same as for the function below. The main thread makes a mutex, lock and condition_variable. It then makes the thread. While this worker thread has not passed a certain point (here printing the numbers), the main thread is not allowed to continue (i.e. has to wait for all numbers being printed).
How do I use condition_variables correctly in this context? Also, I've read that spontaneous wake-ups are an issue. How can I handle them?
int main()
{
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
std::condition_variable convar;
auto worker = std::thread([&]{
/* Do some work. Main-thread can not continue. */
for(int i=0; i<100; ++i) std::cout<<i<<" ";
convar.notify_all(); // let main thread continue
std::cout<<"\nworker done"<<std::endl;
});
// The main thread can do some work but then must wait until the worker has done it's calculations.
/* do some stuff */
convar.wait(lck);
std::cout<<"\nmain can continue"<<std::endl; // allowed before worker is entirely finished
worker.join();
}
Typically you'd have some observable shared state on whose change you block:
bool done = false;
std::mutex done_mx;
std::condition_variable done_cv;
{
std::unique_lock<std::mutex> lock(done_mx);
std::thread worker([&]() {
// ...
std::lock_guard<std::mutex> lock(done_mx);
done = true;
done_cv.notify_one();
});
while (true) { done_cv.wait(lock); if (done) break; }
// ready, do other work
worker.join();
}
Note that you wait in a loop until the actual condition is met. Note also that access to the actual shared state (done) is serialized via the mutex done_mx, which is locked whenever done is accessed.
There's a helper member function that performs the condition check for you so you don't need the loop:
done_cv.wait(lock, [&]() { return done; });
Related
I am trying to use an std::condition_variable from C++11 for a data transaction between between UI thread & worker thread.
Situation:
m_calculated_value is a value which calculated after a complex logic. This is required on a trigger of a event from the UI thread. UI thread calls MyClass::GetCalculatedValue to fetch the value of m_calculated_value which needs to be calculated by the worker thread function that is MyClass::ThreadFunctionToCalculateValue.
Code:
std::mutex m_mutex;
std::condition_variable m_my_condition_variable;
bool m_value_ready;
unsigned int m_calculated_value;
// Gets called from UI thread
unsigned int MyClass::GetCalculatedValue() {
std::unique_lock<std::mutex> lock(m_mutex);
m_value_ready = false;
m_my_condition_variable.wait(lock, std::bind(&MyClass::IsValueReady, this));
return m_calculated_value;
}
bool MyClass::IsValueReady() {
return m_value_ready;
}
// Gets called from an std::thread or worker thread
void MyClass::ThreadFunctionToCalculateValue() {
std::unique_lock<std::mutex> lock(m_mutex);
m_calculated_value = ComplexLogicToCalculateValue();
m_value_ready = true;
m_my_condition_variable.notify_one();
}
Problem:
But the problem is that m_my_condition_variable.wait never returns.
Question:
What am I doing wrong here?
Is it a correct approach to make UI thread wait on a condition variable signal from worker thread? How do I get out of a situation where the condition_variable never triggers due to an error in the worker thread function? Is there a way I can somehow use a timeout here?
Trying to understand how it works:
I see in many examples they use a while loop checking the state of a boolean variable around a condition_var.wait. Whats the point of loop around on a variable? Cant I expect m_my_condition_variable to return out of wait when notify_one is called from other thread ?
What is most likely to happen:
Your worker thread owns and holds the mutex until it's done with the calculation. The main thread has to wait until it can acquire the lock. The worker will signal the CV before it releases the lock (in the destructor), by which time no other thread that would want to wait on the condition variable could have been acquired the lock that it still occupied by the notifying thread. Therefore the other thread never got a chance to wait on the condition variable at the time it gets notified as it just managed to acquire the lock after the notification event took place, causing it to wait infinitely.
The solution would be to remove the lock-acquisition in MyClass::ThreadFunctionToCalculateValue(), it is not required there at all, or at least, shouldn't be.
But anyways, why do you want to re-invent the wheel? For such problems, std::future has been created:
auto future = std::async(std::launch::async, ComplexLogicToCalculateValue);
bool is_ready = future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
auto result = future.get();
Here, you can easily define timeouts, you don't have to worry about condition_variables and alike.
Cant I expect m_my_condition_variable to return out of wait when notify_one is called from other thread ?
No, not exclusively. Spurious wakeups still may occur.
Take a look at this example here:
http://en.cppreference.com/w/cpp/thread/condition_variable
Changes to the code in question noted in comments in the example code below. You might want to consider using the same "handshake" as used in the cppreference.com example to synchronize when it's safe to calculate a new value (the UI thread has a wait / notify, the worker thread has a notify / wait).
Before condition variable wait, the lock needs to be locked. The wait will unlock, wait for a notify, then lock and with the predicate function, check for ready and if not ready (spurious wake up), repeat the cycle.
Before notify_one, the lock should be unlocked, else the wait gets woke up, but fails to get a lock (since it's still locked).
std::mutex m_mutex;
std::condition_variable m_my_condition_variable;
bool m_value_ready = false; // init to false
unsigned int m_calculated_value;
// Gets called from UI thread
unsigned int MyClass::GetCalculatedValue() {
std::unique_lock<std::mutex> lock(m_mutex);
m_my_condition_variable.wait(lock, std::bind(&MyClass::IsValueReady, this));
m_value_ready = false; // don't change until after wait
return m_calculated_value;
} // auto unlock after leaving function scope
bool MyClass::IsValueReady() {
return m_value_ready;
}
// Gets called from an std::thread or worker thread
void MyClass::ThreadFunctionToCalculateValue() {
std::unique_lock<std::mutex> lock(m_mutex);
m_calculated_value = ComplexLogicToCalculateValue();
m_value_ready = true;
lock.unlock(); // unlock before notify
m_my_condition_variable.notify_one();
}
or alternative:
// Gets called from an std::thread or worker thread
void MyClass::ThreadFunctionToCalculateValue() {
{ // auto unlock after leaving block scope
std::lock_guard<std::mutex> lock(m_mutex);
m_calculated_value = ComplexLogicToCalculateValue();
m_value_ready = true;
} // unlock occurs here
m_my_condition_variable.notify_one();
}
I am using std::conditional_variable for timing a signal in a multi-threaded program for controlling the flow of various critical sections. The program works but during exit I am compelled to use a predicate (kill_ == true) to avoid destroying of threads which are still waiting on the std::conditional_variable ::wait(). I don't know if its the proper way to destroy all the waiting threads, advice solicited. Here's a code snippet:
class timer
{
// ...
timer(std::shared_ptr<parent_object> parent,const bool& kill)
:parent_(parent),kill_(kill){}
private:
std::condition_variable cv_command_flow_;
std::mutex mu_flow_;
const bool& kill_;
std::shared_ptr<parent_object> parent_;
};
void timer::section()
{
auto delay = get_next_delay();
std::unique_lock<std::mutex> lock(mu_flow_);
std::cv_command_flow_.wait_until(lock,delay,[] { return kill_ == true; });
if( kill_) return;
parent_->trigger();
std::cv_command_exec_.notify_all();
}
This is generally how I handle the destruction of my waiting threads. You'll want a code section such as this where you want to perform clean up (in a class destructor, the main thread before process exit, etc.):
{
std::lock_guard<std::mutex> lock(mu_flow);
kill_ = true;
}
cv_command_exec_.notify_all();
thread1.join();
I'm assuming that timer::section() was executing within some thread std::thread thread1.
Ownership duration of the mutex is controlled by the scoped block. You'll want the mutex held only when you set kill_ = true and released before you call .notify_all() (otherwise the woken thread might find the lock still held and go back to sleep).
Of course, std::unique_lock usage would look like:
std::unique_lock<std::mutex> lock(mu_flow);
kill_ = true;
lock.unlock();
cv_command_exec_.notify_all();
thread1.join();
It's personal preference to a large degree ... both code sections accomplish the same task.
This is a separate question but related to the previous question I asked here
I am using an std::thread in my C++ code to constantly poll for some data & add it to a buffer. I use a C++ lambda to start the thread like this:
StartMyThread() {
thread_running = true;
the_thread = std::thread { [this] {
while(thread_running) {
GetData();
}
}};
}
thread_running is an atomic<bool> declared in class header. Here is my GetData function:
GetData() {
//Some heavy logic
}
Next I also have a StopMyThread function where I set thread_running to false so that it exits out of the while loop in the lambda block.
StopMyThread() {
thread_running = false;
the_thread.join();
}
As I understand, I can pause & resume the thread using a std::condition_variable as pointed out here in my earlier question.
But is there a disadvantage if I just use the std::atomic<bool> thread_running to execute or not execute the logic in GetData() like below ?
GetData() {
if (thread_running == false)
return;
//Some heavy logic
}
Will this burn more CPU cycles compared to the approach of using an std::condition_variable as described here ?
A condition variable is useful when you want to conditionally halt another thread or not. So you might have an always-running "worker" thread that waits when it notices it has nothing to do to be running.
The atomic solution requires your UI interaction synchronize with the worker thread, or very complex logic to do it asynchronously.
As a general rule, your UI response thread should never block on non-ready state from worker threads.
struct worker_thread {
worker_thread( std::function<void()> t, bool play = true ):
task(std::move(t)),
execute(play)
{
thread = std::async( std::launch::async, [this]{
work();
});
}
// move is not safe. If you need this movable,
// use unique_ptr<worker_thread>.
worker_thread(worker_thread&& )=delete;
~worker_thread() {
if (!exit) finalize();
wait();
}
void finalize() {
auto l = lock();
exit = true;
cv.notify_one();
}
void pause() {
auto l = lock();
execute = false;
}
void play() {
auto l = lock();
execute = true;
cv.notify_one();
}
void wait() {
Assert(exit);
if (thread)
thread.get();
}
private:
void work() {
while(true) {
bool done = false;
{
auto l = lock();
cv.wait( l, [&]{
return exit || execute;
});
done = exit; // have lock here
}
if (done) break;
task();
}
}
std::unique_lock<std::mutex> lock() {
return std::unique_lock<std::mutex>(m);
}
std::mutex m;
std::condition_variable cv;
bool exit = false;
bool execute = true;
std::function<void()> task;
std::future<void> thread;
};
or somesuch.
This owns a thread. The thread repeatedly runs task so long as it is in play() mode. If you pause() the next time task() finishes, the worker thread stops. If you play() before the task() call finishes, it doesn't notice the pause().
The only wait is on destruction of worker_thread, where it automatically informs the worker thread it should exit and it waits for it to finish.
You can manually .wait() or .finalize() as well. .finalize() is async, but if your app is shutting down you can call it early and give the worker thread more time to clean up while the main thread cleans things up elsewhere.
.finalize() cannot be reversed.
Code not tested.
Unless I'm missing something, you already answered this in your original question: You'll be creating and destroying the worker thread each time it's needed. This may or may not be an issue in your actual application.
There's two different problems being solved and it may depend on what you're actually doing. One problem is "I want my thread to run until I tell it to stop." The other seems to be a case of "I have a producer/consumer pair and want to be able to notify the consumer when data is ready." The thread_running and join method works well for the first of those. The second you may want to use a mutex and condition because you're doing more than just using the state to trigger work. Suppose you have a vector<Work>. You guard that with the mutex, so the condition becomes [&work] (){ return !work.empty(); } or something similar. When the wait returns, you hold the mutex so you can take things out of work and do them. When you're done, you go back to wait, releasing the mutex so the producer can add things to the queue.
You may want to combine these techniques. Have a "done processing" atomic that all of your threads periodically check to know when to exit so that you can join them. Use the condition to cover the case of data delivery between threads.
The real code is way more complex but I think I managed to make a mcve.
I'm trying to do the following:
Have some threads do work
Put them ALL into a pause state
Wake up the first of them, wait for it to finish, then wake up the second one, wait for it to finish, wake up the third one.. etc..
The code I'm using is the following and it seems to work
std::atomic_int which_thread_to_wake_up;
std::atomic_int threads_asleep;
threads_asleep.store(0);
std::atomic_bool ALL_THREADS_READY;
ALL_THREADS_READY.store(false);
int threads_num = .. // Number of threads
bool thread_has_finished = false;
std::mutex mtx;
std::condition_variable cv;
std::mutex mtx2;
std::condition_variable cv2;
auto threadFunction = [](int my_index) {
// some heavy workload here..
....
{
std::unique_lock<std::mutex> lck(mtx);
++threads_asleep;
cv.notify_all(); // Wake up any other thread that might be waiting
}
std::unique_lock<std::mutex> lck(mtx);
bool all_ready = ALL_THREADS_READY.load();
size_t index = which_thread_to_wake_up.load();
cv.wait(lck, [&]() {
all_ready = ALL_THREADS_READY.load();
index = which_thread_to_wake_up.load();
return all_ready && my_index == index;
});
// This thread was awaken for work!
.. do some more work that requires synchronization..
std::unique_lock<std::mutex> lck2(mtx2);
thread_has_finished = true;
cv2.notify_one(); // Signal to the main thread that I'm done
};
// launch all the threads..
std::vector<std::thread> ALL_THREADS;
for (int i = 0; i < threads_num; ++i)
ALL_THREADS.emplace_back(threadFunction, i);
// Now the main thread needs to wait for ALL the threads to finish their first phase and go to sleep
std::unique_lock<std::mutex> lck(mtx);
size_t how_many_threads_are_asleep = threads_asleep.load();
while (how_many_threads_are_asleep < threads_num) {
cv.wait(lck, [&]() {
how_many_threads_are_asleep = threads_asleep.load();
return how_many_threads_are_asleep == numThreads;
});
}
// At this point I'm sure ALL THREADS ARE ASLEEP!
// Wake them up one by one (there should only be ONE awake at any time before it finishes his computation)
for (int i = 0; i < threads_num; i++)
{
which_thread_to_wake_up.store(i);
cv.notify_all(); // (*) Wake them all up to check if they're the chosen one
std::unique_lock<std::mutex> lck2(mtx2);
cv2.wait(lck, [&]() { return thread_has_finished; }); // Wait for the chosen one to finish
thread_has_finished = false;
}
I'm afraid that the last notify_all() call (the one I marked with (*)) might cause the following situation:
all threads are asleep
all threads are awaken from the main thread by calling notify_all()
the thread which has the right index finishes the last computation and releases the lock
ALL THE OTHER THREADS HAVE BEEN AWAKENED BUT THEY HAVEN'T CHECKED THE ATOMIC VARIABLES YET
the main thread issues a second notify_all() and THIS GETS LOST (since the threads are ALL awakened yet, they haven't simply checked the atomics yet)
Could this ever happen? I couldn't find any wording for notify_all() if its calls are somehow buffered or the order of synchronization with the functions that actually check the condition variables.
As per the docs on (notify_all)
notify_all is only one half of the requirements to continue a thread. The condition statement has to be true as well. So there has to be a traffic cop designed to wake up the first, wake up the second, wake up the third. The notify function tells the thread to check that condition.
My answer is more high level than code specific but I hope that helps.
The situation you consider can happen. If your working threads (slaves) are awaken when the notify_all() is invoked, then they will probably miss that signal.
One way to prevent this situation is to lock mtx before cv.notify_all() and unlock it afterward. As suggested in the documentation of wait(), lock is used as a guard to pred() access. If the master thread aquires mtx, no other thread are checking the conditions at the same moment. Although they may be doing other jobs at that time, but in your code they are not likely to enter wait again.
I want to implement the following case:
A worker thread that is continuously running unless interrupted by calling boost::thread::interrupt
The thread must pause for 100 ms at the end of each block, but must immediately wake up and continue if notified by another thread to do so
WorkerThread()
{
while(true)
{
...
...
... //done with a block of work
//Pause for 100 ms unless notified by another
//thread to wake up and continue immediately
}
}
Question: Can I use boost::condition_variable::timed_wait in the following way to get the following scenario working?
boost::condition_variable cond;
WorkerThread()
{
while(true)
{
...
...
... //done with a block of work
boost::mutex mut;
boost::unique_lock<boost::mutex> lock(mut); // this lock will always be
//acquired since no one else
//locks *mut*
cond.timed_wait( lock, boost::posix_time::milliseconds(100) );
}
}
OtherThread()
{
//need to make the worker thread immediately wake up
cond.notify_one();
}
Would this work? If not, how do I achieve the scenario above?