42

.NET 4.0 でTPL ( Task Parallel Library ) を使用しています。Thread.GetDomain().UnhandledExceptionイベントを使用して、未処理のすべての例外の処理ロジックを一元化したいと考えています。ただし、私のアプリケーションでは、TPL コードで開始されたスレッドに対してイベントが発生することはありませんTask.Factory.StartNew(...)。のようなものを使用すると、実際にイベントが発生しnew Thread(threadStart).Start()ます。

この MSDN の記事では、TPL を使用するときに Task.Wait() を使用してキャッチすることを提案していますAggregateExceptionが、このメカニズムは十分に「集中化」されていないため、これは私が望んでいることではありません。

誰かがまったく同じ問題を経験していますか、それとも私だけですか? これに対する解決策はありますか?

4

3 に答える 3

35

TaskScheduler.UnobservedTaskException Eventはあなたが望むものだと思います:

失敗したタスクの監視されていない例外が例外エスカレーション ポリシーをトリガーしようとしているときに発生し、既定ではプロセスが終了します。

したがって、このイベントは質問で言及したものと似てDomainUnhandledExceptionいますが、タスクに対してのみ発生します。

ところで、監視されていない例外ポリシー (ええ、これは監視されていない例外ではありません。MS の人たちは新しい単語を発明しました... 再び) が .NET 4.0 から .NET 4.5 に変更されたことに注意してください。.NET 4.0 では観察されない例外によりプロセスが終了しますが、.NET 4.5 では発生しません。これはすべて、C# 5 と VB 11 に含まれる新しい非同期機能によるものです。

于 2012-03-11T11:56:05.923 に答える
21

これを処理するための組み込みの方法がないようです (そして、ほぼ 2 週間後にこの質問への回答はありません)。これを処理するために、いくつかのカスタム コードを既に公開しています。ソリューションの説明はかなり長いので、ブログに投稿しました。気になる方はこちらの記事を参考にしてください。

2010 年 5 月 7 日更新:タスクの継続を利用して、それを行うためのより良い方法を見つけました。class ThreadFactory最上位のハンドラーによってサブスクライブできる Error イベントを公開し、適切な継続が関連付けられたタスクを開始するメソッドを提供する を作成します。
コードはここに掲載されています。

2011 年 4 月 18 日更新: Nifle のコメントに従って、ブログ投稿からコードを投稿します。

internal class ThreadFactory
{
    public delegate void TaskError(Task task, Exception error);

    public static readonly ThreadFactory Instance = new ThreadFactory();

    private ThreadFactory() {}

    public event TaskError Error;

    public void InvokeError(Task task, Exception error)
    {
        TaskError handler = Error;
        if (handler != null) handler(task, error);
    }

    public void Start(Action action)
    {
        var task = new Task(action);
        Start(task);
    }

    public void Start(Action action, TaskCreationOptions options)
    {
        var task = new Task(action, options);
        Start(task);
    }

    private void Start(Task task)
    {
        task.ContinueWith(t => InvokeError(t, t.Exception.InnerException),
                            TaskContinuationOptions.OnlyOnFaulted |
                            TaskContinuationOptions.ExecuteSynchronously);
        task.Start();
    }
}
于 2010-05-04T16:56:16.853 に答える
12

TPL で例外処理を集中化するために使用できるオプションが 2 つあります。 1. タスク スケジューラの監視されていないタスク例外イベントを使用します。2.フォルト状態のタスクの継続の使用。

タスク スケジューラの監視されていないタスクの例外イベントの使用。

タスク スケジューラには、演算子 += を使用してサブスクライブできる UnobservedTaskException イベントがあります。

  • 注 1: ハンドラーの本体では、 UnobservedTaskExceptionEventArgs 引数で SetObserved() を呼び出して、例外が処理されたことをスケジューラーに通知する必要があります。
  • 注 2: ハンドラーは、タスクがガベージ コレクターによって収集されたときに呼び出されます。
  • 注 3: タスクを待機する場合でも、try/catch ブロックによって待機を保護する必要があります。
  • 注 4: .Net 4.0 と 4.5 の未処理のタスク例外の既定のポリシーは異なります。

概要: このアプローチは、ファイア アンド フォーゲット タスクや、一元化された例外処理ポリシーから逃れた例外のキャッチに適しています。

障害状態のタスクの継続の使用。

TPL を使用すると、アタッチ アクションと継続オプションを取るメソッド ContinueWith() を使用して、タスクにアクションをアタッチできます。このアクションは、オプションで指定された場合にのみ、タスクの終了後に呼び出されます。特に:

    t.ContinueWith(c => { /* exception handling code */ },
                   TaskContinuationOptions.OnlyOnFaulted);

Task t に例外処理コードを含む継続をインストールします。このコードは、未処理の例外が原因でタスク t が終了した場合にのみ実行されます。

  • 注 1: 例外処理コードで例外値を取得します。そうしないと、泡が出ます。
  • 注 2: 例外処理コードは、タスクの終了直後に呼び出されます。
  • 注 3: 例外が例外処理コードで取得された場合、それは処理済みと見なされ、タスク待機中の try/catch ブロックはそれをキャッチできません。

Task から継承されたカスタム Task を使用し、継続によって例外ハンドラーを追加した方が、集中型の例外処理に適していると思います。また、タスク スケジューラの Unobserved Task Exception イベントを使用して、カスタマイズされていないタスクを使用しようとする試みをキャッチすることにより、このアプローチに付随します。

于 2014-12-02T22:05:54.263 に答える