why do I need std::condition_variable? - c++

I found that std::condition_variable is very difficult to use due to spurious wakeups. So sometimes I need to set a flags such as:
atomic<bool> is_ready;
I set is_ready to true before I call notify (notify_one() or notify_all()), and then I wait:
some_condition_variable.wait(some_unique_lock, [&is_ready]{
return bool(is_ready);
});
Is there any reason that I shouldn't just do this: (Edit: Ok, this is really a bad idea.)
while(!is_ready) {
this_thread::wait_for(some_duration); //Edit: changed from this_thread::yield();
}
And if condition_variable had chosen a waiting duration (I don't know whether this is true or not), I prefer choose it myself.

You can code this either way:
Using atomics and a polling loop.
Using a condition_variable.
I've coded it both ways for you below. On my system I can monitor in real time how much cpu any given process is using.
First with the polling loop:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
std::atomic<bool> is_ready(false);
void
test()
{
std::this_thread::sleep_for(std::chrono::seconds(30));
is_ready.store(true);
}
int
main()
{
std::thread t(test);
while (!is_ready.load())
std::this_thread::yield();
t.join();
}
For me this takes 30 seconds to execute, and while executing the process takes about 99.6% of a cpu.
Alternatively with a condition_variable:
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
bool is_ready(false);
std::mutex m;
std::condition_variable cv;
void
test()
{
std::this_thread::sleep_for(std::chrono::seconds(30));
std::unique_lock<std::mutex> lk(m);
is_ready = true;
cv.notify_one();
}
int
main()
{
std::thread t(test);
std::unique_lock<std::mutex> lk(m);
while (!is_ready)
{
cv.wait(lk);
if (!is_ready)
std::cout << "Spurious wake up!\n";
}
t.join();
}
This has the exact same behavior except that during the 30 second execution, the process is taking 0.0% cpu. If you're writing an app that might execute on a battery powered device, the latter is nearly infinitely easier on the battery.
Now admittedly, if you had a very poor implementation of std::condition_variable, it could have the same inefficiency as the polling loop. However in practice such a vendor ought to go out of business fairly quickly.
Update
For grins I augmented my condition_variable wait loop with a spurious wakeup detector. I ran it again, and it did not print out anything. Not one spurious wakeup. That is of course not guaranteed. But it does demonstrate what a quality implementation can achieve.

The purpose of std::condition_variable is to wait for some condition to become true. It is not designed to be just a receiver of a notify. You might use it, for example, when a consumer thread needs to wait for a queue to become non-empty.
T get_from_queue() {
std::unique_lock l(the_mutex);
while (the_queue.empty()) {
the_condition_variable.wait(l);
}
// the above loop is _exactly_ equivalent to the_condition_variable.wait(l, [&the_queue](){ return !the_queue.empty(); }
// now we have the mutex and the invariant (that the_queue be non-empty) is true
T retval = the_queue.top();
the_queue.pop();
return retval;
}
put_in_queue(T& v) {
std::unique_lock l(the_mutex);
the_queue.push(v);
the_condition_variable.notify_one(); // the queue is non-empty now, so wake up one of the blocked consumers (if there is one) so they can retest.
}
The consumer (get_from_queue) is not waiting for the condition variable, they are waiting for the condition the_queue.empty(). The condition variable gives you the way to put them to sleep while they are waiting, simultaneously releasing the mutex and doing so in a way that avoids race conditions where you miss wake ups.
The condition you are waiting on should be protected by a mutex (the one you release when you wait on the condition variable.) This means that the condition rarely (if ever) needs to be an atomic. You are always accessing it from within a mutex.

Related

Minimal mutexes for std::queue producer/consumer

I have two threads that work the producer and consumer sides of a std::queue. The queue isn't often full, so I'd like to avoid the consumer grabbing the mutex that is guarding mutating the queue.
Is it okay to call empty() outside the mutex then only grab the mutex if there is something in the queue?
For example:
struct MyData{
int a;
int b;
};
class SpeedyAccess{
public:
void AddDataFromThread1(MyData data){
const std::lock_guard<std::mutex> queueMutexLock(queueAccess);
workQueue.push(data);
}
void CheckFromThread2(){
if(!workQueue.empty()) // Un-protected access...is this dangerous?
{
queueAccess.lock();
MyData data = workQueue.front();
workQueue.pop();
queueAccess.unlock();
ExpensiveComputation(data);
}
}
private:
void ExpensiveComputation(MyData& data);
std::queue<MyData> workQueue;
std::mutex queueAccess;
}
Thread 2 does the check and isn't particularly time-critical, but will get called a lot (500/sec?). Thread 1 is very time critical, a lot of stuff needs to run there, but isn't called as frequently (max 20/sec).
If I add a mutex guard around empty(), if the queue is empty when thread 2 comes, it won't hold the mutex for long, so might not be a big hit. However, since it gets called so frequently, it might occasionally happen at the same time something is trying to get put on the back....will this cause a substantial amount of waiting in thread 1?
As written in the comments above, you should call empty() only under a lock.
But I believe there is a better way to do it.
You can use a std::condition_variable together with a std::mutex, to achieve synchronization of access to the queue, without locking the mutex more than you must.
However - when using std::condition_variable, you must be aware that it suffers from spurious wakeups. You can read about it here: Spurious wakeup - Wikipedia.
You can see some code examples here:
Condition variable examples.
The correct way to use a std::condition_variable is demonstrated below (with some comments).
This is just a minimal example to show the principle.
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <iostream>
using MyData = int;
std::mutex mtx;
std::condition_variable cond_var;
std::queue<MyData> q;
void producer()
{
MyData produced_val = 0;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // simulate some pause between productions
++produced_val;
std::cout << "produced: " << produced_val << std::endl;
{
// Access the Q under the lock:
std::unique_lock<std::mutex> lck(mtx);
q.push(produced_val);
cond_var.notify_all(); // It's not a must to nofity under the lock but it might be more efficient (see #DavidSchwartz's comment below).
}
}
}
void consumer()
{
while (true)
{
MyData consumed_val;
{
// Access the Q under the lock:
std::unique_lock<std::mutex> lck(mtx);
// NOTE: The following call will lock the mutex only when the the condition_varible will cause wakeup
// (due to `notify` or spurious wakeup).
// Then it will check if the Q is empty.
// If empty it will release the lock and continue to wait.
// If not empty, the lock will be kept until out of scope.
// See the documentation for std::condition_variable.
cond_var.wait(lck, []() { return !q.empty(); }); // will loop internally to handle spurious wakeups
consumed_val = q.front();
q.pop();
}
std::cout << "consumed: " << consumed_val << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200)); // simulate some calculation
}
}
int main()
{
std::thread p(producer);
std::thread c(consumer);
while(true) {}
p.join(); c.join(); // will never happen in our case but to remind us what is needed.
return 0;
}
Some notes:
In your real code, none of the threads should run forever. You should have some mechanism to notify them to gracefully exit.
The global variables (mtx,q etc.) are better to be members of some context class, or passed to the producer() and consumer() as parameters.
This example assumes for simplicity that the producer's production rate is always low relatively to the consumer's rate. In your real code you can make it more general, by making the consumer extract all elements in the Q each time the condition_variable is signaled.
You can "play" with the sleep_for times for the producer and consumer to test varios timing cases.

