如何在Delphi中进行异步编程?

jpf*_*ius 8 delphi multithreading asynchronous delphi-xe

我有一个应用程序,其中大多数操作需要一些时间,我希望始终保持GUI响应.用户触发的任何操作的基本模式如下:

  1. 准备动作(在主线程中)
  2. 执行动作(在后台线程中保持gui响应)
  3. 显示结果(在主线程中)

我尝试了几个方法来实现这一目标,但从长远来看,所有这些都会导致问题(在某些情况下看似随机访问违规).

  1. 准备操作,然后调用后台线程,并在后台线程的末尾,用于Synchronize调用OnFinish主线程中的事件.
  2. 准备操作,然后调用后台线程,并在后台线程的末尾,用于PostMessage通知GUI线程结果已准备就绪.
  3. 准备操作,然后调用后台线程,然后忙等待(在调用时Application.ProcessMessages)直到后台线程完成,然后继续显示结果.

我无法想出另一种选择,但这对我来说都不是很完美.这样做的首选方法是什么?

klu*_*udg 5

您可以使用OTL实现模式询问,如OTL作者在此处所示


Mar*_*mes 5

1)是'Orignal Delphi'方式,强制后台线程等待同步方法执行,并使系统暴露于比我满意的更多死锁潜力.TThread.Synchronize至少重写了两次.我曾经在D3上使用过一次,并且遇到了问题.我看看它是如何工作的.我再也没用过它.

2)我经常使用的设计.我使用app-lifetime线程(或线程池),创建线程间通信对象,并使用基于TObjectQueue后代的生产者 - 消费者队列将它们排队到后台线程.后台线程对对象的数据/方法进行操作,将结果存储在对象中,并在完成时将PostMessage()对象(强制转换为lParam)返回到主线程,以便在消息中显示结果的GUI-处理程序,(再次抛出lParam).然后,主GUI线程中的后台线程不必对同一对象进行操作,也不必直接访问彼此的任何字段.

我使用GUI线程的隐藏窗口(使用RegisterWindowClass和CreateWindow创建),用于PostMessage的后台线程,LParam中的comms对象和'target'TwinControl(通常是TForm类),作为WParam.隐藏窗口的普通wndproc只使用TwinControl.Perform()将LParam传递给表单的消息处理程序.这比将对象直接PostMessaging到TForm.handle更安全 - 遗憾的是,如果重新创建窗口,句柄会发生变化.隐藏窗口从不调用RecreateWindow(),因此它的句柄永远不会改变.

生产者 - 消费者队列'从GUI'排队,线程间通信类/对象和PostMessage()'进入GUI'将很好地工作 - 我已经做了几十年.

重新使用comms对象也很简单 - 只需在启动时在循环中创建一个加载(最好是在初始化部分,以便使所有表单的通信对象都活得更长),并将它们推送到PC队列 - 这就是你的池.如果comms类具有池实例的私有字段,则更容易 - "releaseBackToPool"方法则不需要参数,如果有多个池,则确保始终将对象释放回自己的池.

3)无法真正改善David Hefferman的评论.只是不要这样做.