About .Net System.Threading.Tasks UnHandled Exception


最初对线程异常的盲点

不得惭愧的说,之前我一直认为多线程中线程的未处理异常对程序 Main Thread 毫无影响。我觉得我之所以有这样的认识有以下几个原因(不是找借口哈):

如果不去究其原因,就只能想微软常说的那样“it was not a problem, that was by design.”, 但确实,有些东西预先就是这么设计的。

常见异步处理代码片段

It works Bad!

It works Good!

但如果你以为记住这些API的表现就行了,在以后的使用中就不会有什么问题了,那就太天真了,举个栗子:上边那些works good的API在不同版本.NET Framework下任有不同的表现。

特殊的"By Design"

微软对此有几个特殊的“By Design”,对于那些由Task.Factory.StartNew等相关方式创建的线程所抛出的UnhandledException,需要特别注意:

所以,在那些只装有.NET framework 4.0的机器上,我们的应用程序在GC回收时,若发现有未处理的线程异常,则会终止应用程序。

以上,我都全部验证过,的确如此,之前一直没注意这个,直到有一天用户抛给我一个bug.但如果.NET Framework一直保持Update,那么,这将不会是一个问题。

那么,如果我们想要在一个地方,统一处理所有的Unhandled Exception,如何做呢?
我们可以订阅TaskScheduler.UnobservedTaskException全局事件,该事件即可作为那些未处理异常的Handler,标记异常已被处理以改变.NET 4.0的默认行为(terminates the process).

后记

所以,只要涉及到多线程,就会增加程序的复杂度,就算你做好了多线程资源同步等等常规性的问题,总避免不了出现一些隐式的问题,直到发现它那天为止。

但也不是无法完全避免,比如只要涉及到有新的线程开销了,是否需要特别关注,线程内部的异常要怎么处理,如果做好了这样的“内聚”工作,相信线程间、模块间的依赖也就消失了,那么,自然问题也就少了。

(打赏)

If you want to pay for this
I will list your account name here.
HA HA!