Multi-threaded input processing

I am new to using multithreading and I am working on a program that handles mouse movement, it consists of two threads, the main thread gets the input and stores the mouse position in a fixed location and the child thread loops through that location to get the value. So how do I reduce CPU utilization, I am using conditional variables to achieve this, is there a better way to do this? It seems that adding a delay to the subthreads would also work
void Engine::InputManager::MouseMove(const MouseMoveEvent& ev)
{
cur_mouse_ev_.x_ = ev.x_;
cur_mouse_ev_.y_ = ev.y_;
cv_.notify_all();
}
void Engine::InputManager::ProcessInput(MouseMoveEvent* ev)
{
while (true)
{
cv_.wait(u_mutex_);
float dx = static_cast<float>(ev->x_ - pre_mouse_pos[0]) * 0.25f;
float dy = static_cast<float>(ev->y_ - pre_mouse_pos[1]) * 0.25f;
g_pGraphicsManager->CameraRotateYaw(dx);
pre_mouse_pos[0] = ev->x_;
pre_mouse_pos[1] = ev->y_;
}
}
Using std::condition_variable is a good and efficient way to achieve what you want.
However - you implementation has the following issue:
std::condition_variable suffers from spurious wakeups. You can read about it here: Spurious wakeup - Wikipedia.
The correct way to use a condition variable requires:
To add a variable (bool in your case) to hold the "condition" you are waiting for. The variable should be updated under a lock using the mutex.
Again under a lock: calling wait in a loop until the variable satisfies the condition you are waiting for. If a spurious wakeup will occur, the loop will ensure getting into the waiting state again. BTW - wait method has an overload that gets a predicate for the condition, and loops for you.
You can see some code examples here:
Condition variable examples.
A minimal sample that demonstrates the flow:
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cond_var;
bool ready{ false };
void handler()
{
{
std::unique_lock<std::mutex> lck(mtx);
cond_var.wait(lck, []() { return ready; }); // will loop internally to handle spurious wakeups
}
// Handle data ...
}
void main()
{
std::thread t(handler);
// Prepare data ...
std::this_thread::sleep_for(std::chrono::seconds(3));
{
std::unique_lock<std::mutex> lck(mtx);
ready = true;
}
cond_var.notify_all();
t.join();
}
you could try using a semaphore, for (possibly) better performance
instead of 2 threads, you could try using coroutines (standard or your own), for less memory consumption. A thread needs a stack frame, that's several MBytes at least. A coroutine may not need anything extra.

