【问题标题】:Why do UI Controls in WPF have Thread Affinity?为什么 WPF 中的 UI 控件具有线程关联性?
【发布时间】:2012-01-04 20:08:47
【问题描述】:

为什么创建控件的线程是可以更新它的线程?为什么 MS 没有让人们能够使用锁定和其他线程同步技术来读取和写入具有多线程的 UI 控件上的属性。

【问题讨论】:

  • MS 在 msdn 上的回答“最后,WPF 的线程模型与现有的具有线程亲和性的单线程执行的 User32 线程模型保持同步。主要原因是互操作性 - 像 OLE 2.0 这样的系统、剪贴板和 Internet Explorer 都需要单线程关联 (STA) 执行。”

标签: c# wpf


【解决方案1】:

每个 MSDN 的简短描述是

WPF 的线程模型与现有的 User32 保持同步 具有线程亲和性的单线程执行的线程模型。这 主要原因是互操作性——像 OLE 2.0 这样的系统, 剪贴板和 Internet Explorer 都需要单线程 亲和力(STA)执行

更长的描述是这样的:

WPF 中的大多数对象都派生自 DispatcherObject,它提供 处理并发和线程的基本结构。 WPF 是 基于调度程序实现的消息传递系统。这有效 很像熟悉的 Win32 消息泵;实际上,WPF 调度程序 使用 User32 消息执行跨线程调用。

在讨论时确实有两个核心概念需要理解 WPF 中的并发性——调度程序和线程亲和性。

在 WPF 的设计阶段,目标是移动到单个 执行线程,但非线程“关联”模型。线 当组件使用执行者的身份时,就会发生亲和性 线程来存储某种类型的状态。最常见的形式是 使用线程本地存储 (TLS) 来存储状态。线程亲和性 要求每个执行的逻辑线程只属于一个 操作系统中的物理线程,可以变成内存 密集的。最后,WPF 的线程模型与 现有的单线程执行的 User32 线程模型 线程亲和性。主要原因是互操作性—— OLE 2.0、剪贴板和 Internet Explorer 等系统都需要 单线程关联 (STA) 执行。

鉴于您有带有 STA 线程的对象,您需要一种方法来 线程之间进行通信,并验证您是否正确 线。这就是调度员的作用。调度员是一个 基本的消息调度系统,具有多个优先队列。 消息示例包括原始输入通知(鼠标移动), 框架功能(布局)或用户命令(执行此方法)。 通过从 DispatcherObject 派生,您可以创建一个 CLR 对象,该对象具有 STA 行为,并将在创建时获得一个指向调度程序的指针 时间。

您可以阅读全文here

我个人更喜欢 WPF 的单线程模型,而不是必须使用锁定和线程同步技术。 Dispatcher 可用于将消息传递到different priority levels 的主 UI 线程,该线程负责处理大多数小型后台进程,如果您需要任何繁重的处理,您仍然可以为此创建自己的后台线程。

【讨论】:

  • 只是为了添加一些解释优先于调度锁定/信号量等。调度程序本质上是一个具有单线程消费者的队列 - 即一个演员。演员有很多与他们相关的可靠文献。此外,将生产/消费代码与并发代码隔离有助于防止开发人员使用共享状态破坏缓存——这种效果通常会使多线程代码明显慢于细粒度并发的单线程代码。
【解决方案2】:

WPF 与几乎所有的 UI 工具包一样,通过发送消息循环来工作。由于消息可能随时出现并影响任何控件,因此您需要全局锁定。为了减少出错的可能性,您可能需要一个可以在锁下调用委托的函数。也许是这样的:

Dispatcher.Invoke(Delegate, Object())

这被编组到 UI 线程而不是获取全局锁这一事实只是一个实现细节。

【讨论】:

  • 所以真正简短的回答是 WPF 只是建立在旧的遗留东西上,为开发人员提供了一个闪亮的友好界面。因此是 STA 模型。
猜你喜欢
  • 1970-01-01
  • 2014-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多