【问题标题】:Why does System.Threading.Timer callback successfully update UI?为什么 System.Threading.Timer 回调成功更新 UI?
【发布时间】:2012-06-04 16:31:25
【问题描述】:

我的表单应用程序中有几个 System.Threading.Timers 带有更新 UI 的回调...成功 - 即没有抛出错误。

在我知道不应该在 UI 线程以外的任何线程上更新 UI 之前,我已经构建了这些。

现在我很困惑为什么当我在这些单独的 threading.timer 线程上更新 UI 时它不会引发跨线程异常?

我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。

编辑:我的应用程序是一个 WinForms 应用程序。

【问题讨论】:

  • 你能给我们看一些代码吗?我不认为这项工作完全像你的答案那样靠运气。我从来没有看到它没有失败。
  • @gbianchi 这取决于正在更新的控件。在检查跨线程更新方面,一些控件比其他控件更好。通过某些控件,它“有时”可以工作。
  • 您的可执行文件在发布模式下编译。 Microsoft 有意禁用对非调试代码的检查以保持向后兼容。因此,它会起作用,但可能会导致细微的错误或偶尔出现故障,具体取决于您的具体操作。

标签: c# winforms multithreading thread-safety


【解决方案1】:

我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。

如果这是 Windows 窗体,则完全靠运气。在后台线程上更新 UI 并不能始终如一地工作,但偶尔不会抛出。特别是,如果CheckForIllegalCrossThreadCalls 为假,它有时会“工作”,并且永远不会抛出 - 尽管行为通常是错误的。一些控件并不总是检查每个属性,因此一些项目即使它们并不总是正常工作,也“工作”,因为这通常会引入以后难以诊断和纠正的错误。

附带说明:如果这是 WPF,您可以在后台线程上更改绑定到 UI 的项目的值,从而有效地更新您的 UI。 WPF 绑定系统会自动为您将其编组到 UI 线程。但是,更改集合的一部分是行不通的。

【讨论】:

    【解决方案2】:

    我在使用 WinForms 时也遇到过这种情况。见这里:Can you access UI elements from another thread? (get not set) 在我看来,它的工作原理是“魔法”(读作“随机方式”),不应被视为在实践中这样做的邀请。这绝不是更新 GUI 的线程安全方式。有时程序不会抱怨。

    【讨论】:

      【解决方案3】:

      在 .NET 1.0 和 1.1 中,不执行跨线程检查,因此您永远不会收到InvalidOperationException(尽管 MSDN 承认执行跨线程更新“通常会导致不可预知的结果”,其中可能包括应用程序崩溃)。

      在 .NET 2.0 及更高版本中,根据 Control.CheckForIllegalCrossThreadCalls 静态属性的值执行跨线程检查。它的默认值是从Debugger.IsAttached 静态属性初始化的(指示是否将调试器附加到进程),这意味着当应用程序自行运行时(没有 Visual Studio 或任何其他调试器)不执行跨线程检查附在上面)。

      这个设置当然可以被用户代码覆盖,包括引用的库。

      【讨论】:

        【解决方案4】:

        我相信这与您创建的计时器类型有关。有两种类型:

            System.Timers.Timer;
            System.Windows.Forms.Timer 
        

        这两者之间有明显的区别,如果您更新 UI,System.Timers.Timer 会抛出异常,而 System.Windows.Forms.Timer 不会。如果你有一个 using 语句:“Using System.Windows.Forms”并且只是有一个“Timer”,这将是 Windows.Forms.Timer,它与 System.Timers.Timer 明显不同。

        在后台(我相信)System.Windows.Forms.Timer 正在捕获 WM_TIMER 消息,因此您处于更新 GUI 的线程上。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-06
          • 1970-01-01
          相关资源
          最近更新 更多