Conditional variable is stuck on waiting

Why the condition variable is stuck on waiting if it was notified in worker_thread? What am I missing here?
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
std::mutex m;
std::condition_variable cv;
void worker_thread()
{
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
std::cout << "Start waiting..." << std::endl;
std::unique_lock<std::mutex> lk(m);
cv.wait(lk);
std::cout << "Finished waiting..." << std::endl;
worker.join();
getchar();
}
Your problem is that cv.notify_one() only wakes threads that are currently waiting. cv doesn't remember you notified it, and someone later comes along and waits.
Your worker thread is outpacing your main thread. So the notify happens before the main thread.
This is just a symptom of your real problem; you are using a condition variable wrong. Barring extremely advanced use, all use of condition variable should be in a triple.
A std::condition_variable.
A std::mutex.
A payload.
Your code is missing the payload.
To signal, you:
std::unique_lock<std::mutex> l(m);
payload = /* move it to a 'set' or 'non-empty' state */;
cv.notify_one(); // or all
to listen you:
std::unique_lock<std::mutex> l(m);
cv.wait(l, [&]{ return /* payload is in a set or non-empty state */; });
// while locked, consume one "unit" of payload from the payload.
with minor variations for wait_for and the like.
Following this cargo-cult pattern is important, as it avoids a number of pitfalls. It deals with both spurious wakeups with the wait happening after the notification.
Your code is missing a payload. So your code is vulnerable to both the waiting thread outrunning the signaling thread, and spurious wakeups.
Note that getting "clever" here is highly discouraged. For example, deciding that "I'll use an atomic variable to avoid using a mutex when signaling" actually doesn't work. Either follow the above recipe dogmatically, or go and spend a few months learning the threading and memory model of C++ well enough to improvise.
notify_one will unblock a waiting thread if there is one. If there are no waiting threads, nothing happens. A condition_variable does not have a state to remember how many threads should be notified when it is waited on.

