0
votes

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?

1
Your two examples above have identical code.Howard Hinnant

1 Answers

1
votes

...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:

  1. it unlocks the given lock,
  2. it waits for some other thread to call cv.notify_all(), and then
  3. it re-locks the lock.

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.