WPF 支持创建多个 UI 线程,跨窗口的或者窗口内的都是可以的;但是这个过程并不是线程安全的。
你有极低的概率会遇到 WPF 多线程 UI 的线程安全问题,说直接点就是崩溃。本文将讲述其线程安全问题。
此问题现已报告给微软:Creating multi-thread UI has a low probability to crash · Issue #297 · dotnet/wpf
本文内容
简述这个线程安全问题
必要条件:
- 创建多个 WPF UI 线程
- 其实两个就够了,一个我们平时写的 App 类所在的主 UI 线程;一个后台 UI 线程,例如用来显示启动闪屏的 UI 线程
- 两个线程的话你需要大量重复试验才能复现;而创建更多线程可以大大提高单次复现概率
- 这些 UI 线程都显示 WPF 窗口
- 无论是 .NET Framework 4.7.2 版本的 WPF,还是 .NET Core 3 版本的 WPF 都会出现此问题
现象:
- 抛出异常,程序崩溃
比如下面是其中一种异常:
Exception thrown: 'System.NullReferenceException' in WindowsBase.dll
Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
at System.IO.Packaging.PackagePart.CleanUpRequestedStreamsList()
at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at Walterlv.Bugs.MultiThreadedUI.SplashWindow.InitializeComponent() in C:\Users\lvyi\Desktop\Walterlv.Bugs.MultiThreadedUI\Walterlv.Bugs.MultiThreadedUI\SplashWindow.xaml:line 1
at Walterlv.Bugs.MultiThreadedUI.SplashWindow..ctor() in C:\Users\lvyi\Desktop\Walterlv.Bugs.MultiThreadedUI\Walterlv.Bugs.MultiThreadedUI\SplashWindow.xaml.cs:line 24
at Walterlv.Bugs.MultiThreadedUI.Program.<>c__DisplayClass1_0.<RunSplashWindow>b__0() in C:\Users\lvyi\Desktop\Walterlv.Bugs.MultiThreadedUI\Walterlv.Bugs.MultiThreadedUI\Program.cs:line 33
下图是 .NET Core 3 版本的 WPF 中在 Visual Studio 2019 抓到的异常: