gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 14:47:08 44 4
gpt4 key购买 nike

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

  1. 准备操作(在主线程中)
  2. 执行操作(在后台线程中,同时保持 GUI 响应)
  3. 显示结果(在主线程中)

我尝试了几种方法来完成此任务,但从长远来看,所有这些方法都会导致问题(在某些情况下似乎会出现随机访问冲突)。

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

我无法想出其他替代方案,而且这些方案都不适合我。执行此操作的首选方法是什么?

最佳答案

1) 是“原始 Delphi”方式,强制后台线程等待,直到执行完同步方法,并使系统面临比我满意的更多死锁可能性。 TThread.Synchronize 已被重写至少两次。我在 D3 上使用过一次,但遇到了问题。我查看了它是如何工作的。我再也没有使用过它。

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

我使用 GUI 线程的隐藏窗口(使用 RegisterWindowClass 和 CreateWindow 创建)作为后台线程来 PostMessage、LParam 中的通信对象和“目标”TwinControl(通常是 TForm 类)作为 WParam。隐藏窗口的简单 wndproc 仅使用 TwinControl.Perform() 将 LParam 传递给表单的消息处理程序。这比将对象直接 PostMessaging 到 TForm.handle 更安全 - 不幸的是,如果重新创建窗口,句柄可能会更改。隐藏窗口永远不会调用 RecreateWindow(),因此它的句柄永远不会改变。

生产者-消费者队列“从 GUI 出来”、线程间通信类/对象和 PostMessage()“进入 GUI”将会很好地工作 - 我已经这样做了几十年。

重用通信对象也相当容易 - 只需在启动时在循环中创建一个负载(最好在初始化部分中,以便通信对象比所有形式都长),然后将它们推送到 P-C 队列 - 这就是你的水池。如果 comms 类有一个池实例的私有(private)字段,那就更容易了 - 那么“releaseBackToPool”方法就不需要任何参数,并且如果有多个池,则可以确保对象始终释放回它们自己的池。

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

关于multithreading - 如何在Delphi中进行异步编程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12424952/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com