opc*_*0de 8 delphi multithreading thread-safety
我知道我必须调用Synchronize来从没有创建控件的线程更新vcl或者向窗口发送消息.
我经常听到这个词不是线程安全的,但是我找不到关于发生了什么的实际解释.
我知道应用程序可能会因访问冲突而崩溃,但我不知道为什么?
请介绍一下这个话题.
Rem*_*eau 12
VCL UI控件中线程不安全的最大原因之一是TWinControl.Handle属性getter.它不仅仅是控件的简单只读访问器HWND.HWND如果它还不存在,它也会创建它.如果一个工作线程Handle在不HWND存在时读取该属性,它会HWND在工作线程上下文中创建一个新的,这很糟糕,因为HWNDs与创建线程上下文相关联,这将使得拥有控件最多无法使用,因为Windows消息为控件不再通过主消息循环.但糟糕的是,如果主线程读取相同的Handle在同一时间的工作线程确实财产(例如,如果主线程动态地重新创建Handle为任意数量的原因),所以它们之间的线程上下文创建了一个竞争条件HWND是被分配为新的Handle,以及潜在的句柄泄漏潜力,如果两个线程最终创建新的HWNDs但只有一个可以保留而另一个被泄露.
线程不安全的另一个罪犯是VCL的MakeObjectInstance()函数,VCL在内部使用该函数将TWinControl.WndProc()非静态类方法指定为TWinControl.Handle窗口的消息过程,以及将任何TWndMethod对象方法指定为由其HWND创建的消息过程.AllocateHWnd()功能(TTimer例如使用). MakeObjectInstance()做了相当多的内存分配/缓存和twiddling内存内容,不受多线程的并发访问保护.
如果您可以确保Handle提前分配控件,并且如果您可以确保主线程Handle在工作线程运行时从不重新创建,那么可以安全地从工作线程向该控件发送消息而不使用Synchronize().但这是不可取的,工作者线程必须考虑太多因素.这就是为什么最好只在主线程中完成所有 UI访问.这就是VCL UI系统的使用方式.
关于Windows中的GDI线程安全性,请参阅此参考文章.
它清楚地表明您可以从多个线程安全地访问句柄,但不应该同时进行.您需要保护对GDI句柄的访问,例如使用关键部分.
请记住,与大多数Windows句柄一样,GDI处理是映射到(在较新的Windows下,64位兼容性)的内部结构的指针.像在多线程计算中一样,同时访问相同的内容可能是问题的根源,这些问题很难识别和修复.integerNativeUInt
VCL本身的UI部分从一开始就不是线程安全的,因为它依赖于非线程安全的Windows API.例如,如果您在一个线程中释放GDI对象(在另一个线程中仍然需要),您将面临潜在的GPF.
Embarcadero(此时)可以使VCL线程安全,通过关键部分序列化所有UI访问,但它可能增加了复杂性,并降低了整体性能.请注意,即使是Microsoft .Net平台(在WinForms和WPF中)也需要一个用于UI访问的专用线程AFAIK.
因此,要从多个线程刷新UI,您有几种模式:
Synchronize来自线程的调用; WM_USER从后台线程发送GDI自定义消息(请参阅参考资料)以通知UI线程需要刷新;从我的角度来看,我更喜欢大多数UI的选项2,以及用于远程客户端 - 服务器访问的附加选项3(可以与选项2混合使用).因此,您不必从服务器端向UI触发某些更新事件.在HTTP/AJAX RESTful世界中,这确实很有意义.选项1有点慢,恕我直言.在所有情况下,选项2和3都需要一个清晰的n层分层架构,其中逻辑和UI不会混合:但无论如何,对于任何严肃的开发来说,这都是一个很好的模式.
| 归档时间: |
|
| 查看次数: |
1174 次 |
| 最近记录: |