web-dev-qa-db-ja.com

C ++スレッドでの条件変数の使用と、これと一緒に「unique_lock」と「mutex」を使用する必要がある理由を説明してください。

私はこの特定のコードを参照しています:

このコードには基本的に3つのスレッドがあります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/ からのものです

ありがとう

4
Nilesh

条件変数を使用すると、保持されているミューテックスをアトミックに解放し、スレッドをスリープ状態にすることができます。次に、シグナルが送信された後、ミューテックスをアトミックに再取得してウェイクアップします。たとえば、生産者/消費者問題でこれに遭遇します。あなたwillミューテックスを保持しながらスリープ状態になるとデッドロックになりますが、スリープする前に解放するとデッドロックになる可能性もあります(ウェイクアップの信号がないため)。

これは、例なしでいくつかの段落で説明できるものではなく、条件変数を使用する際のいくつかのよく知られた落とし穴と警告があります。 Andrew D.Birrellによる「スレッドを使用したプログラミング入門」をご覧ください。

言語に関係なく、条件変数は常にミューテックスを取ります。待機が呼び出されたときにミューテックスを保持する必要があります。待機から戻った後も、目的の条件がまだ真であることを常に確認する必要があります。そのため、条件付き待機は常にwhileループにラップされています。 C++ 11は、whileループの構文糖衣構文である述語オーバーロードも提供します。

ミューテックスは共有状態を保護します。この条件では、通知されるまでブロックできます。

unique_lockは、指定されたミューテックスをロックおよびロック解除するためのRAII(Resource Acquisition Is Initialization)ラッパーです。概念的には、C#のlockステートメントと同じです。ミューテックスの取得と解放をunique_lockインスタンスの存続期間に関連付けることにより、例外処理を簡素化します。 condition_variableが、それが良い習慣であるという事実以外に、それを使用するように強制する理由があるかどうかはわかりません。 unique_locklock_guardの唯一の違いは、unique_lockのロックを解除できることです...そのため、lock_guardの代わりにcondition_variableを使用する必要があります。

10