How to ensure wait_for is called before notify_one - c++

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.

Related

If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released what would be result?

Is it clear what would happen if a thread blocked on a std::condition_variable receives a notification but the lock on the associated mutex is not yet released, and the lock will be released 10 seconds later? Would the thread wait for the lock to be released or is the situation undefined?
I added a 15seconds sleep on purpose to make the lock unavailable during that time to see how waiting thread will be doing. It is doing OK but just wanted to be sure about it.
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
struct SharedResource
{
SharedResource() :
cv_mutex(), cv(), counter(0)
{
}
/*
This mutex is used for three purposes:
1) to synchronize accesses to counter
2) to synchronize accesses to std::cerr
3) for the condition variable cv
*/
std::mutex cv_mutex;
std::condition_variable cv;
int counter;
};
void waits(SharedResource& sharedRes)
{
std::unique_lock<std::mutex> lk(sharedRes.cv_mutex);
std::cerr << "Waiting... \n";
while (sharedRes.counter != 1)
{
sharedRes.cv.wait_for(lk,3s);
std::cerr << "Thread ID: " << std::this_thread::get_id() << " wakes up every 3 seconds.\n";
}
std::cerr << "...finished waiting." << "counter: " << sharedRes.counter << std::endl;
} //The lk object will be unlocked after this scope ends.
void signals(SharedResource& sharedRes)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(sharedRes.cv_mutex);
std::cerr << "Notifying...\n";
} // The lk object will be unlocked after this scope ends.
sharedRes.cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(6));
{
std::lock_guard<std::mutex> lk(sharedRes.cv_mutex);
sharedRes.counter = 1;
std::cerr << "Notifying again...\n";
sharedRes.cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(15));
}// The lk object will be unlocked after this scope ends.
}
int main()
{
SharedResource sharedRes;
std::thread
t1(waits, std::ref(sharedRes)),
t2(signals, std::ref(sharedRes));
t1.join();
t2.join();
}
If a thread that is blocked on a std::condition_variable is notified, but the lock on the associated mutex has not been released what would be result?
It will continue to wait / wait_for until it can reacquire the lock.
When std::condition_variable::wait and wait_for returns (for whatever reason), the lock is held again, so you don't have to worry about that.
It can even return from wait without having gotten any notifications (spurious wake-ups) - but, no matter what, the lock is reacquired when the call returns.

How std::condition_variable and std::mutex works exactly?

I'm reading this std::condition_variable example:
#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();
}
Let's focus on the beggining:
std::thread worker(worker_thread);
here, we start the worked, which will lock the mutex immediately:
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
Then, we lock the mutex on main to change the value of ready
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
but how is it possible that we even arrive at the line ready=true? The mutext m is blocked from the worked thread, so the line std::lock_guard<std::mutex> lk(m); will wait until the mutex m is unlocked. As I understand, when a mutex is locked and we try to lock it, we'll wait until it gets unlocked. However, it'll never get unlocked because the worked thread is waiting, therefore not releasing it.
In the link you have attached, note that the following
The wait operations atomically release the mutex and suspend the
execution of the thread.
Hence the line
cv.wait(lk, []{return ready;});
releases the mutex and suspends the execution of the thread until the condition variable is notified, a timeout expires (with wit_for()), or a spurious wake-up occurs, hence the thread is awakened, and the mutex is atomically reacquired
Here's another example that will give you the gist of the mechanism.
#include <cstdio>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool signal = 0;
void A()
{
while (1)
{
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [](){return signal;});
signal = 0;
}
printf("Lock release from th A\n");
}
}
int main()
{
std::thread th(A);
for (unsigned i = 0; i < 100; i++)
{
{
std::lock_guard<std::mutex> lock(mtx);
signal = 1;
}
cv.notify_one();
printf("Sending signal %i\n", i);
std::this_thread::sleep_for(std::chrono::seconds(5));
}
th.join();
return 0;
}

Switching from polling to event based system

Basically what i am trying to achieve is to check whether the data has been changed or not since the last time i checked.
What i am doing here is i initiate a separate thread that continuously runs in a loop and checks the stop variable at the end of the loop. The stop variable is a global variable so i can easily give it a 0 value to terminate the polling loop from the main thread.
In the loop i have a set of variables that hold the value of data that i retrieved in the previous iteration and a set of variables that are used to store the recently retrieved data. All i do is compare the variable with the new data with the ones that are holding the previous data. After this i update the set of variables that are holding the previous data to the most recent data.
I wanted to ask if there is a more efficient way of doing this? maybe something that would not require polling?
Yes; one way is to have the polling thread wait on a condition variable, and have the producer wake it up by signalling the same condition variable.
An example in C++ is given at cppreference:
#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();
}

why lock_guard can get an already locked mutex by unique_lock? - still questions

I am studying this example. I have found this question and thought that I will get an answer, but I still have a question.
I post the the code here for convenience:
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::cout << "------------------------\n";
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();
return 0;
}
Should not the statement std::unique_lock<std::mutex> lk(m); block the main thread because mutex m is locked by worker_thread? If yes, isn't the statement cv.wait(lk, []{return processed;}); after it unnecessary in this example? When main thread can lock the mutex, processed will be already true.
The call to wait unlocks the mutex for the duration of the wait. See http://en.cppreference.com/w/cpp/thread/condition_variable/wait.
EDIT: Which is explicitly stated in the answer to the question you linked to: https://stackoverflow.com/a/32030975/212870
EDIT 2: It is not true that "When main thread can lock the mutex, processed will already be true". The worker thread may not even have started yet, or if it has it may not have seen that ready is set.
Line cv.wait(lk, []{return ready;}); does the following if ready is false:
Unlocks the mutex lk
Blocks the thread waiting for notification
When notification arrives, unblocks the thread and locks the mutex lk
So the main thread does not block on std::lock_guard<std::mutex> lk(m); as the mutex is unlocked by worker thread.

why lock_guard can get an already locked mutex by unique_lock?

I am reading the example code of using condition_variable here. I post the code below:
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::cout << "------------------------\n";
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();
return 0;
}
My question is the worker_thread is launched first, so I would assume the mutex m is locked by the worker_thread, but why in the main the mutex m still can be locked by lock_guard?
A condition variable is only one part of a tripod.
The three parts are the condition variable, state and the mutex that guards the state.
The condition variable provides a mechanism to notify when the state changes.
This operation uses all 3:
cv.wait(lk, []{return ready;})
The condition variable's method takes a lock (which must have been acquired), and a lambda (which tests the state).
Within the wait method, the lk is unlocked until the condition variable detects a message (which could be spurious). When it detects a message, it relocks the mutex and runs the test (whose goal is to determine if the detection was spurious). If the test fails, it unlocks and waits again: if the test passes, it keeps the lock locked and exits.
There is also the "the test threw" path, which results in a different lock state depending on the version of the standard your code implemented (C++11 had a defect, IIRC).
The important thing you missed is that wait unlocks the mutex passed in.