我知道我必须调用 Synchronize 来从未创建控件或向窗口发送消息的线程更新 vcl。
我经常听到“线程不安全”这个词,但我找不到关于正在发生的事情的实际解释。
我知道应用程序可能会因访问冲突而崩溃,但我又不知道为什么?
请阐明这个主题。
最佳答案
VCL UI 控件中线程不安全的最大原因之一是 TWinControl.Handle
属性 getter。它不仅仅是控件的 HWND
的简单只读访问器。如果 HWND
尚不存在,它还会创建它。如果工作线程在尚不存在 HWND
时读取 Handle
属性,则会在工作线程上下文中创建一个新的 HWND
,这是不好的,因为HWND
与创建线程上下文相关联,这最多会使所属控件几乎无法操作,因为该控件的 Windows 消息将不再通过主消息循环。但更糟糕的是,如果主线程与工作线程同时读取相同的 Handle
属性(例如,如果主线程为任意数量动态地重新创建 Handle
原因),线程上下文创建被分配为新的 Handle
的 HWND
之间存在竞争条件,并且如果两个线程都结束,则存在潜在的句柄泄漏可能性创建新的 HWND
,但只有一个可以保留,另一个会泄漏。
线程不安全的另一个罪魁祸首是 VCL 的 MakeObjectInstance()
函数,VCL 在内部使用该函数将 TWinControl.WndProc()
非静态类方法分配为TWinControl.Handle
窗口的消息过程,以及指定任何 TWndMethod
类型的对象方法作为由AllocateHWnd()
函数(例如 TTimer
使用)。 MakeObjectInstance()
对内存内容进行了大量的内存分配/缓存和调整,这些内存内容不受多线程并发访问的保护。
如果您可以确保提前分配控件的Handle
,并且如果您可以确保主线程永远不会重新创建该在工作线程运行时进行处理
,然后就可以从工作线程安全地向该控件发送消息,而无需使用Synchronize()
。但这是不可取的,工作线程需要考虑的因素太多了。这就是为什么所有 UI 访问最好仅在主线程中完成的原因。这就是 VCL UI 系统的用途。
关于multithreading - 从创建 UI 的同一线程更新 VCL。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10648996/