【问题标题】:Do we have to use Synchronize if we want to make some changes in the VCL main thread?如果我们想在 VCL 主线程中进行一些更改,是否必须使用 Synchronize?
【发布时间】:2014-04-11 13:09:26
【问题描述】:

假设我想在程序处于子线程中时简单地更改标签的标题。我不想使用同步。我真的不想让操作系统切换到另一个线程上下文来完成这项工作。我知道我不能通过在我的子线程中放置一些锁(信号量或其他东西)来做到这一点。谁能告诉我为什么我不能为此使用锁? 在此先感谢:)

【问题讨论】:

  • 如果你想要一个稳定的解决方案,你必须使用SynchronizeQueue
  • @SirRufo 为什么我不能只使用一些锁? vcl 控件不是典型的共享资源吗?我的意思是为什么要以不同的方式处理 VCL 控件?
  • 您也可以使用PostMessage 将自定义消息发布到 VCL 表单的句柄。
  • 作为替代方案,您可以在子线程中使用 Windows API(直接使用窗口句柄),在某些情况下您可以摆脱它。但要小心,VCL 假定它只在主线程中运行,并且 VCL 方法用于操作底层窗口。在某些情况下,底层窗口可能与 VCL 包装类的属性不同步。
  • 不安全,抱歉。 VCL 不是线程安全的。

标签: multithreading delphi synchronize


【解决方案1】:

如果我们想在 VCL 主线程中进行一些更改,是否必须使用Synchronize

是的。

嗯,访问 VCL 对象的代码必须在主线程上执行,Synchronize 是实现这一目标的最常用方法。没有办法绕过这个限制。

【讨论】:

  • 感谢您的回答。我认为我的观点还没有被很好地理解。我知道 VCL 类和许多其他类一样不是线程安全的。但是我们仍然可以在子线程中使用非 VCL 类,并通过应用一些同步规则(放置一些锁等)使它们成为线程安全的。但我的问题是为什么我们不能对 vcl 类做同样的事情。这是由于 Delphi 的一些内部问题或问题造成的吗?
  • 简单地说,VCL 被设计为只在主线程中使用。首先,VCL 反映了对线程具有亲和力的窗口的 Win32 设计。最重要的是,VCL 不对其共享数据结构执行序列化,因为它被设计为完全在主线程中使用。
【解决方案2】:

大卫的回答是 100% 正确的。但我想我会更清楚一点......

想象一下这种情况:您有一个 VCL 组件,其中包含许多要从线程更新的属性。您在主 VCL 线程和附加线程中创建一个锁(例如临界区)和任何调用,您在尝试访问该对象及其属性时都尊重此锁。但是,由于 VCL 不承认存在其他尝试使用它的线程,因此主线程中可能有一些东西试图访问您的线程试图访问的相同属性... 同时时间。我不是在谈论可能访问此属性的您自己的代码,而是在 VCL 本身背后的一些东西。 VCL 自己不可能知道你的锁来确认它。

因此,在主线程中使用任何东西时,即使是最好的锁定机制也不安全。同步是多线程工作方式的重要组成部分,尽管有一些替代方案,例如提供 windows 消息。

场景

假设您创建了一个继承自 TButton 的自定义按钮组件。您在此按钮后面创建了一个线程,并希望在此线程内更新按钮的标题。您创建一个临界区锁来保护您的控制。

假设您有一个操作管理器,并且此按钮被分配给一个操作。动作管理器负责更新按钮的标题。虽然您的线程和所有代码在访问您的按钮控件时都遵守锁,但操作管理器对此一无所知,并尝试继续更新标题。

【讨论】:

  • AFAIK,甚至像 FastMM 这样基于主线程的东西,也可能会干扰。 Synchronize 确实是唯一的纯解决方案,无需借助 Windows 消息或内存映射文件等依赖项。
  • 感谢您的详细回答。但我想我们可以对你的场景做点什么。我们可以覆盖该 vcl 类的属性设置器和获取器,将一些锁定代码放入其中。但我认为它会严重降低性能。我说的对吗?
  • 为了避免使用 Synchronize 真的值得吗?
  • 不,杰瑞,这就是我的意思。这是不值得的。再次感谢
  • Fastmm 是线程安全的。当然。您省略了对窗口线程关联性问题的介绍。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-12
  • 2014-09-11
  • 1970-01-01
相关资源
最近更新 更多