【问题标题】:UI freezes when using SystemEvents.UserPreferenceChanged and multiple UI threads使用 SystemEvents.UserPreferenceChanged 和多个 UI 线程时 UI 冻结
【发布时间】:2014-09-22 13:33:08
【问题描述】:

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

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

当有长时间运行的任务时,它会冻结/卡住整个进程并且没有异常或通知被触发..它挂起应用程序。

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

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

为卡住的进程并行任务查找附加快照。似乎线程在内部相互等待并阻止进程。与SystemEvents.UserPreferenceChanged 事件相关的代码位于其中一个堆栈中。

为什么会发生这种情况,我该如何解决?

【问题讨论】:

  • 用VS和break附加进程,然后检查所有的调用堆栈,你应该可以找到它挂在哪里
  • 为什么你的工作线程是 STA 线程?不要为它指定公寓模型。
  • "UI 更新将使用 .net 事件操作功能完成。"这是非常模糊的。发布所有相关代码。目前我们只能猜测。
  • 谁投了反对票?嘘。如果这个问题不存在,我可能永远找不到完全相同的问题。

标签: c# .net winforms ui-thread sta


【解决方案1】:

它在 SystemEvents.UserPreferenceChanged 事件上死锁。这是具有多个线程上的窗口的应用程序死锁的标准方式。调用死锁的最佳方法是按 Windows+L 键。你可以在this blog post看到这个死锁的深入分析。

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

当然,这使得在工作线程上创建 UI 非常危险。这在技术上是可行的,但是您必须避免使用工具箱中的多个控件。当在错误的线程上引发 UserPreferenceChanged 事件时,他们不能很好地处理它。 肯定导致死锁的是 DataGridView、NumericUpDown、DomainUpDown、ToolStrip+MenuStrip 和 ToolStripItem 派生类。有问题的(不能足够深入地分析代码)是 RichTextBox 和 ProgressBar。看起来我应该把 ProgressBar 放在第一组,从你的调用堆栈来看。

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

【讨论】:

    猜你喜欢
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多