当前位置: 首页 > news >正文

如何防止后台线程抛出的异常让程序崩溃退出

如果你的程序抛了异常,你是怎么处理的呢?等待程序崩溃退出?还是进行补救?

如果是做 UI 开发,很容易就找到 Dispatcher.UnhandledException 事件,然后在事件中进行补救。如果补救成功,可以设置 e.Handled = true 来阻止异常继续让程序崩溃退出。但是,如果是后台线程抛出了异常呢?并没有 Dispatcher 可以用。所以我们就束手就擒让程序自己退出吗?


WPF 和 Windows Forms 都是微软的框架,为了照顾初学者,微软会默认每一个开发者都不会正确地处理异常。于是在异常发生之后,微软 Windows 会假设开发者并不知道如何应对以便让应用程序正常工作,就擅自将应用程序进程结束掉,以便防止应用程序自己内部产生奇怪的状态和错误,避免对系统环境造成不可逆的严重后果。

能够写出异常处理代码的开发者,微软会默认他们懂了异常处理。

写出了监听 Dispatcher.UnhandledException 事件的开发者,微软会认为他们已经学会了如何在 UI 线程中处理异常。于是允许开发者设置 e.Handled = true 来标记异常已被正确处理,程序可以不用退出了。

还有一个事件 Appdomain.CurrentDomain.UnhandledException,然而这个事件却并不允许开发者标记 e.Handled = true。因为微软认为,应用程序域中所有的线程发生异常都会进入这个事件中,大多数开发者都不明白这些线程这些异常是怎么回事,所以不认为这些开发者具备正确处理这些异常的能力。比如 WPF 的触摸模块发生了异常,开发者知道如何恢复吗?并不知道,还不如结束掉程序然后重启呢!

在这个事件中,有一个属性 IsTerminating 指示是否应用程序正因为这次异常准备退出,不过开发者并不能拿这个属性做些什么。

但还是要照顾更高级的开发者的,于是祭出新的配置——legacyUnhandledExceptionPolicy

app.config 文件的 <runtime> 节点中添加如下代码:

<legacyUnhandledExceptionPolicy enabled="1"/>  

加上了这个配置之后,Appdomain.CurrentDomain.UnhandledException 事件的 IsTerminating 就变成了 false 啦!也就是说,程序并不会因为这次的异常而崩溃退出。

既然你通过这个配置节点于微软达成了契约,你就需要好好地在 Appdomain.CurrentDomain.UnhandledException 事件中写好异常的恢复逻辑。如果不好好恢复,小心有些致命的异常会导致你的程序出现雪崩式的错误,最终 Windows 还是会通过 CorruptedStateException 把你干掉的!


参考资料

  • c# - How to prevent an exception in a background thread from terminating an application? - Stack Overflow
  • Exceptions in Managed Threads - Microsoft Docs

相关文章:

  • CaptureMouse/CaptureStylus 可能会失败
  • 使用 ExceptionDispatchInfo 捕捉并重新抛出异常
  • 使用 Task.Wait()?立刻死锁(deadlock)
  • 如何实现一个可以用 await 异步等待的 Awaiter
  • WPF 同一窗口内的多线程 UI(VisualTarget)
  • WPF 和 UWP 中,不用设置 From 或 To,Storyboard 即拥有更灵活的动画控制
  • 从 “x is null 和 x == null” 的区别看 C# 7 模式匹配中常量和 null 的匹配
  • 使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用
  • WPF 跨应用程序域的 UI(Cross AppDomain UI)
  • 将 UWP 的有效像素(Effective Pixels)引入 WPF
  • 用动画的方式画出任意的路径(直线、曲线、折现)
  • 使 WPF 支持触摸板的横向滚动
  • NullReferenceException,就不应该存在!
  • 当我们使用 MVVM 模式时,我们究竟在每一层里做些什么?
  • 分享一个算法,计算能在任何背景色上清晰显示的前景色
  • 30秒的PHP代码片段(1)数组 - Array
  • docker-consul
  • HTTP请求重发
  • js数组之filter
  • linux安装openssl、swoole等扩展的具体步骤
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Webpack 4x 之路 ( 四 )
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 利用DataURL技术在网页上显示图片
  • 漂亮刷新控件-iOS
  • 如何优雅地使用 Sublime Text
  • #NOIP 2014#Day.2 T3 解方程
  • (9)STL算法之逆转旋转
  • (TOJ2804)Even? Odd?
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)基于IDEA的JAVA基础1
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转) ns2/nam与nam实现相关的文件
  • (转)3D模板阴影原理
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .bat文件调用java类的main方法
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .net连接oracle数据库
  • .NET命令行(CLI)常用命令
  • .NET委托:一个关于C#的睡前故事
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @RequestMapping用法详解
  • @zabbix数据库历史与趋势数据占用优化(mysql存储查询)
  • [ IO.File ] FileSystemWatcher
  • [20171102]视图v$session中process字段含义
  • [30期] 我的学习方法
  • [Angular] 笔记 21:@ViewChild
  • [C]整形提升(转载)
  • [emacs] CUA的矩形块操作很给力啊
  • [FUNC]判断窗口在哪一个屏幕上
  • [Golang]K-V存储引擎的学习 从零实现 (RoseDB mini版本)
  • [Hadoop in China 2011] Hadoop之上 中国移动“大云”系统解析
  • [Java][Android][Process] ProcessBuilder与Runtime差别