怎么办asynchronuous编程德尔福? [英] How to do asynchronuous programming in Delphi?

查看:168
本文介绍了怎么办asynchronuous编程德尔福?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,其中大部分的操作需要一定的时间,我想保持GUI响应在任何时候。由用户触发任何行动的基本模式如下:


  1. prepare的动作(在主线程)

  2. (同时保持GUI响应在后台线程)执行动作

  3. 显示结果(在主线程)

我试过几件事情要做到这一点,但所有这些都造成长期来看(貌似随机访问冲突在某些情况下)的问题。


  1. prepare的动作,然后调用一个后台线程,并在后台线程结束时,使用同步来调用 OnFinish 事件的主线。

  2. prepare的动作,然后调用一个后台线程,并在后台线程结束时,使用 PostMessage的通知GUI线程,结果是准备好了。

  3. prepare的动作,然后调用一个后台线程,则忙等待(在调用 Application.ProcessMessages ),直到后台线程完成后,再入手显示结果。

我不能想出另一种选择,并没有这非常适合我。什么是preferred方式做到这一点?


解决方案

1)是一部开拓创新的德尔福的方式,强制后台线程等待,直到同步方法已经执行,系统暴露于更多的死锁电位比我很高兴与。 TThread.Synchronize已经重新写入至少两次。我用了一次,在D3和有问题。我看着它如何工作的。我再也没有使用过。

2)我我最常使用的设计。我使用的应用程序千载难逢的线程(或线程池),创建线程间通讯科对象,并将它们排队使用基于TObjectQueue后代一个生产者 - 消费者队列后台线程。后台线程/秒的对象和数据/方法,结果存储在对象,完成后,PostMessage的()对象,(转换成的lParam)在MESSAGE-操作回主线程结果显示GUI处理器,(施放lParam的回来了)。在主界面线程的后台线程则永远不会有相同的对象进行操作,并从来没有直接访问对方的任何领域。

我用的是GUI线程的一个隐藏的窗口(与RegisterWindowClass和CreateWindow的创建),对于后台线程PostMessage的到,通讯科在对象和lParam目标TwinControl,(通常是TForm的类),如wParam参数。为隐藏窗口的琐碎的WndProc只是使用TwinControl.Perform()来传递对Lparam型窗体的消息处理程序。这比直接Po​​stMessaging对象到TForm.handle更安全 - 把手如果重新创建窗口可不幸的是,改变。隐藏窗口从未称RecreateWindow()等其手柄不会改变。

中的GUI',线程间通讯科类/对象和PostMessage的()就是一个不错的生产者 - 消费者队列从GUI了' - 我已经做了几十年。

重新使用与通讯对象是相当容易太 - 只需要在启动时一个循环的负载,(preferably在初始化部分,这样与通讯对象活得比所有形式),并把它们压到PC队列 - 这就是你的游泳池。这是更容易,如果与通讯类有游泳池实例的私有字段 - 那么releaseBackToPool'方法不需要参数,如果有多个池,确保对象总是释放回自己的游泳池。

3)真的不能大卫Hefferman的评论改善。只是不去做。

I have an application, where most of the actions take some time and I want to keep the GUI responsive at all times. The basic pattern of any action triggered by the user is as follows:

  1. prepare the action (in the main thread)
  2. execute the action (in a background thread while keeping the gui responsive)
  3. display the results (in the main thread)

I tried several things to accomplish this but all of them are causing problems in the long run (seemingly random access violations in certain situations).

  1. Prepare the action, then invoke a background thread and at the end of the background thread, use Synchronize to call an OnFinish event in the main thread.
  2. Prepare the action, then invoke a background thread and at the end of the background thread, use PostMessage to inform the GUI thread that the results are ready.
  3. Prepare the action, then invoke a background thread, then busy-wait (while calling Application.ProcessMessages) until the background thread is finished, then proceed with displaying the results.

I cannot come up with another alternative and none of this worked perfectly for me. What is the preferred way to do this?

解决方案

1) Is the 'Orignal Delphi' way, forces the background thread to wait until the synchronized method has been executed and exposes the system to more deadlock-potential than I am happy with. TThread.Synchronize has been re-written at least twice. I used it once, on D3, and had problems. I looked at how it worked. I never used it again.

2) I the design I use most often. I use app-lifetime threads, (or thread pools), create inter-thread comms objects and queue them to background threads using a producer-consumer queue based on a TObjectQueue descendant. The background thread/s operate on the data/methods of the object, store results in the object and, when complete, PostMessage() the object, (cast to lParam) back to the main thread for GUI display of results in a message-handler, (cast the lParam back again). The background threads in the main GUI thread then never have to operate on the same object and never have to directly access any fields of each other.

I use a hidden window of the GUI thread, (created with RegisterWindowClass and CreateWindow), for the background threads to PostMessage to, comms object in LParam and 'target' TwinControl, (usually a TForm class), as WParam. The trivial wndproc for the hidden window just uses TwinControl.Perform() to pass on the LParam to a message-handler of the form. This is safer than PostMessaging the object directly to a TForm.handle - the handle can, unfortunately, change if the window is recreated. The hidden window never calls RecreateWindow() and so its handle never changes.

Producer-consumer queues 'out from GUI', inter-thread comms classes/objects and PostMessage() 'in to GUI' WILL work well - I've been doing it for decades.

Re-using the comms objects is fairly easy too - just create a load in a loop at startup, (preferably in an initialization section so that the comms objects outlive all forms), and push them onto a P-C queue - that's your pool. It's easier if the comms class has a private field for the pool instance - the 'releaseBackToPool' method then needs no parameters and, if there is more than one pool, ensures that the objects are always released back to their own pool.

3) Can't really improve on David Hefferman's comment. Just don't do it.

这篇关于怎么办asynchronuous编程德尔福?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