1) 是“原始 Delphi”方式,强制后台线程等待同步方法执行完毕,并使系统面临比我满意的更多死锁可能性。TThread.Synchronize 至少被重写了两次。我在 D3 上使用过一次,但遇到了问题。我看了看它是如何工作的。我再也没有用过它。
2)我最常使用的设计。我使用应用程序生命周期线程(或线程池),创建线程间通信对象,并使用基于 TObjectQueue 后代的生产者-消费者队列将它们排队到后台线程。后台线程/s 对对象的数据/方法进行操作,将结果存储在对象中,完成后,PostMessage() 对象,(转换为 lParam)返回到主线程,以便在消息中以 GUI 显示结果-处理程序,(再次将 lParam 投射回去)。主 GUI 线程中的后台线程就不必对同一个对象进行操作,也不必直接访问彼此的任何字段。
我使用 GUI 线程的隐藏窗口(使用 RegisterWindowClass 和 CreateWindow 创建)作为 PostMessage 的后台线程,LParam 中的 comms 对象和“目标”TwinControl(通常是 TForm 类)作为 WParam。隐藏窗口的简单 wndproc 只使用 TwinControl.Perform() 将 LParam 传递给表单的消息处理程序。这比将对象直接发送到 TForm.handle 更安全 - 不幸的是,如果重新创建窗口,句柄可能会发生变化。隐藏窗口从不调用 RecreateWindow(),因此它的句柄永远不会改变。
生产者 - 消费者队列“从 GUI 出来”、线程间通信类/对象和 PostMessage()“进入 GUI”将运行良好 - 我已经这样做了几十年。
重用通讯对象也相当容易——只需在启动时在循环中创建一个负载(最好在初始化部分中,以便通讯对象比所有形式都更有效),然后将它们推送到 PC 队列中——这就是你的池。如果 comms 类有一个用于池实例的私有字段,那就更容易了——“releaseBackToPool”方法不需要参数,如果有多个池,则确保对象总是被释放回它们自己的池。
3)不能真正改善大卫赫弗曼的评论。只是不要这样做。