在 TPL 中快速抛出未处理的异常
Posted
技术标签:
【中文标题】在 TPL 中快速抛出未处理的异常【英文标题】:Fast throw unhandled exceptions in TPL 【发布时间】:2016-02-07 09:32:19 【问题描述】:我的问题:我想在 .NET 4 下的 WinForms 应用程序中使用 TPL,并且 我需要任务继续来立即提升任何未处理的异常(“快速抛出”),而不是等待 GC
收集 @987654322 @. 有可能吗?
在支持async/await
的.NET 4.5 中,可以编写:
如果没有在Excecute
方法中处理,将立即抛出继续中的异常。
如何在没有async/await
支持的情况下在 .NET 4 中实现相同的行为?
【问题讨论】:
【参考方案1】:首先,您应该知道可以将 async-await 与 .Net 4.0 与 Microsoft.Bcl.Async
一起使用
但如果没有它,您可以使用 ContinueWith
向任务添加延续,并仅在出现 TaskContinuationOptions.OnlyOnFaulted
异常时运行它
Me.LongWork().ContinueWith(Sub(task) MsgBox(task.Exception.Message), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted)
【讨论】:
这不能回答我的问题——我想“快速抛出”任何未处理的异常。也许我因为带有处理程序的示例而引入了一些混淆。但是想象一下没有处理程序。或者任何异常处理程序总是有可能自己引发异常。我希望立即抛出这些异常,而 TPL 不会将它们作为 UnobservedTaskException 吞下。 在整个调用堆栈中提升和冒泡异常。途中可能有我的自定义处理程序可以正确处理它。没有处理程序拆除应用程序,是的。 @mancze 只要没有线程等待它,任务就没有调用堆栈可以冒泡。您可以使用Task.Wait
阻止任务,但随后使用 TPL 开始将毫无意义。
我明白了,您已经明白了该任务本身没有特定的调用堆栈。除非我将任务安排到特定线程(ui 线程)。调用 Wait
可以解决问题,但会阻止我不想这样做的 ui 线程。我想尽快“Wait
”,因为抛出异常。继续使用Wait
是不行的,因为再次 - 它的未处理异常将被 TPL 捕获。
我很乐意将您的答案标记为解决方案,因为您正确指出可以通过Microsoft.Bcl.Async
添加async/await
支持。它帮助我找到了自己的解决方案。如果您能强调答案的这一部分,我会很高兴。后面的部分不太相关。【参考方案2】:
1) 可以按照 i3arnon 的建议使用 Microsoft.Bcl.Async
。
2) 或者,如果您不想引用额外的库,我已经提出了基于 async/await
的解决方案。背后的魔力很糟糕,但它是我拥有的最好的。
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Threading
Public Module TaskExtensions
''' <summary>Throws the exception on the current SynchronizationContext or ThreadPool if there is none.</summary>
''' <param name="task">Task whose faulted continuation should throw exception.</param>
<Extension()>
Public Sub ThrowOnFaulted(task As Task)
Dim context = SynchronizationContext.Current
ThrowOnFaulted(task, context)
End Sub
''' <summary>Throws the exception on the ThreadPool in given context.</summary>
''' <param name="task">Task whose faulted continuation should throw exception.</param>
''' <param name="targetContext">The target context on which to propagate the exception. Null to use the ThreadPool.</param>
<Extension()>
Public Sub ThrowOnFaulted(task As Task, targetContext As SynchronizationContext)
task.ContinueWith(Sub(t) ThrowOnFaultedCore(t, targetContext), TaskContinuationOptions.OnlyOnFaulted)
End Sub
''' <remarks>Taken from System.RunTime.CompilerServices.AsyncServices.</remarks>
Private Sub ThrowOnFaultedCore(task As Task, targetContext As SynchronizationContext)
Dim exception = task.Exception
If targetContext IsNot Nothing Then
Try
targetContext.Post(Sub(state) Throw DirectCast(state, Exception), exception)
Return
Catch ex As Exception
exception = New AggregateException(exception, ex)
End Try
End If
ThreadPool.QueueUserWorkItem(Sub(state) Throw DirectCast(state, Exception), exception)
End Sub
End Module
它符合要求 - “快速”抛出异常并且可以处理。异常被Post
ed 到目标SynchronizationContext
,从而逃避了TPL 的异常捕获机制。它远非快速和同步,但至少它比等待任务处理表现得更好。
【讨论】:
以上是关于在 TPL 中快速抛出未处理的异常的主要内容,如果未能解决你的问题,请参考以下文章
Visual C ++ - 从设置表单图标中抛出未处理的异常?
抛出未处理的异常:读取访问冲突。 x 是 0x20B4112
C++ Battle4Zion 项目抛出未处理的异常:读取访问冲突。 **this** 是 nullptr。发生了
抛出未处理的异常:写访问冲突。 bunnies_array 是 0x5CB3CBA
Visual Studio 2019 c++latest random_device uniform_int_distribution 抛出未处理的异常