2016-08-16 36 views
1

重要な領域を持つアプリケーションを作成しています。AutoResetEvent.WaitOne()が原因でデッドロックが発生する

私は相互排除を実現するためにAutoResetEventを使用することにしました。 は、ここで私は、クリックイベントを呼び出しますButton_Click()方法

それが正常に動作ボタンを持っているコード

public class MyViewModel 
    { 
     private AutoResetEvent lock = new AutoResetEvent(true); 
     private aync Task CriticalRegion() 
     { 
      Dosomething(); 
     } 


     public async Task Button_Click() 
     { 
      Debug.WriteLine("Entering Button_Click"); 
      lock.WaitOne(); 
      try 
      { 
       await CriticalRegion(); 
      } 
      finally 
      { 
       lock.Set(); 
       Debug.WriteLine("Leaving Button_Click"); 

      } 
     } 

    } 

です。しかし、Button_Click()への最初の呼び出しが完了する前に、別の時間ボタンをクリックするのに十分速ければ、アプリケーション全体が応答を停止します。デバッグウィンドウで

私は、メソッドが完了したことがないように、この

Entering Button_Click 
Entering Button_Click 

のようなものが見える見つけます。

私は少し苦労し、私はこの場合lock.WaitOne();

if (!sync.WaitOne(TimeSpan.FromSeconds(1))) 
    { 
     return; 
    } 

を変更した場合、私のアプリは、デッドロックを回避することができますが、それは動作しますなぜ私にはわからないことがわかります。

私は自分のOSコースのIPCと、C#のasyncawaitのパターンしか知りません。私は.NETの世界のスレッドに慣れていません。

実際に何が舞台裏で起こっているのか本当に理解したいです。任意のreplysため 感謝;)あなたはWaitOne()コールを除いて行うように見えることはありませんAutoResetEvent.Set()を呼び出すまで

+1

投稿されたスニペットはデッドロックのデモンストレーションには不十分です。しかし、間違っていることは明らかです。クラス名に少し集中してください。それはオートリセット*イベント*です。イベントはシグナリングに使用され、「重要領域」には相互排除が必要です。これはmutexを必要とします。最も簡単にはC#で 'lock'キーワードを使って行います。UIスレッドのロックを使用することは正式には違法であり、事実上、デッドロックを引き起こす可能性は非常に高くなります。 –

答えて

4

awaitを呼び出すときに、それがコードどれを実行しようとすることを意味し、ConfigureAwait(false)と呼ばれていないながらWaitOneは、(ボタンのクリックハンドラは、メインスレッド上で実行される)、メインスレッドをブロックしているので、あなたがデッドロックを持っていますブロックされていてもメインスレッドのawaitの後にあり、デッドロックが発生します。

デッドロック状況の深刻な説明については、this postを読むことをお勧めします。

Eventオブジェクトを使用すると、相互排除のためにHansが使用されるため、コードでは、おそらく非同期タスク内にロックを深く入れ、ロックに適したパターンを使用することをお勧めします(好ましくはlock statement)。コメントに述べられている。

+0

ありがとう、それらの投稿は本当に助けになりました。他の質問、私の重要な地域は実際にいくつかの 'await'キーワードを含んでいます。それで' SemaphoreSlim.WaitAsync() 'を使うのはどうですか? – Hohenheim

+0

「SemaphoreSlim」は、実際に非同期ロックを使用する方が望ましいと思われます。 – argaz

0

AutoResetEvent.WaitOne()が無限にブロックします。

AutoResetEvent.WaitOne()文書を引用:

ブロック現在のスレッド電流WaitHandleが信号を受信するまで

+0

あなたは正しいですが、彼は100%ではなくレースコンディションのデッドロックを説明しています。この場合、私の説明がうまくいくと思います。 – argaz

関連する問題