How std::condition_variable and std::mutex works exactly? - c++

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

Related

An example condition_variable::notify_one

from
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cout << "...finished waiting; i == " << i << '\n';
done = true;
}
void signals()
{
std::this_thread::sleep_for(200ms);
std::cout << "Notifying falsely...\n";
cv.notify_one(); // waiting thread is notified with i == 0.
// cv.wait wakes up, checks i, and goes back to waiting
std::this_thread::sleep_for(300ms); // Add to make sure 'waits' thread wakes up**
std::unique_lock<std::mutex> lk(cv_m);
i = 1;
while (!done)
{
std::cout << "Notifying true change...\n";
lk.unlock();
cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns**
std::this_thread::sleep_for(300ms);
lk.lock();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join();
t2.join();
}
This is an example I got from cppreference. I have tried to execute the codes and observe the second notify seems not effected. Even I commented it out, the "signals" thread is still done.
Should it be put in the forever loop ??
Also if I add a wait before taking the cv_m mutex, seems it's working as expected

C++ - std::condition_variable notified by different threads

I am trying to notify an event from two different threads. Main thread wakes up on first notify_one() call but not on the second one. Is this the right way to use condition variable?
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
bool is_ready_1(false);
bool is_ready_2(false);
std::mutex m;
std::condition_variable cv;
void test1()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::mutex> lk(m);
is_ready_1 = true;
cv.notify_one();
}
void test2()
{
std::this_thread::sleep_for(std::chrono::seconds(6));
std::unique_lock<std::mutex> lk(m);
is_ready_2 = true;
cv.notify_one();
}
int main()
{
std::thread t1(test1);
std::thread t2(test2);
std::unique_lock<std::mutex> lk(m);
while (!is_ready_1)
{
cv.wait(lk);
if (is_ready_1)
std::cout << "Spurious wake-1 up!\n";
}
while (!is_ready_2)
{
cv.wait(lk);
if (is_ready_2)
std::cout << "Spurious wake-2 up!\n";
}
t1.join();
t2.join();
system("pause");
}
Try this code. Note that a condition variable accepts a predicate that first checks if the the condition is met, and then takes the lock. When you notify the variable, it runs the predicate (without taking the lock), if the condition is true, the thread will own the lock else the calling thread will keep waiting for the next notification.
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
auto is_ready_1=false;
auto is_ready_2=false;
std::mutex m;
std::condition_variable cv;
void test1()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::mutex> lk(m);
is_ready_1 = true;
cv.notify_one();
}
void test2()
{
std::this_thread::sleep_for(std::chrono::seconds(6));
std::unique_lock<std::mutex> lk(m);
is_ready_2 = true;
cv.notify_one();
}
int main()
{
std::thread t1(test1);
std::thread t2(test2);
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {
if (!is_ready_1)
{
std::cout << "Spurious 1" << std::endl;
}
return is_ready_1;
});
//preceding line must clear before this is executed
cv.wait(lk, [] {
if (!is_ready_2)
{
std::cout << "Spurious 1" << std::endl;
}
return is_ready_2;
});
t1.join();
t2.join();
system("pause");
}
Also on Windows 10, I see two spurious wakeup events, I suspect these happen when the thread is woken up from sleep.

How to ensure wait_for is called before notify_one

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.

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.

Does a mutex get unlocked when calling notify on a condition variable?

I am trying to understand what happens to a mutex when it is used in a condition variable.
In the following example, taken from cppreference
int main()
{
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
bool notified = false;
std::thread producer([&]() {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(m);
std::cout << "producing " << i << '\n';
produced_nums.push(i);
notified = true;
cond_var.notify_one();
}
done = true;
cond_var.notify_one();
});
std::thread consumer([&]() {
std::unique_lock<std::mutex> lock(m);
while (!done) {
while (!notified) { // loop to avoid spurious wakeups
cond_var.wait(lock);
}
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
}
notified = false;
}
});
producer.join();
consumer.join();
}
The producer thread calls cond_var.notify_one() before the mutex gets unlocked. Does the mutex m get unlocked when notify is called, or does the notification occurs only when the mutex gets unlocked?
Notifying does not unlock the mutex. You can tell (indirectly) because you don't pass the lock to notify_one() the way you do to wait(), which does release the mutex while it waits.
On the other side, the notified thread(s) are notified "immediately". But they won't necessarily return from wait() immediately. Before they can return from wait() they must first re-acquire the mutex, so they will block there until the notifying thread releases it.
The lock is being acquired in the constructor and released in the destructor of std::unique_lock. From this info you can deduce that the producer releases the lock after the call to notify_one() completes.
For performance reason I suggest to unlock the mutex before to notify other threads.