单独的 TThread 块 GUI 线程中的操作

Posted

技术标签:

【中文标题】单独的 TThread 块 GUI 线程中的操作【英文标题】:Operations in separate TThread block GUI thread 【发布时间】:2011-02-19 18:05:26 【问题描述】:

我使用本教程 http://delphi.about.com/od/kbthread/a/thread-gui.htm 创建了一个类,该类使用 TDownLoadURL 在另一个线程中从 Internet 异步下载文件。我这样做是因为我想在不阻塞 UI 线程的情况下下载文件,这样程序就不会在大型下载期间变得无响应、进度条可以更新等。

我遇到了一个问题,因为即使我已经在另一个线程中完成了下载(从 TThread 继承并在 Execute 方法中完成工作),GUI 线程似乎被阻止并且在下载完成之前不会处理消息。这是我的类的代码:http://codepad.org/nArfOPJK(只有 99 行,一个简单的类)。我正在执行它,在按钮单击的事件处理程序中:

var
    frame: TTProgressFrame;
    dlt: TDownloadThread;
begin
    dlt := TDownloadThread.Create(True);
    dlt.SetFile('C:\ohayo.zip');
    dlt.SetURL('http://download.thinkbroadband.com/512MB.zip');
    dlt.SetFrame(frame);
    dlt.SetApp(Application);
    dlt.Start;

注意:SetApp 方法适用于当我从我的类 TDownloadThreadUpdateDownloadProgress 方法内部手动调用 app.ProcessMessages 时。这将防止 GUI 无响应,但它使进度条的行为变得怪异(aero 进度条的移动发光的东西移动得太快了),所以我删除了它。我想正确地解决这个问题,如果我必须打电话给ProcessMessages,那么多线程真的没有意义。

有人可以帮我解决这个问题吗?谢谢。

【问题讨论】:

代码看起来是正确的(包括你的线程之一)。您是否尝试在调试器下运行它并查看 dlt.Start 的执行速度(即它是立即返回还是...)? @Eugene:不,由于某种原因,Start 不会立即返回,或者根本不会返回,直到下载完成。什么鬼? @Kokonotsu 不知道,但是您可以将 Classes.pas 添加到您的项目中(如果您有源代码),跟踪 Start 方法并查看给出的结果。 @Eugene,不,我没有 Classes 的来源。我能做什么? VCL 源代码应该包含在 Delphi 中。 【参考方案1】:

我现在有你的解决方案!

调用TDownLoadURL.Execute(您在TDownloadThread 中调用dl.Execute)会导致操作被转移回主线程,这就是您的用户界面变得无响应的原因。

相反,您应该调用ExecuteTarget(nil),它不会执行任何此类阴谋并且按您的意愿工作:下载在工作线程上运行。

【讨论】:

@David 查看代码,是什么让主线程在下载线程上等待?就像我说的,Start 在下载完成之前不会返回。这是关于什么的? @David 不,下载线程就是您在我发布的代码中看到的全部内容。这基本上就是整个项目了,除了主表单按钮处理程序的代码非常少,其中大部分也发布在问题中。 @David 我确定它是 TDownLoadURL,因为我将代码更改为使用 CreateThread 而不是 TThread,所以出于某种原因 TDownLoadURL 导致 GUI 线程等待。 @Kokonotsu 是的,我也一直在调试代码。 TDownloadURL 旨在通过在主线程之外运行 Execute 方法来工作。它通过调用SendAppMessage 回到那里。 @Kokonotsu 我想我现在有答案了!!致电UpdateProgress 时,请确保将电话回拨至Synchronize

以上是关于单独的 TThread 块 GUI 线程中的操作的主要内容,如果未能解决你的问题,请参考以下文章

GTK+ 接口应该在单独的线程中运行吗?

如何在 GUI 线程和工作线程之间共享数据?

串行端口块 GUI - 发射信号块 PyQt-App

如何在框架关闭时终止或杀死python GUI应用程序中的子线程

具有非阻塞 tcp 调用的 TThread

RT-Thread 线程调度