Is my wait - notify mechanism using std::mutex correct?

I started using std::mutexes to stop a thread and wait for another thread to resume it. It works like this:
Thread 1
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
// Locks it again to pause this thread
myWaitMutex.lock();
Thread 2
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
However I am not sure if this is correct and will work without problems on all platforms. If this is not correct, what is the correct way to implement this in C++11?
The problems with the code
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
.try_lock() tries to aquire the lock and returns true if successful, i.e., the code says "if we aquire the lock then retry to lock it again and again until we fail". We can never "fail" as we currently own the lock ourselves that we are waiting on, and so this will be an infinite loop. Also, attempting to lock using a std::mutex that the caller have already aquired a lock on is UB, so this is guaranteed to be UB. If not successful, .try_lock() will return false and the while loop will be exited. In other words, this will not ensure that the mutex will be locked.
The correct way to ensure the mutex will be locked is simply:
myWaitMutex.lock();
This will cause the current thread to block (indefinitely) until it can aquire the lock.
Next, the other thread tries to unlock a mutex it does not have a lock on.
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
This won't work as it's UB to .unlock() on a std::mutex that you don't already have a lock on.
Using locks
When using mutex locks, it's easier to use a RAII ownership-wrapper object such as std::lock_guard. The usage pattern of std::mutex is always: "Lock -> do something in critical section -> unlock". A std::lock_guard will lock the mutex in its constructor, and unlock it in its destructor. No need to worry about when to lock and unlock and such low-level stuff.
std::mutex m;
{
std::lock_guard<std::mutex> lk{m};
/* We have the lock until we exit scope. */
} // Here 'lk' is destroyed and will release lock.
A simple lock might not be the best tool for the job
If what you want is to be able to signal a thread to wake up, then there's the wait and notify structure using std::condition_variable. The std::condition_variable allows any caller to send a signal to waiting threads without holding any locks.
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std::literals;
int main() {
std::mutex m;
std::condition_variable cond;
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
cond.wait(lk); // Will block until 'cond' is notified.
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
cond.notify_all(); // Notify all waiting threads.
t.join(); // Remember to join thread before exit.
}
However, to further complicate things there's this thing called spurious wakeups that mean that any waiting threads may wake up at any time for unknown reasons. This is a fact on most systems and has to do with the inner workings of thread scheduling. Also, we probably need to check that waiting is really needed as we're dealing with concurrency. If, for example, the notifying thread happens to notify before we start waiting, then we might wait forever unless we have a way to first check this.
To handle this we need to add a while loop and a predicate that tells when we need to wait and when we're done waiting.
int main() {
std::mutex m;
std::condition_variable cond;
bool done = false; // Flag for indicating when done waiting.
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
while (!done) { // Wait inside loop to handle spurious wakeups etc.
cond.wait(lk);
}
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
{ // Aquire lock to avoid data race on 'done'.
std::lock_guard<std::mutex> lk{m};
done = true; // Set 'done' to true before notifying.
}
cond.notify_all();
t.join();
}
There are additional reasons why it's a good idea to wait inside a loop and use a predicate such as "stolen wakeups" as mentioned in the comments by #David Schwartz.
It sounds to me that you are looking for condition variable. In the end there should always be a way to make it work through mutexes, but condition variable is the current C++ idiomatic way to handle the `block and wait until something happens' scenario.
The behavior of a mutex when a thread that holds it attempts to lock it is undefined. The behavior of a mutex when a thread that doesn't hold it attempts to unlock it is undefined. So your code might do anything at all on various platforms.
Instead, use a mutex together with a condition variable and a predicate boolean. In pseudo-code:
To block:
Acquire the mutex.
While the predicate is false, block on the condition variable.
If you want to re-arm here, set the predicate to false.
Release the mutex.
To release:
Acquire the mutex.
Set the predicate to true.
Signal the condition variable.
Release the mutex.
To rearm:
Acquire the mutex.
Set the predicate to false.
Release the mutex.
Please check this code....
std::mutex m_mutex;
std::condition_variable m_cond_var;
void threadOne(){
std::unique_lock<std::mutex> lck(mtx);
while (!ready){
m_cond_var.wait(lck);
}
m_cond_var.notify_all();
}
void threadTwo(){
std::unique_lock<std::mutex> lck(mtx);
read = true;
m_cond_var.notify_all();
}
I hope you will get the solution. And it is very proper!!

C++ Holding a number of threads

I'm new to C++ (on Windows) and threading and I'm currently trying to find a solution to my problem using mutexes, semaphores and events.
I'm trying to create a Barrier class with a constructor and a method called Enter. The class Barrier with it's only method Enter is supposed to hold off any thread that enters it, until a number of thread have reached that method. The number of thread to wait for it recieved at the contructor.
My problem is how do I use the locks to create that effect? what I need is something like a reversed semaphore, that holds threads until a count has been reached and not like the regular semaphore works that lets threads in until a count is reached.
Any ideas as to how to go about this would be great.
Thanks,
Netanel.
Maybe:
In the ctor, store the limit count and create an empty semaphore.
When a thread calls Enter, lock a mutex first so you can twiddle inside safely. Inc a thread count toward the limit count. If the limit has not yet been reached, release the mutex and wait on the semaphore. If the limit is reached, signal the semaphore[limit-1] times in a loop, zero the thread count, (ready for next time), release the mutex and return from Enter(). Any threads that were waiting on the semaphore, and are now ready/running, should just return from their 'Enter' call.
The mutex prevents any released thread that loops around from 'getting in again' until all the threads that called 'Enter' and waited have been set running and the barrier is reset.
You can implement it with condition variable.
Here is an example:
I declare 25 threads and launch them doing the WorkerThread function.
The condition I am checking to block/unblick the threads is whether the number of threads in the section is less than 2.
(I have added some asserts to prove what my coode does).
My code is simply sleeping in the critical section and after I decrease the number of threads in the critical section.
I also added a mutex for the cout to have clean messages.
#include
#include
#include
#include
#include
#include
#include /* assert */
using namespace std;
std::mutex m;
atomic<int> NumThreadsInCritialSection=0;
int MaxNumberThreadsInSection=2;
std::condition_variable cv;
mutex coutMutex;
int WorkerThread()
{
// Wait until main() sends data
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return NumThreadsInCritialSection<MaxNumberThreadsInSection;});
}
assert (NumThreadsInCritialSection<MaxNumberThreadsInSection);
assert (NumThreadsInCritialSection>=0);
NumThreadsInCritialSection++;
{
std::unique_lock<std::mutex> lk(coutMutex);
cout<<"NumThreadsInCritialSection= "<<NumThreadsInCritialSection<<endl;
}
std::this_thread::sleep_for(std::chrono::seconds(5));
NumThreadsInCritialSection--;
{
std::unique_lock<std::mutex> lk(coutMutex);
cout<<"NumThreadsInCritialSection= "<<NumThreadsInCritialSection<<endl;
}
cv.notify_one();
return 0;
}
int main()
{
vector<thread> vWorkers;
for (int i=0;i<25;++i)
{
vWorkers.push_back(thread(WorkerThread));
}
for (auto j=vWorkers.begin(); j!=vWorkers.end(); ++j)
{
j->join();
}
return 0;
}
Hope that helps, tell me if you have any questions, I can comment or change my code.
Pseudocode outline might look like this:
void Enter()
{
Increment counter (atomically or with mutex)
if(counter >= desired_count)
{
condition_met = true; (protected if bool writes aren't atomic on your architecture)
cond_broadcast(blocking_cond_var);
}
else
{
Do a normal cond_wait loop-plus-predicate-check (waiting for the broadcast and checking condition_met each iteration to protect for spurious wakeups).
}
}