使用任务并行库时如何处理所有未处理的exception?
我在.NET 4.0中使用TPL( 任务并行库 )。 我想通过使用Thread.GetDomain().UnhandledException
事件来集中处理所有未处理的exception的逻辑。 但是,在我的应用程序中,事件永远不会被启动TPL代码的线程触发,例如Task.Factory.StartNew(...)
。 事实上,如果我使用像new Thread(threadStart).Start()
。
这篇MSDN文章build议在使用TPL时使用Task#Wait()来捕获AggregateException
,但这不是我想要的,因为它不是“集中”足够的机制。
有没有人遇到同样的问题,还是只是我? 你有这个解决scheme吗?
我认为TaskScheduler.UnobservedTaskException事件是你想要的:
在故障的Task的未观测exception即将触发exception升级策略(默认情况下会终止该过程)时发生。
所以,这个事件类似于你在问题中提到的DomainUnhandledException
,但是只发生在任务上。
顺便说一下,不可观察的例外策略(是的,这不是一个未被发现的例外,MS的人发明了新的词…再次),从.NET 4.0更改为.NET 4.5。 在.NET 4.0中,未观察到的exception导致进程终止,但在.NET 4.5中 – 不。 这完全是因为我们在C#5和VB 11中有了新的asynchronous内容。
似乎没有内置的方法来处理这个问题(几乎2周后这个问题就没有答案了)。 我已经推出了一些自定义代码来照顾这个。 解决scheme描述非常冗长,所以我张贴在我的博客中。 如果你有兴趣,请参考这篇文章 。
2010年5月7日更新:我发现了一个更好的方法来做到这一点,利用任务延续。 我创build了一个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(); } }
我看到两个选项可用于集中TPL中的exception处理:1.使用Task Scheduler的Unobserved Task Exception事件。 2.使用延续执行故障状态任务。
使用Task Scheduler的Unobserved Task Exception事件。
任务计划程序有一个UnobservedTaskException事件,您可以使用operator + =来订阅它。
- 注1:在处理程序的主体中,您需要调用UnobservedTaskExceptionEventArgs参数上的SetObserved()来通知调度程序处理了exception。
- 注2:垃圾回收器收集任务时调用处理程序。
- 注3:如果你等待任务,你仍然被强制保护等待try / catch块。
- 注4:.NET 4.0和4.5中未处理的任务例外的默认策略是不同的。
简介:这种方法适用于“即丢即用”任务以及捕获从集中式exception处理策略中逃脱的exception。
对具有故障状态的任务使用延续。
使用TPL,您可以使用方法ContinueWith()将操作附加到任务,该方法需要附加操作和继续选项。 这个动作将在任务结束后被调用,并且只在选项指定的情况下被调用。 尤其是:
t.ContinueWith(c => { /* exception handling code */ }, TaskContinuationOptions.OnlyOnFaulted);
将exception处理代码连续安装到任务t。 此代码仅在Task t由于未处理的exception而终止的情况下运行。
- 注1:获取exception处理代码中的exception值。 否则它会冒出来的。
- 注2:任务终止后立即调用exception处理代码。
- 注3:如果在exception处理代码中得到exception,将被视为处理,在等待的任务上的try / catch块将无法捕获。
我认为集中式exception处理使用通过继续添加exception处理程序从任务inheritance的自定义任务会更好。 并伴随此方法使用任务计划程序的未观察任务exception事件来捕获尝试使用未定制的任务。