Разное поведение блокировки мьютекса при использовании condition_variable - PullRequest
0 голосов
/ 28 апреля 2020

Я использую мьютекс в двух разных ситуациях: - первый пример: я использую мьютекс с unique_lock, чтобы убедиться, что потоки не обращаются к одному и тому же ресурсу одновременно - второй пример: я расширяю свой первый пример, чтобы использовать условие 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;
}

Результат этого:

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

Мы можем видеть, что первый поток, который овладевает мьютексом, может делать свое дело, и только после его завершения следующий поток может выйти за пределы блокировки unique_lock (Mutex); оператор

Теперь я разверните этот пример, чтобы использовать переменную 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;
}

Выход из этого

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

Я не понимаю, как все 4 потока могут получить блокировку мьютекса, в то время как нет нигде связи между условной переменной и мьютексом?

1 Ответ

1 голос
/ 28 апреля 2020

... когда нет нигде ссылки между условной переменной и мьютексом?

Ссылка здесь:

cv.wait(lock);

Функция wait делает три вещи, прежде чем возвращает:

  1. он разблокирует данный lock,
  2. он ждет, пока какой-то другой поток вызовет cv.notify_all(), а затем
  3. он повторно блокирует lock.

Конечно, если сначала был пробужден какой-то другой поток, то, возможно, придется подождать, чтобы повторно заблокировать блокировку после того, как он проснулся от уведомления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...