2013-07-26 14 views
5

私は終了時にイベントを通知するワーカースレッドを持っています。このイベントは、メインスレッドにマーシャリングされ、ワー​​カースレッドの終了を通知します。ワーカースレッドが未処理の例外を検出すると、この例外はメインスレッドのエラー処理システムによって処理されます。そのため、ワーカースレッドは予期しない終了を示すプロパティを設定し、その例外を別のプロパティに保存し、イベントを通知して終了します。スレッドが予期せず終了したときにスローする例外はありますか?

イベントがメインスレッドにマーシャリングされた後、元の例外を内部例外として設定して新しい例外をスローしたいとします。私の質問は、この新しいExceptionの型はどうすればいいのですか?このような状況のために特定のSystem.somethingExceptionがあるかどうか、この特定の状況に対して自分自身のExceptionクラスを設計するか、適切なメッセージで標準System.Exceptionをスローする必要がありますか?

C#の-psuedoコード:私はあなたがTaskでバックグラウンド作業を行うと、そのタスクの継続で例外を処理することにより、未処理のバックグラウンド例外のハンドリングに必要なすべての例外を行うことができると信じて

class MyThread 
{ 
    public TerminationState Termination { get; private set; } 
    public Exception UncaughtException { get; private set; } 

    public delegate void ThreadTerminatedDelegate(MyThread thread); 
    public event ThreadTerminatedDelegate ThreadTerminated; 

    private void run() 
    { 
     try 
     { 
      doSomeWork(); 
     } 
     catch(Exception e) 
     { 
      UncaughtException = e; 
      Termination = TerminationState.AbortOnException; 
      ThreadTerminated(this); 
      return; 
     } 
     Termination = TerminationState.NormalTermination; 
     ThreadTerminated(this); 
    } 
} 

class MainThread 
{ 
    private MyThread myThread = new MyThread(); 

    private void run() 
    { 
     myThread.ThreadTerminated += handleTermination; 
     myThread.Start(); 
    } 

    private void handleTermination(MyThread thread) 
    { 
     if (InvokeRequired) 
     { 
      MyThread.ThreadTerminatedDelegate cb = new MyThread.ThreadTerminatedDelegate(handleTermination); 
      BeginInvoke(cb, new object[] { thread }); 
     } 
     else 
     { 
      if (thread.Termination == TerminationState.AbortOnException) 
      { 
       if (isFatal(thread.UncaughtException)) 
        throw new Exception("", thread.UncaughtException); //what to do here? 
       else 
        fixTheProblem(); 
      } 
      else 
      { 
       //normal wrapping up 
      } 
     } 
    } 
} 
+0

スレッドが何をしているかによって異なります。実際に私は、AggregateExceptionがフラットなものを汎用エラーに似ていないので、元の例外を他のものに呑み込むことはできません。そのような良い考えはしません。私はそれを(元のスタックトレースを維持するために)クローンしたいと思います。しかしそれはちょうど私の意見です... –

+0

例外を再びスローすると、どういうことが起こりたいですか? 99%の確率はあなたのプログラムがクラッシュすることです。何が良いものなのか、何かが成し遂げられなかったのです。しかし、最初は例外をキャッチしても構いません。それも同様にクラッシュしますが、少なくともあなたはより良い診断を得て、無駄なコードを書く必要はありません。 –

+0

@Adrianoクローンと再スローイングの代わりに、 'throw;'を使うことはできませんでしたか?元のスタックトレースはそのままです – JSQuareD

答えて

1

こと明示的にメインスレッド上で実行するようにスケジュールされています。継続に指定できる追加オプションがありますが、これはシナリオに当てはまるはずです。

Task.Factory.StartNew(
    () => 
    { 
     // Do some work that may throw. 
     // This code runs on the Threadpool. 
     // Any exceptions will be propagated 
     // to continuation tasks and awaiters 
     // for observation. 
     throw new StackOverflowException(); // :) 
    } 
).ContinueWith(
    (a) => 
    { 
     // Handle your exception here. 
     // This code runs on the thread 
     // that started the worker task. 
     if (a.Exception != null) 
     { 
      foreach (var ex in a.Exception.InnerExceptions) 
      { 
       // Try to handle or throw. 
      } 
     } 
    }, 
    CancellationToken.None, 
    TaskContinuationOptions.None, 
    TaskScheduler.FromCurrentSynchronizationContext() 
); 

もう1つの有用なリンクはMSDN's Asyncronous Programming Patternsです。アプリケーションで非同期操作を実装する3つの主な方法を示します。現在の実装は、記事でEAP(イベントベースの非同期パターン)と呼ばれるものと最もよく似ています。

個人的には、.NET 4.0 TPL(Task Parallel Library)に依存するTAP(タスクベースの非同期パターン)が望ましいです。構文の簡潔さと広範な能力のために、マスタリングする価値があります。 MSDNから

:(もたIAsyncResultパターンと呼ばれる)

  • 非同期プログラミングモデル(APM)のパターン、非同期操作を開始および終了方法が必要です(例えば、非同期書き込み操作のためのBeginWriteおよびEndWrite)。このパターンは新しい開発にはもはや推奨されません。詳細については、「非同期プログラミングモデル(APM)」を参照してください。
  • イベントベースの非同期パターン(EAP)。非同期サフィックスを持つメソッドが必要で、1つ以上のイベント、イベントハンドラの委任タイプ、およびEventArgの派生タイプも必要です。 EAPは.NET Framework 2.0で導入されました。新しい開発にはもはやお勧めできません。詳細については、「イベントベースの非同期パターン(EAP)」を参照してください。
  • タスクベースの非同期パターン(TAP)。単一のメソッドを使用して非同期操作の開始と完了を表します。 TAPは.NET Framework 4で導入され、.NET Frameworkでの非同期プログラミングの推奨アプローチです。詳細については、「タスクベースの非同期パターン(TAP)」を参照してください。

また、信頼できるBackgroundWorkerクラスについても忘れないでください。このクラスは長い間私にとって重要なものでしたが、TAPによって幾分廃止されましたが、それでも仕事は終わり、理解して使いやすいです。

// Create a new background worker. 
var bgw = new BackgroundWorker(); 

// Assign a delegate to perform the background work. 
bgw.DoWork += (s, e) => 
    { 
     // Runs in background thread. Unhandled exceptions 
     // will cause the thread to terminate immediately. 
     throw new StackOverflowException(); 
    }; 

// Assign a delegate to perform any cleanup/error handling/UI updating. 
bgw.RunWorkerCompleted += (s, e) => 
    { 
     // Runs in UI thread. Any unhandled exception that 
     // occur in the background thread will be accessible 
     // in the event arguments Error property. 
     if (e.Error != null) 
     { 
      // Handle or rethrow. 
     } 
    }; 

// Start the background worker asynchronously. 
bgw.RunWorkerAsync(); 
+0

答えをありがとう!今は休暇中ですので、見る時間がありません。来週になると、詳細を見て問題が解決すれば回答を受け入れます。 :) – JSQuareD

+1

うん、これは私の醜いハックのエレガントな代案です、ありがとう!また、さまざまな非同期プログラミングパターンの監視のおかげで、私は "C#を一言で"読むようになり、おそらく来る時間にこれらの方法でうまくいくでしょう。 :) – JSQuareD

関連する問題