代码之家  ›  专栏  ›  技术社区  ›  TalentTuner

为什么只允许用户界面线程修改用户界面?

  •  22
  • TalentTuner  · 技术社区  · 14 年前

    我知道如果我从不同的线程修改一个控件,我应该小心,因为winforms和wpf不允许从其他线程修改控件的状态。

    为什么有这样的限制?

    如果我可以编写线程安全代码,我应该能够安全地修改控制状态。那么,为什么存在这种限制呢?

    6 回复  |  直到 14 年前
        1
  •  23
  •   Brian Rasmussen    14 年前

    几个GUI框架都有这个限制。根据这本书 Java Concurrency in Practice 这样做的原因是为了避免复杂的锁定。问题是,GUI控件可能必须对来自UI、数据绑定等的两个事件做出反应,这会导致来自多个不同源的锁定,从而产生死锁风险。为了避免这种情况,.NET WinForms(和其他UI)将对组件的访问限制在单个线程上,从而避免锁定。

        2
  •  9
  •   Steve Ellinger    14 年前

    对于Windows,当创建控件时,通过消息泵的消息执行UI更新。编程器无法直接控制泵运行的线程,因此控制消息的到达可能导致控制状态的更改。如果允许另一个线程(程序员直接控制的线程)更改控件的状态,那么必须设置某种同步逻辑,以防止控件状态损坏。.NET中的控件不是线程安全的;我怀疑这是设计的。在所有控件中加入同步逻辑在设计、开发、测试和支持提供此功能的代码方面都是昂贵的。程序员当然可以为控件提供线程安全性。 为了他自己的准则 ,但不适用于.NET中与其代码同时运行的代码。此问题的一个解决方案是将这些类型的操作仅限于一个线程和一个线程,这使得.NET中的控制代码更易于维护。

        3
  •  3
  •   Ben Voigt    14 年前

    .NET保留随时访问创建它的线程中的控件的权利。因此,来自另一个线程的访问永远不会是线程安全的。

        4
  •  2
  •   Brian Gideon    14 年前

    您可能能够使自己的代码线程安全,但无法将必要的同步原语注入内置的winform和wpf代码中,这些代码与代码中的代码匹配。记住,有很多消息在幕后传递,最终导致UI线程访问控件,而您从未真正意识到它。

    控件线程关联的另一个有趣的方面是 能够 (尽管我怀疑他们不会)使用 Thread Local Storage 模式。显然,如果您访问的线程上的控件不是在其上创建的控件,那么无论您多么仔细地构造代码以防止多线程代码的所有正常问题,它都将无法访问正确的TLS数据。

        5
  •  1
  •   Theodore Zographos    14 年前

    实际上,据我所知,这是从一开始的计划!每个控件都可以从任何线程访问!仅仅是因为当另一个线程需要访问控件时需要线程锁定——而且由于锁定代价高昂——一个新的线程模型被称为“线程租用”。在该模型中,相关的控件将仅使用一个线程聚合为“上下文”,从而减少所需的锁定量。 很酷,嗯?

    不幸的是,这种尝试太大胆了,不可能成功(而且由于仍然需要锁定,所以更复杂一些),所以在WPF中再次使用了好的旧Windows窗体线程模型——使用单个UI线程和创建线程来声明控件的所有权——以使我们的生活……更简单?

        6
  •  1
  •   supercat    14 年前

    Windows支持许多操作,尤其是在组合使用时,这些操作本身就不是线程安全的。例如,当一个线程试图将一些文本插入以第50个字符开头的文本字段,而另一个线程试图从该字段中删除前40个字符时,会发生什么情况?Windows可以使用锁来确保在第一个操作完成之前无法开始第二个操作,但是使用锁会增加每个操作的开销,并且如果一个实体上的操作需要操作另一个实体,也会增加死锁的可能性。要求涉及特定窗口的操作必须发生在特定线程上是比防止同时执行不安全的操作组合所必需的更严格的要求,但相对容易分析。使用多线程的控件并通过其他方法避免冲突通常会更困难。