2012-01-09 12 views
2

状況:
私は非常に複雑なコンソールアプリケーションを持っており、それぞれがサブスレッドを生成します(3または4レベル用)。すべてが主にデリゲート/イベント駆動です。 スレッドが作成されるスコープ内のtry/catchブロックは、スレッドの実行開始時にそのスレッドとは無関係です。私はこれを管理するきれいな方法を見つけたいと思っています。説明の目的のためにマルチスレッドジャングルのグローバル例外処理 - フェイルセーフ/再起動

、次のパターンは私のアプリでは多くのレベルで頻繁に表示されます。

public void Activate() 
    { 
     ThreadPool.QueueUserWorkItem(Activate_Entrypoint);  
    } 

問題:
は限り私はまだ/デバッグ機能を開発していたとして、例外がフローに」投げられました"マイクロレベルで。
しかし、今はプロダクションパッケージを構築して準備する必要があります。そのため、例外が発生した場合でもすべてをスムーズに実行する必要があります。だから私はクリーンなユーザーメッセージ/ログとシャットダウン/再起動が必要ですトップレベルで。モードを上げる

例外:
私が期待するとして、これまで提起されていないようですが、私はOnUnhandledException

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException); 

を実装しています。 エラッタ編集:本当に正しくレイズするのですが、私は本編であまりにも遅くバインディングを宣言していたので発砲しませんでした。
私は、アプリケーションの動作を監視するために有効/無効にする別のスレッドでゼロ除算を入れました。

重要 - クリーンなデザイン:
私は、Appの残りの部分にオブザーバーを持つ、ただ一言で言えばするメイントップスレッドが必要です。 重大なエラーが発生した場合は、このスレッドをにすることをお勧めします。(起動した子アプリケーションスレッドを中止します)、次にを再起動してください。を再起動してください。あなたはそれを聞いた:私はちょうどすべてを停止する醜いクラッシュを望んでいない。私はそれがまだ実行されていることを確認し、それを再起動(それは24/7サーバー側のアプリケーションです)の世話をするラッパースレッドでアプリケーションを分離したいと思います。 私はまた、これが地獄であるあらゆる場所であらゆる例外を処理することを避けたいと思います。私はちょうど安全ベルトが発生した場合に処理されない例外を吹き飛ばし、アプリケーションをメインのスレッドから再起動することによってきれいに管理することを望みます。

考えられる解決策:
私は、スレッド間のフラグを渡すと、定期的な点検に関するいくつかの記事に出くわしました。興味深いと思うが、スレッドレベルをたくさん使用すると複雑になる可能性がある。 私はQuartz.netを使用して、いくつかのフラグで一定のスキャンタスクをスケジュールし、必要に応じてスレッドを停止して再起動するアクションを実行します。まだ完了していない、ちょうどそれを与える。

私が何かを見逃してしまった場合は、私に同行して詳細を尋ねてください。これは私が本当に快適である(まだではない)フィールドではありません。

資源: Joseph Albahari on Threading/

+0

AppDomain.UnhandledExceptionが動作する必要があります。なぜあなたはそれに問題があるだろう非常に不明。 –

+1

UnhandledExceptionが呼び出されていないことについては、0で割るのではなく明示的に例外をスローしようとしましたか?私は完全にはわかりませんが、ゼロ除算は「チェックされた」コンテキストでの例外の結果に過ぎないと考えています。デフォルトでコンパイラは '未チェック'の算術演算を使用し、例外をスローするのではなくNaNまたはINF値を生成します。 –

+0

確かに、AppDomainは1つしかないのですか? – rene

答えて

3

あなたはthis MSDN documentationに記載されて直面している問題:スレッドプールのスレッド上

未処理の例外プロセスを終了します。このルールには3つの例外があります。

スレッドプールスレッドでは、Abortが呼び出されたため、ThreadAbortExceptionがスローされます。

アプリケーションドメインがアンロードされているため、スレッドプールスレッドでAppDomainUnloadedExceptionがスローされます。

共通言語ランタイムまたはホストプロセスがスレッドを終了します。

共通言語ランタイムによって作成されたスレッドでこれらの例外が処理されない場合、例外はスレッドを終了させますが、共通言語ランタイムは例外をさらに進めません。

メインスレッドまたはアンマネージコードからランタイムに入ったスレッドでこれらの例外が処理されない場合、これらの例外は正常に処理され、アプリケーションが終了します。

この情報に基づいて、各親スレッドで例外を処理する必要があります。

私たちが非常によく似た設計をする方法は、親内のコレクションで開始された各スレッドを追跡することです。

親プロセスのメインループを通過するたびに、各スレッドの状態をチェックします。 スレッドがアクティブでなくなった(または一定期間応答しない)場合、何かが間違っていることがわかっているので、子プロセスを正常にシャットダウンしてから、最上位のプロセス、スレッドを終了します。

次に、メインスレッドが次のパススルーを実行すると、子スレッドが終了したことがわかり、必要に応じて再起動します。

私たちはこの同じ基本設計を少なくとも10年間実行しています(VB6でコアを開始しました)。これはさまざまな構成と負荷で非常にうまく機能しています。

+0

ありがとうございます。 'Thread.Abort()'は正常なシャットダウンですか? :) –

+0

はい。 ThreadAbortExceptionが発生し、未処理の場合は.Netはスレッドを終了させ、例外の伝播を続行しません。 –

+0

ハムム...そうです。私はこれを慎重に見せます。ありがとうございました –