C++ Thread safety and notify_all() - c++

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.

Related

notify_one only when there are waiting threads is correct?

I've seen the following type of a dispatch queue implementation several times where the thread pushing a new element to the queue calls notify_one only when the queue was empty before pushing the element. This condition would reduce unnecessary notify_one calls because q.size() != 0 before pushing a new element means there are only active threads (assuming there are multiple consumer threads).
#include <queue>
#include <condition_variable>
#include <mutex>
using Item = int;
std::queue<Item> q;
std::condition_variable cv;
std::mutex m;
void process(Item i){}
void pop() {
while (true) {
std::unique_lock<std::mutex> lock(m);
// This thread releases the lock and start waiting.
// When notified, the thread start trying to re-acquire the lock and exit wait().
// During the attempt (and thus before `pop()`), can another `push()` call acquire the lock?
cv.wait(lock, [&]{return !q.empty();});
auto item = q.front();
q.pop();
process(item);
}
}
void push(Item i) {
std::lock_guard<std::mutex> lock(m);
q.push(i);
if (q.size() == 1) cv.notify_one();
}
int main() { /* ... */ }
However, is the following scenario possible ? Suppose that all the consumer threads are waiting.
the pushing thread acquires the lock and push a new element and calls notify_one because the queue was empty.
a notified thread tries to re-acquire the lock (and exit wait())
the pushing thread acquires the lock again and pushes another element before a notified thread re-acquires the lock.
In this case, no notify_one call wouldn't occur after 3. and there would be only one active thread when the queue isn't empty.
For the operation after wake up
According to wake's doc
Atomically unlocks lock, blocks the current executing thread, and adds it to the list of threads waiting on *this. The thread will be unblocked when notify_all() or notify_one() is executed. It may also be unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits.
Means your code is atomic between #1 to #2 when it's woken up. Don't need to worry about the synchronization since your compiler should handle it.
void pop() {
while (true) {
std::unique_lock<std::mutex> lock(m);
// When sleep, cv release the lock
cv.wait(lock, [&]{return !q.empty();}); // <----#1
// When wake up, it acquires the lock
auto item = q.front();
q.pop();
process(item); // <----#2
}
}
For spurious wakeup
The second overload with predicate would handle spurious wakeup for you.
template< class Predicate > void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting ); (2) (since C++11)
Equivalent to
while (!stop_waiting()) {
wait(lock);
}
This overload may be used to ignore spurious awakenings while waiting for a specific condition to become true.
Note that lock must be acquired before entering this method, and it is reacquired after wait(lock) exits, which means that lock can be used to guard access to stop_waiting().
That is the condition_variable overload with predicate would save you from spurious wake up.
The handmade while loop for checking spurious wake up is not needed.

Two std::unique_lock used on same mutex causes deadlock ?

I found this code on code review stack exchange which implements a producer-consumer problem. I am posting a section of code here.
In the given code, let's consider a scenario when producer produces a value by calling void add(int num), it acquires lock on mutex mu and buffer.size()==size_ this makes the producer go on wait queue due to the conditional variable cond.
At the same moment, a context switch takes place and consumer calls function int remove() to consume value , it tries to acquire the lock on mutex mu , however the lock has already been acquired previously by the producer so it fails and never consumes the value, hence causing a deadlock.
Where am I going wrong here ? Because the code seems to work properly when I run it, debugging it didn't help me.
Thanks
void add(int num) {
while (true) {
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [this](){return buffer_.size() < size_;});
buffer_.push_back(num);
locker.unlock();
cond.notify_all();
return;
}
}
int remove() {
while (true)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [this](){return buffer_.size() > 0;});
int back = buffer_.back();
buffer_.pop_back();
locker.unlock();
cond.notify_all();
return back;
}
}
The idea for std::condition_variable::wait(lock, predicate), is that you you wait until the predicate is met and have the lock on mutex afterwards. To do this atomically (which is important most of the time) you have to lock the mutex first, then the wait will release it and lock it for checking the predicate. If it is met the mutex stays locked and the execution continues. If not, the mutex will be released again.
OutOfBound's answer is good, but a bit more detail on exactly what is "atomic" is useful.
The wait operation on a condition variable has a precondition and a postcondition that the passed in mutex is locked by the caller. The wait operation unlocks the mutex internally and does so in a way that is guaranteed not to miss any notify or notify_all operations from other threads that happen as a result of unlocking the mutex. Inside wait the unlock of the mutex and entering a state waiting for notifies are atomic with respect to each other. This avoids sleep/wakeup races.
The conditional critical section form tests the predicate internally. It still depends on notifies being done correctly however.
In some sense, one can think of wait as doing this:
while (!predicate()) {
mutex.unlock();
/* sleep for a short time or spin */
mutex.lock();
}
The condition variable with notifies allows the commented line in the middle to be efficient. Which gives:
while (!predicate()) {
atomic { /* This is the key part. */
mutex.unlock();
sleep_until_notified();
}
mutex.lock();
}

C++ : How to use an std::condition_variable between UI thread & worker std::thread

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();
}

How to use a std::condition_variable correctly?

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; });

Not all threads notified of condition_variable.notify_all()

I have following scenario:
condition_variable cv;
mutex mut;
// Thread 1:
void run() {
while (true) {
mut.lock();
// create_some_data();
mut.unlock();
cv.notify_all();
}
}
// Thread 2
void thread2() {
mutex lockMutex;
unique_lock<mutex> lock(lockMutex);
while (running) {
cv.wait(lock);
mut.lock();
// copy data
mut.unlock();
// process data
}
}
// Thread 3, 4... - same as Thread 2
I run thread 1 all the time to get new data. Other threads wait with condition_variable until new data is available, then copy it and do some work on it. Work perfomed by threads differs in time needed to finish, the idea is that threads will get new data only when they finished with the old one. Data got in meantime is allowed to be "missed". I don't use shared mutex (only to access data) because I don't want threads to depend on each other.
Above code works fine on Windows, but now I run it on Ubuntu and I noticed that only one thread is being notified when notify_all() is called and the other ones just hangs on wait().
Why is that? Does Linux require different approach for using condition_variable?
Your code exhibits UB immediately as it relocks the unique lock that the cv has relocked when it exits wait.
There are other problems, like not detecting spurious wakeups.
Finally cv notify all onky notified currently waiting threads. If a thread shows up later, no dice.
It's working by luck.
The mutex and the condition variable are two parts of the same construct. You can't mix and match mutexes and cvs.
try this:
void thread2() {
unique_lock<mutex> lock(mut); // use the global mutex
while (running) {
cv.wait(lock);
// mutex is already locked here
// test condition. wakeups can be spurious
// copy data
lock.unlock();
// process data
lock.lock();
}
}
Per this documentation:
Any thread that intends to wait on std::condition_variable has to
acquire a std::unique_lock, on the same mutex as used to
protect the shared variable
execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the
thread.
When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is
atomically reacquired. The thread should then check the condition
and resume waiting if the wake up was spurious.
This code
void thread2() {
mutex lockMutex;
unique_lock<mutex> lock(lockMutex);
while (running) {
doesn't do that.