Пожалуйста, объясните использование условных переменных в потоках c ++, и почему мы должны использовать `unique_lock` и` mutex` вместе с этим - PullRequest
0 голосов
/ 14 мая 2018

Я ссылаюсь на этот конкретный фрагмент кода:

этот код в основном состоит из трех потоков 1. Выполните некоторое рукопожатие с сервером 2. Загрузите данные из файлов XML.3. Выполните обработку данных, загруженных из XML.Как мы видим, Задача 1 не зависит от каких-либо других Задач, но Задача 3 зависит от Задачи 2. Таким образом, это означает, что Задача 1 и Задача 2 могут выполняться параллельно различными потоками для повышения производительности приложения.Таким образом, приложение построено так, чтобы быть многопоточным.

#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;

class Application
{
  std::mutex m_mutex;
  std::condition_variable m_condVar;
  bool m_bDataLoaded;
public:
  Application()
  {
    m_bDataLoaded = false;
  }
  void loadData()
  {
   // Make This Thread sleep for 1 Second
   std::this_thread::sleep_for(std::chrono::milliseconds(1000));
   std::cout<<"Loading Data from XML"<<std::endl;
   // Lock The Data structure
   std::lock_guard<std::mutex> guard(m_mutex);
   // Set the flag to true, means data is loaded
   m_bDataLoaded = true;
   // Notify the condition variable
   m_condVar.notify_one();
  }
  bool isDataLoaded()
  {
    return m_bDataLoaded;
  }
  void mainTask()
  {
    std::cout<<"Do Some Handshaking"<<std::endl;
    // Acquire the lock
    std::unique_lock<std::mutex> mlock(m_mutex);
    // Start waiting for the Condition Variable to get signaled
    // Wait() will internally release the lock and make the thread to block
    // As soon as condition variable get signaled, resume the thread and
    // again acquire the lock. Then check if condition is met or not
    // If condition is met then continue else again go in wait.
    m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
    std::cout<<"Do Processing On loaded Data"<<std::endl;
  }
};
int main()
{
   Application app;
   std::thread thread_1(&Application::mainTask, &app);
   std::thread thread_2(&Application::loadData, &app);
   thread_2.join();
   thread_1.join();
   return 0;
}

этот код от http://thispointer.com/c11-multithreading-part-7-condition-variables-explained/

Спасибо

1 Ответ

0 голосов
/ 15 мая 2018

Переменные условия позволяют атомарно освободить удерживаемый мьютекс и перевести поток в режим сна. Затем, получив сигнал, атомно восстанавливают мьютекс и просыпаются. Вы сталкиваетесь с этим, например, в проблеме производителя / потребителя. Вы будете заблокированы, если вы ложитесь спать, удерживая мьютекс, но вы также можете заблокировать его, если отпустите его перед сном (пропустив сигнал пробуждения).

Это не то, что можно объяснить в нескольких параграфах без примеров, и есть несколько известных подводных камней и предостережений при использовании условных переменных. Проверьте "Введение в программирование с помощью потоков" Эндрю Бирреллом.

Независимо от языка, условные переменные всегда принимают мьютекс. Мьютекс должен удерживаться при вызове wait. Вы должны всегда проверять, что желаемое условие все еще выполняется после возвращения из ожидания. Вот почему вы всегда видите условные ожидания, заключенные в цикл while. C ++ 11 также дает вам предикатную перегрузку, которая является синтаксическим сахаром для цикла while.

Мьютекс защищает общее состояние. Условие позволяет блокировать, пока не получит сигнал.

unique_lock - это оболочка RAII (Resource Acquisition Is Initialization) для блокировки и разблокировки данного мьютекса. Это концептуально идентично выражению lock в C #. Это упрощает обработку исключений, связывая получение и освобождение мьютекса со временем жизни экземпляра unique_lock. Я не знаю, есть ли причина, по которой condition_variable заставляет вас использовать это, кроме того факта, что это хорошая практика. Единственная разница между unique_lock и lock_guard заключается в том, что unique_lock можно разблокировать ... именно поэтому вы должны использовать его вместо lock_guard с condition_variable.

...