2017-10-06 17 views
2

プロデューサ/コンシューマの問題を実装するコードレビュースタックエクスチェンジでは、codeが見つかりました。私はここにコードのセクションを掲示しています。与えられたコードで同じmutexで使用される2つのstd :: unique_lockがデッドロックを引き起こしますか?

、プロデューサーはvoid add(int num)を呼び出して値を生成する場合のシナリオを考えてみましょう、これはプロデューサーが原因条件変数condに待ちキューに行かせるミューテックスmuのロックを取得し、buffer.size()==size_

同じ瞬間に、コンテキストスイッチが行われ、消費者の呼び出しは値を消費するint remove()機能、それがミューテックスmuのロックを取得しようとすると、しかしロックはすでにそれが失敗し、決して消費して生産して、以前に取得されていますその値はデッドロックの原因となります。

ここで私は間違っていますか?コードを実行すると、コードが正常に動作するように見えるので、デバッグすることは私を助けませんでした。

おかげ

void add(int num) { 
     while (true) { 
      std::unique_lock<std::mutex> locker(mu); 
      cond.wait(locker, [this](){return buffer_.size() < size_;}); 
      buffer_.push_back(num); 
      locker.unlock(); 
      cond.notify_all(); 
      return; 
     } 
    } 
    int remove() { 
     while (true) 
     { 
      std::unique_lock<std::mutex> locker(mu); 
      cond.wait(locker, [this](){return buffer_.size() > 0;}); 
      int back = buffer_.back(); 
      buffer_.pop_back(); 
      locker.unlock(); 
      cond.notify_all(); 
      return back; 
     } 
    } 
+0

待ち条件が満たされるまで、ロックを解除し、 ' –

+1

待機を終了する前にそれを再取得する必要がありながら、(真){...; return;} '...なぜループを使うのですか? – Jarod42

答えて

3

OutOfBoundの答えは良いですが、正確には "アトミック"とは少し詳細が便利です。

wait条件変数の操作には、渡されたミューテックスが呼び出し元によってロックされるという前提条件と事後条件があります。 waitオペレーションは内部的にミューテックスのロックを解除し、ミューテックスのロック解除の結果として起こる他のスレッドからのnotifyまたはnotify_allオペレーションを見落とさないように保証します。 waitの内部では、mutexのロックを解除し、通知を待つ状態に入ることはお互いに原子的である。これにより、睡眠/起床レースが回避されます。

条件付きクリティカルセクションフォームは、述部を内部的にテストします。それでも、正しく行われていることを通知に依存します。

は、ある意味では、人はこれをやって waitと考えることができます:通知と

while (!predicate()) { 
    mutex.unlock(); 
    /* sleep for a short time or spin */ 
    mutex.lock(); 
} 

条件変数は、効率的であることを途中でコメント行することができます。どの与えます:

while (!predicate()) { 
    atomic { /* This is the key part. */ 
     mutex.unlock(); 
     sleep_until_notified(); 
    } 
    mutex.lock(); 
} 
2

std::condition_variable::wait(lock, predicate)のアイデアは、述語が満たされ、その後ミューテックスをロックしているされるまで、あなたは待つということです。これを原子的に(これはほとんどの場合重要です)行うには、最初にミューテックスをロックしなければなりません。その後、待機が解除され、述部をチェックするためにロックされます。満たされていれば、ミューテックスはロックされたままであり、実行は継続する。そうでない場合、ミューテックスは再び解放されます。