2012-07-19 7 views
5

ワーカースレッドから定期的にイベントを発生させる外部コンポーネントを使用しています。私のイベントハンドラでは、ディスパッチャを使ってメインスレッド上のメソッドを呼び出します。プログラムがシャットダウンし、外付け部品の廃棄()の、プログラム時々ハング(とのみタスクマネージャで見られるし、死滅させることができる)とき、これは、しかし...うまくワーカースレッドがメインスレッド上で何かを呼び出そうとするとデッドロックが発生する

private void HandleXYZ(object sender, EventArgs e) 
{ 
    ... 
    if(OnTrigger != null) 
     dispatcher.Invoke(OnTrigger, new TimeSpan(0, 0, 1), e); 
} 

に動作します。

私は何が起きているのかを見ると、コンポーネントがメインスレッド(Dispose()メソッドのままです)に戻るのを待機しているように見えますが、ワーカースレッドはディスパッチャーが呼び出すのを待っています上記のメインスレッドへの呼び出し(ディスパッチャで停止します.Invoke-line)。

今のところ、私はシャットダウンの問題を、Invokeにタイムアウトを追加することで解決しましたが、これはうまくいくと思われますが間違っています。 これを行うためのよりクリーンな方法がありますか?シャットダウンする前に、メインスレッドに他のスレッドからのジョブにある程度の時間がかかるようにすることはできますか?

ディスパッチャがあるので...プログラムがシャットダウンを開始したときにすでに、待っている(かもしれない)、

PSを私はシャットダウンする前に、「切断」にイベントを試してみましたが、それは解決しません。外部コンポーネントとは、私がソースコードにアクセスできないということを意味します。

+0

使用してください段落次回 – Shai

+1

多く – Vedran

答えて

6

はい、これはデッドロックの一般的な原因です。ディスパッチャがディスパッチャのループを終了したため、応答が返されないためハングします。クイック・キュアは、代わりにBeginInvokeを使用することです。呼び出しターゲットが実行を終了するのを待つことはありません。もう一つの簡単な方法は、ワーカースレッドのIsBackgroundプロパティをTrueに設定して、CLRがそれを強制終了させることです。

これらはクイックフィックスであり、うまく機能します。確かにあなたの開発マシンでは、しかし、あなたはそれがまだ間違って行くかもしれないという気持ちが残っている場合は、デッドロックやスレッドレースを観察していない、ではないは存在しないことを証明します。完全に安全にそれを行うには、2つの「良い」の方法があります:あなたはワーカースレッドが終了し、もはやイベントを発生させることができていること確認するまで

  • は出口のメインスレッドを許可していません。 This answerにパターンが表示されます。

  • Environment.Exit()でプログラムを強制終了します。これは非常に粗ですが、非常に効果的です。あなたはUIスレッドが2番目の市民だけである大量のスレッドプログラムを持っているときにしか使えません。これは適切なアプローチとして思われるかもしれませんが、新しいC++言語標準はプログラムを終了するためのサポートされた方法にそれを高めました。 this answerで詳細を読むことができます。クリーンアップ関数の登録方法については、AppDomain.ProcessExitイベントと同様の処理が必要です。これを行う前に、最初の箇条書きに注目してください。

+0

良い答え!私はBeginInvoke-wayがタイムアウトよりも気分が良いと言うでしょう。 – FrankB

+0

これは、プログラムがシャットダウンしておらず、メインスレッドがイベントを待つ場合...メインスレッドが「アクティブ」に待機していても、ディスパッチャがメインスレッドにInvokeを取得するかどうかを示します。 – FrankB

+0

元の質問との関連性が不明です。しかし、メインスレッド内のどのような「待機」もデッドロックを引き起こす可能性があります。 Invoke()呼び出しは、メインスレッドがアイドル状態で、ディスパッチャーループを実行している場合にのみディスパッチできます。 –

1

イベントサブスクリプションに関しては、particluarオブジェクトがもう必要でないことを知ったときに、それらをクリーンアップすることをお勧めします。そうしないと、メモリリークが発生する危険性があります。 weak event pattern(MSDN)もご覧ください。

デッドロック自体については、コードを知らなくてもわかります。

私はHandleXYZ()が原因と思われません。あなたのIDisposable()実装を確認したいと思います。 MSDN documentationをご覧になり、実装と比較してください。

あなたの実装のどこかで、GarbageCollectorのタイミングに依存するいくつかのメソッド呼び出しが行われているとします。これは不確定的です。時には、あなたのケースでうまくいくことがあります。

+0

感謝を助けるコードを貼り付け...残念ながら処分()のコードが(外部部品) – FrankB

+1

質問は、@FrankBである私には利用できません、あなたはクリーンアップをしますか?原則として、 'IDispoeable()'を実装しているクラスは常にクリーンアップしてください。そのサードパーティ製のコンポーネントが何かを待っている場合、あなた自身のコードがいくつかのリソースを適切に解放しなかった可能性があります。 –

+0

他のコンポーネントは、イベントハンドラがメインスレッド(待機中のコンポーネントによってブロックされています...)を待つ間、イベントが戻るのを待ちます。 Dispatcherにメインスレッドの待機を強制的に停止させることができれば、クリーンアップは解決策に過ぎません。タイムアウトを設定する以外にもできますか? – FrankB

関連する問題