我在.NET 4.0中使用TPL(Task Parallel Library)。我想通过使用Thread.GetDomain().UnhandledException
事件来集中处理所有未处理异常的处理逻辑。但是,在我的应用程序中,从未使用TPL代码启动的线程触发事件,例如, Task.Factory.StartNew(...)
。如果我使用类似new Thread(threadStart).Start()
的内容,事件确实会被触发。
This MSDN article建议在使用TPL时使用Task.Wait()来捕获AggregateException
,但这不是我想要的,因为这种机制不够“集中”。
有没有人遇到过同样的问题,还是仅仅是我?你对此有什么解决方案吗?
答案 0 :(得分:33)
我认为TaskScheduler.UnobservedTaskException Event就是你想要的:
在故障Task's未观察到的异常即将触发时发生 异常升级策略,默认情况下会终止 过程
因此,此事件类似于您在问题中提到的DomainUnhandledException
,但仅适用于任务。
答案 1 :(得分:21)
似乎没有内置的方法来处理这个问题(并且在将近两周之后没有回答这个问题)。我已经推出了一些自定义代码来处理这个问题。解决方案描述相当冗长,所以我发布在我的博客中。如果您有兴趣,请参阅this post。
2010年5月7日更新:我发现了一种更好的方法,可以继续使用任务。我创建了一个class ThreadFactory
来公开Error事件,该事件可以由顶级处理程序订阅,并提供启动任务的方法以及正确的继续。
代码已发布here。
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();
}
}
答案 2 :(得分:10)
我看到两个选项可用于在TPL中集中异常处理: 1.使用任务计划程序的未观察任务异常事件。 2.对故障状态的任务使用延续。
使用任务计划程序的未观察任务异常事件。
任务调度程序有一个UnobservedTaskException事件,您可以使用operator + =订阅它。
摘要:此方法适用于即发即弃任务以及捕获从集中式异常处理策略中转出的异常。
使用故障状态任务的延续。
使用TPL,您可以使用方法ContinueWith()将操作附加到任务,该方法采用附加操作和继续选项。在任务终止后将调用此操作,并且仅在选项指定的情况下调用。特别是:
t.ContinueWith(c => { /* exception handling code */ },
TaskContinuationOptions.OnlyOnFaulted);
将异常处理代码的继续安装到Task t。此代码仅在由于未处理的异常而终止任务t的情况下运行。
我认为集中式异常处理最好使用从Task继承的自定义任务,并通过continuation添加异常处理程序。并通过使用任务计划程序的未观察任务异常事件来捕获此方法,以捕获未使用自定义任务的尝试。