タスクパラレルライブラリを使用する場合、すべての未処理の例外を処理する方法は?
-
01-10-2019 - |
質問
私はTPLを使用しています(タスクパラレルライブラリ).NET 4.0。を使用して、すべてのハンドルされていない例外の処理ロジックを一元化したい Thread.GetDomain().UnhandledException
イベント。ただし、私のアプリケーションでは、TPLコードで開始されたスレッドの場合、イベントが発生することはありません。 Task.Factory.StartNew(...)
. 。私がのようなものを使用すると、イベントは確かに解雇されます new Thread(threadStart).Start()
.
このMSDNの記事 task.wait()を使用してキャッチすることを提案します AggregateException
TPLで作業するとき、しかし、このメカニズムは十分に「集中化」されていないため、それは私が望むものではありません。
誰かが同じ問題を経験していますか、それとも私だけですか?これに対する解決策はありますか?
解決 2
これを処理する組み込みの方法はないようです(ほぼ2週間後にこの質問に対する答えはありません)。私はすでにこれを処理するためにいくつかのカスタムコードを展開しています。ソリューションの説明はかなり長いので、ブログに投稿しました。参照する この郵便受け 興味があるなら。
2010年5月7日更新: タスクの継続を利用して、それを行うためのより良い方法を見つけました。私はaを作成します class ThreadFactory
これにより、トップレベルのハンドラーでサブスクライブできるエラーイベントが公開され、適切な継続で接続されたタスクを開始する方法を提供します。
コードが投稿されています ここ.
更新4/18/2011: 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();
}
}
他のヒント
おもう taskscheduler.unobservedtaskexceptionイベント あなたが望むものです:
障害があるときに発生します タスク 観察されていない例外は、例外エスカレーションポリシーをトリガーしようとしていることであり、デフォルトではプロセスを終了します。
したがって、このイベントはに似ています DomainUnhandledException
あなたはあなたの質問で言及したが、タスクのみで発生すること。
ところで、観察されていない削除ポリシー(ええ、これは観察されていない例外ではなく、MS Guysが新しい単語を発明しました...再び)は.NET 4.0から.NET 4.5に変更されたことに注意してください。 .NET 4.0では、未観測の例外はプロセス終了につながりますが、.NET 4.5-ではありません。これは、C#5とVB 11にある新しい非同期のものです。
TPLでの例外処理の集中化の目的に使用できる2つのオプションがあります。1。観察されていないタスク例外イベントのタスクスケジューラの使用。 2.障害状態のタスクの継続の使用。
タスクスケジューラの観察されていないタスク例外イベントの使用。
タスクスケジューラには、Operator +=を使用してサブスクライブすることができる未観察のakskexceptionイベントがあります。
- 注1:ハンドラーの本文では、例外が処理されたことをスケジューラに通知するために、obsaskexceptioneventargs引数でsetobserved()を呼び出す必要があります。
- 注2:ハンドラーは、タスクがガベージコレクターによって収集されたときに呼び出されます。
- 注3:タスクを待つ場合は、トライ/キャッチブロックによって待機を保護することを余儀なくされます。
- 注4:.NET 4.0と4.5の未処理タスクの例外のデフォルトポリシーは異なります。
概要:このアプローチは、火災とフォゲットのタスクや、集中型例外処理ポリシーから逃げた例外をキャッチするのに適しています。
障害状態のタスクの継続の使用。
TPLを使用すると、アクションと継続オプションを添付するMethod継続()を使用してタスクにアクションを添付できます。このアクションは、タスク終了後に呼び出され、オプションで指定された場合のみです。特に:
t.ContinueWith(c => { /* exception handling code */ },
TaskContinuationOptions.OnlyOnFaulted);
タスクtへの例外処理コードを使用して継続をインストールします。このコードは、未解決の例外のためにタスクTが終了した場合にのみ実行されます。
- 注1:例外処理コードで例外値を取得します。それ以外の場合は、バブルアウトされます。
- 注2:例外処理コードは、タスク終了後すぐに呼び出されます。
- 注3:例外が例外コードで取得された場合、それは処理されていると見なされます、タスクの待機でブロックを試してみてください。
継続的に追加された例外ハンドラーを使用して、タスクから継承されたカスタムタスクを使用するための集中型例外ハンドリングの方が良いと思います。観察されていないタスク例外イベントのタスクスケジューラのイベントを使用して、カスタマイズされていないタスクを使用しようとする試みを使用して、このアプローチに伴います。