【问题标题】:Reason for .NET UI element thread-restriction.NET UI 元素线程限制的原因
【发布时间】:2011-02-26 14:28:37
【问题描述】:

我们知道,除了实例化元素的线程之外,不可能从任何线程执行操作任何 UI 元素属性的代码......我的问题是:为什么?

我记得当我们使用 COM 用户界面元素时(在 COM/Visual Basic 6.0 时代),所有 UI 元素都是使用 COM 类和 co-class 创建的,它们使用称为 Thread- 的内存模型存储其资源 -本地存储 (TLS),但我记得,这是必需的,因为与 COM 组件的构造方式相关,并且不应该与 .NET UI 元素相关。这种限制仍然存在的根本原因是什么?

是因为底层操作系统仍然对所有 UI 元素使用基于 COM 的 Win32 API 类,即使是在托管 .NET 应用程序中操作的那些?

【问题讨论】:

  • 我喜欢你的想法,考虑到 .net 应该让 RAD 更快,我们为什么要不得不担心所有的线程tomgiggery。我的意思是它不应该只是工作,.Net 框架为我们解决了所有这些问题。更深入地说,为什么 Windows/操作系统不照顾它。
  • 我的另一个总猜测,但我认为其意图是当操作系统完全迁移到使用托管代码 api 并剥离旧的 Win32 API 时,这个限制就会消失。 . 但如果有更基本的事情发生,则不会......

标签: .net user-interface multithreading


【解决方案1】:

AFAIK,它甚至比 COM 更基本。它归结为良好的 ol' Windows API。我相信 Windows 中的窗口应该由一个线程拥有,期间。每个线程都有自己的消息泵,将消息分派到它拥有的窗口。它是 Windows 的一个非常基本的构造——现在可能有点过时,但很基本。

我的感觉是,当您需要将 WPF 集成到 Windows 窗体应用程序中,或者如果您需要使用您在某个地方获得的 HWND 与应用程序中的其他地方的 Windows 对象进行猴子操作时,这种线程关联有助于互操作性。 . 这可能也是允许旧版本的 Windows (XP) 托管 WPF 应用程序而无需对操作系统本身进行任何重大架构更改的原因。

【讨论】:

  • 如果您是正确的,那么当操作系统 Api 已完全迁移以使用托管代码时,这可能会被避免/修改......但是,如果有一个更根本的原因,那么这可能是不可能的/。
  • 据我了解,还有其他操作系统允许这样做,我相信 BeOS 就是其中之一。他们真的试图从那个操作系统中脱离出来,以期待未来对并行性的需求。我认为每个窗口都有几个线程(一个渲染线程和一个 UI 线程,每个 window,而不是每个应用程序).​​...
【解决方案2】:

听起来您指的是 WPF,而不是通用的 Windows API 编程。我不是 WPF 内部的专家,但这里有一些关于为什么将 UI 操作保留在一个 UI 线程中是一个好主意的内容:

  1. 避免死锁。当您有多个线程在运行时,所有共享资源都必须受到某种锁的保护。当有多个锁时,陷入死锁的风险很高 - 线程 A 拥有锁 1 但正在等待锁 2,线程 B 拥有锁 2 但正在等待锁 1。这可以通过严格的顺序来避免锁定获取,但人性不足。
  2. 减少对昂贵锁的需求。如果您可以要求所有 UI 操作在 UI 线程上执行,则可以消除保护内部数据所需的大量锁。
  3. 降低创建由没有消息循环的线程拥有的窗口句柄的风险。

最后一项与 Win API 相关。创建窗口句柄时,它会绑定到发出 CreateWindow 调用的线程。发送到该窗口句柄的消息将被放置在与该线程关联的消息队列中。如果该线程不处理窗口消息,则窗口将无响应 - UI 冻结。如果另一个线程尝试向该窗口发送消息,则该线程也将被冻结,等待同步调用完成。这雪球很快就变得丑陋了。这就是为什么确保只在准备处理窗口消息的线程上创建窗口句柄很重要的原因。

为什么窗口句柄的消息队列绑定到特定线程?我不知道,但我相信答案不是微不足道的。

【讨论】:

  • 全部正确。 WPF 的美妙之处在于您拥有自己的渲染线程,因此您的最后一个场景不会发生。您可以在 WPF 中尽情享受完美的绘画、完全无响应的应用程序! ;-)
  • @dthpr[e,实际上,不。我不是 WPF 专家。我指的是标准的 .Net Winforms UI 元素。并且死锁发生在 multi=Threading 正确,而不是单线程在错误的线程上......这个限制比要求单线程更严格,它限制代码在其他任何线程上执行(即使是单线程模式)而不是创建 UI 元素的线程。
【解决方案3】:

来自http://msdn.microsoft.com/en-us/library/ms741870.aspx

从历史上看,Windows 允许 UI 元素只能由 创建它们的线程。这意味着 一个后台线程负责 一些长时间运行的任务无法更新 完成后的文本框。视窗 这样做是为了确保完整性 用户界面组件。一个列表框可能看起来 奇怪,如果它的内容被更新了 在后台线程 绘画。

【讨论】:

  • 好吧,我现在可以这样做了,我只需要在 UI Control 元素上调用 BeginInvoke() 即可切换到正确的线程... 需要单线程的单个框架 UI 函数可以以这种方式编码,无论它们是否被允许在一个线程或另一个线程上执行......
  • 您可能会发现 BackgroundWorker 很有用:albahari.com/threading/part3.aspx#_BackgroundWorker.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 2018-12-08
  • 1970-01-01
  • 2011-06-18
  • 2015-02-27
相关资源
最近更新 更多