I use a mutex in two different situations: - first example: I use the mutex with unique_lock to make sure that threads don't access the same resource simultaneously - second example: I expand my first example to use a condition_variable, so that all threads wait until this additional thread notifies them.
Here is my first example
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
using namespace std;
mutex Mutex;
condition_variable cv;
bool ready = false;
void print(const char* ThreadName,int WaitTime)
{
cout << ThreadName << " : Waiting to get lock!" << endl;
unique_lock<mutex> lock(Mutex);
cout << ThreadName << " : Got the lock" << endl;
this_thread::sleep_for(chrono::milliseconds(WaitTime));
while (!ready)
{
cv.wait(lock);
}
cout<< ThreadName << " : thread is finishing now...." << endl;
}
void execute(const char* ThreadName)
{
this_thread::sleep_for(chrono::milliseconds(2000));
cout<< ThreadName << "Thready is ready to be executed!" << endl;
ready = true;
cv.notify_all();
}
int main()
{
thread t1(print, "Print1",200);
thread t2(print, "Print2",1000);
thread t3(print, "Print3",500);
thread t4(print, "Print4",10);
thread te(execute, "Execute");
t1.join();
t2.join();
t3.join();
t4.join();
te.join();
return 0;
}
The result of this is :
Print1Print3 : Waiting to get lock!Print2 : Waiting to get lock!
Print2 : Got the lock
Print4 : Waiting to get lock!
: Waiting to get lock!
Print2 : thread is finishing now....
Print3 : Got the lock
Print3 : thread is finishing now....
Print4 : Got the lock
Print4 : thread is finishing now....
Print1 : Got the lock
Print1 : thread is finishing now....
We can see that the first thread that gets a hold of the mutex, can do his thing, and only once its finished, the next thread can get beyond the unique_lock lock(Mutex); statement
Now I expand this example to use a condition_variable
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
using namespace std;
mutex Mutex;
condition_variable cv;
bool ready = false;
void print(const char* ThreadName,int WaitTime)
{
cout << ThreadName << " : Waiting to get lock!" << endl;
unique_lock<mutex> lock(Mutex);
cout << ThreadName << " : Got the lock" << endl;
this_thread::sleep_for(chrono::milliseconds(WaitTime));
while (!ready)
{
cv.wait(lock);
}
cout<< ThreadName << " : thread is finishing now...." << endl;
}
void execute(const char* ThreadName)
{
this_thread::sleep_for(chrono::milliseconds(2000));
cout<< ThreadName << "Thready is ready to be executed!" << endl;
ready = true;
cv.notify_all();
}
int main()
{
thread t1(print, "Print1",200);
thread t2(print, "Print2",1000);
thread t3(print, "Print3",500);
thread t4(print, "Print4",10);
thread te(execute, "Execute");
t1.join();
t2.join();
t3.join();
t4.join();
te.join();
return 0;
}
Output from this one is
Print1Print3: Waiting to get lock!
: Waiting to get lock!
Print2 : Waiting to get lock!
Print4 : Waiting to get lock!
Print3 : Got the lock
Print1 : Got the lock
Print4 : Got the lock
Print2 : Got the lock
ExecuteThready is ready to be executed!
Print2 : thread is finishing now....
Print4 : thread is finishing now....
Print1 : thread is finishing now....
Print3 : thread is finishing now....
What I don't understand is how all 4 threads can get a lock on the mutex, while there is nowhere a link between the condition_variable and the mutex?
...when there is nowhere a link between the condition_variable and the mutex?
The link is here:
cv.wait(lock);
The wait
function does three things before it returns:
lock
,cv.notify_all()
, and thenlock
.Of course, if some other thread was awakened first, then it may have to wait to re-lock the lock after it has awakened from the notification.