我知道我必须调用Synchronize来从未创建控件或未向窗口发送消息的线程中更新vcl。
我经常听到“线程不安全”这个词,但是我找不到关于正在发生的事情的实际解释。
我知道应用程序可能因访问冲突而崩溃,但是我又不知道为什么?
请阐明这个话题。
最佳答案
关于Windows中的GDI线程安全性see this reference article。
它明确指出可以从多个线程安全地访问句柄,但是不应同时进行。您需要保护对GDI句柄的访问,例如使用关键部分。
请记住,与大多数Windows句柄一样,GDI句柄是映射到integer
的内部结构的指针(在较新的Windows下,为64位兼容性,为NativeUInt
)。像在多线程计算中一样,同时访问同一内容可能是问题的根源,很难识别和解决。
从一开始,VCL本身的UI部分就从来就不是线程安全的,因为它依赖于非线程安全的Windows API。例如,如果您在一个线程中释放一个GDI对象,而在另一个线程中仍然需要该对象,那么您将面临潜在的GPF。
Embarcadero(此时)本可以使VCL线程安全,可以通过关键部分序列化所有UI访问,但是它可能增加了复杂性并降低了整体性能。请注意,即使Microsoft .Net平台(在WinForms和WPF中)也都需要专用的线程来进行UI访问,即AFAIK。
因此,要从多个线程刷新UI,您可以使用以下几种模式:
Synchronize
调用; WM_USER
),以通知UI线程需要刷新。 从我的角度来看,对于大多数UI,我更喜欢选项2,对于远程客户端-服务器访问,我更喜欢附加的选项3(可以与选项2混合使用)。因此,您不必从服务器端触发对UI的某些更新事件。在HTTP/AJAX RESTful世界中,这确实是有道理的。选项1有点慢,恕我直言。在所有情况下,选项2和3都需要一个清晰的n-Tier layered architecture,其中逻辑和UI不会混合在一起:但是对于任何认真的开发,无论如何这都是一个很好的模式。