使用 SystemEvents.UserPreferenceChanged 和多个 UI 线程时 UI 冻结

问题描述 投票:0回答:1

在我的 C# Windows 窗体应用程序中,有两个线程:

  1. 主线程(Program.cs)
  2. WorkerClass 线程(STA-公寓)。

当任务长时间运行时,它会冻结/卡住整个进程,并且不会引发任何异常或通知。它会挂起应用程序。

内部应用程序仅处理记录(从 SQL 表中选择并插入 Access DB 表)

UI 更新将使用事件操作功能完成。

查找卡住的进程并行任务的附加快照。似乎线程在内部相互等待并导致进程阻塞。与

SystemEvents.UserPreferenceChanged
事件相关的代码位于其中一个堆栈上。

为什么会发生这种情况以及如何解决?

Application Stuck Process

c# .net winforms ui-thread sta
1个回答
5
投票

它在

SystemEvents.UserPreferenceChanged
事件上陷入僵局。 这是具有多个线程死锁的窗口的应用程序的标准方式。调用死锁的最佳方法是按 Windows+L 键。 您可以在这篇博文中看到对这个死锁的深入分析。

SystemEvents
类是这里的麻烦制造者,它尝试在程序的 UI 线程上引发事件。这非常重要,UI 不是线程安全的。问题是,您有 two 线程创建了 UI。
SystemEvents
无法猜测哪一个是正确的,它只有 50% 的几率,所以注定会猜错。 如果它最初猜错了程序中的哪个线程是 UI 线程,并且该线程退出了,那么它将是 100% 错误。

这当然使得在工作线程上创建 UI 变得极其危险。 这在技术上是可行的,但是您必须避免使用工具箱中的多个控件。 当

UserPreferenceChanged
事件在错误的线程上引发时,他们不能很好地处理该事件。 肯定导致死锁的是 DataGridView、NumericUpDown、DomainUpDown、ToolStrip+MenuStrip 和 ToolStripItem 派生类。 不确定的(无法足够深入地分析代码)是 RichTextBox 和 ProgressBar。 从你的调用堆栈来看,看起来我应该将 ProgressBar 放在第一组中。

真正的解决方法是在工作线程上创建 UI。 这从来没有必要,你的程序的 UI 线程已经能够处理任意数量的窗口。

© www.soinside.com 2019 - 2024. All rights reserved.