2016-12-27 4 views
3

次のコードを参照してください。この単純なシナリオでデッドロックは可能ですか?

std::mutex mutex; 
std::condition_variable cv; 
std::atomic<bool> terminate; 

// Worker thread routine 
void work() { 
    while(!terminate) { 
     { 
      std::unique_lock<std::mutex> lg{ mutex }; 
      cv.wait(lg); 

      // Do something 
     } 
     // Do something 
    } 
} 

// This function is called from the main thread 
void terminate_worker() { 
    terminate = true; 
    cv.notify_all(); 
    worker_thread.join(); 
} 

は、次のシナリオが発生する可能性がありますか?

  1. ワーカースレッドが信号を待っています。
  2. メインスレッドはterminate_worker()と呼ばれます。
    • メインスレッドは、アトミック変数terminatetrueに設定し、ワーカースレッドに通知します。
    • ワーカースレッドが起動し、ジョブを実行してterminateからロードします。このステップで、メインスレッドによって行われたterminateへの変更はまだ見えていません、ワーカースレッドは別の信号を待つことを決定します。今、デッドロックが発生し
  3. ...

私はこれが今まで可能であるだろう。私が理解しているように、std::atomicは競合状態を保証するものではありませんが、メモリの順序は異なります。質問:

  1. これは可能ですか?
  2. terminateがアトミック変数ではなく、単にboolの場合、これが可能ですか?それとも原子性はこれとは関係がありませんか?
  3. 可能であれば、どうすればよいですか?

ありがとうございます。

+0

[ 'のstd :: memory_order'](http://en.cppreference.com/w/cpp/atomic/memory_order):

Aは次のようになります(最小限の変更で)コードを修正しました – melak47

+0

@ melak47詳細を記入してください。私はこれが 'std :: memory_order'であることを知っています。しかし、私はどのように 'std :: condition_variable'がメモリの順序制限で動作するのか分かりません。 –

+0

関連:http://stackoverflow.com/questions/8819095/concurrency-atomic-and-volatile-in-c11-memory-model – Leon

答えて

2

cv.notify_all() afaik(私が間違っていれば修正してください)はwait()と同期するので、ワーカースレッドが起動すると、terminateに変更が表示されます。

しかし:

デッドロックは、以下のように起こることができる:

  1. ワーカースレッド(WT)をterminateフラグが依然として偽であると判断します。

  2. メインスレッド(MT)はterminateフラグを設定し、cv.notify_all()を呼び出します。

  3. 通知が「失われたり無視される」という条件変数を待っている人はいません。
  4. MTはjoinとブロックを呼び出します。
  5. WTはスリープ状態になり(ブロックcv.wait())、ブロックされます。

ソリューション:

あなたはcv.notify呼んでいるとき

  • あなたがterminateを変更している一方で、ロックを保持する必要がある(、ロックを保持する必要はありませんが
  • )同じロックを保持している間に、条件と実際の呼び出しの確認が行われることを確認する必要があります。wait

これは、スレッドをスリープ状態にする直前にこのチェックを実行する形式のwaitです。

// Worker thread routine 
void work() { 
    while(!terminate) { 
     { 
      std::unique_lock<std::mutex> lg{ mutex }; 
      if (!terminate) { 
       cv.wait(lg); 
      } 

      // Do something 
     } 
     // Do something 
    } 
} 

// This function is called from the main thread 
void terminate_worker() { 
    { 
     std::lock_guard<std::mutex> lg(mutex); 
     terminate = true; 
    } 
    cv.notify_all(); 
    worker_thread.join(); 
} 
+0

いずれにしても、OPは終了変数の状態を待った後にチェックする必要があります。提供されたコードでは、条件変数が通知された理由を区別できません。 terminatee要求または別のスレッドとの通常の同期化のいずれかになります。 – paweldac

+0

@paweldac:はい、彼はおそらく(ビジネスロジックを知らずに)話すのは難しいでしょうが、デッドロックが発生するかどうかという疑問とはどういう関係がありますか? – MikeMB

+1

なぜdownvote? – MikeMB

関連する問題