如何让主(调用)线程等待子线程完成执行?
How to make the main (calling) thread wait for a child thread to complete execution?
使用:Delphi 10 Seattle,Win32 VCL 表单应用程序
我正在开发一个更新程序,用于检查一个或多个已安装软件应用程序的更新,并在找到更新时按顺序下载更新。下载每个更新后,它将在继续下载下一个更新之前安装更新。下载位实现为线程class(TThread 的后代),其构造函数如下:
constructor TWebFileDownloaderThread.Create(CreateSuspended: Boolean; const AWebFileURL, ALocalFilePath: String;
ACallBackProc: TProgressCallback; AProxySetting: TProxySetting);
begin
inherited Create(CreateSuspended);
FWorkResult := False;
FWebFileURL := AWebFileURL;
FProxySetting := AProxySetting;
FLocalFilePath := ALocalFilePath;
FUpdateCallbackProc := ACallBackProc;
end;
主线程创建并启动下载线程如下:
procedure TfmMain.DownloadUpdateFromWeb(const AInstallerFileURL: String);
var
internet_file_download_thread: TWebFileDownloaderThread;
begin
internet_file_download_thread := TWebFileDownloaderThread.Create(True, AInstallerFileURL, FUpdateDownloadDir,
UpdateProgressCallback, FProxySetting);
internet_file_download_thread.OnTerminate := WebFileDownloaderThread_TerminatedMethod;
internet_file_download_thread.FreeOnTerminate := True;
internet_file_download_thread.Start;
end;
我的具体问题是:如何让主(调用)UI 线程等到下载线程完成,然后再创建新的下载线程开始下一次下载?
我认为需要某种形式的排队,但不确定如何实施。非常感谢您的提示和建议。
你不应该阻塞主线程。所以不要等到工作线程完成。而是安排工作线程在完成时向主线程发出信号。例如:
- 正在发送消息,或
- 使用
TThread.Synchronize
,或
- 使用
TThread.Queue
,或
- 处理线程的
OnTerminate
事件,或
- 一些其他形式的 inter-thread 交流。
OnTerminate
对我来说是个不错的选择。
您也可以考虑使用更高级别的并行库。例如 RTL 的并行库或 OTL。这样你就可以避免纠结于线程的细节,让并行库来处理这些事情。
如果您这样做,您可以使用 producer/consumer 架构设计您的应用程序:
- 创建线程安全队列。
- 创建一个或多个下载线程,这些是消费者。
- 主线程,即生产者,将下载作业推送到队列中。
- 消费者线程在队列上等待,当它包含作业时,消费者线程通过下载文件来完成作业并处理它们。
这种设计使用高级并行库实现起来非常简单。
如果我没理解错的话,您有一个 URL 列表可供下载和安装(通过先前执行更新检查获得)。您想从这些 URL 下载更新并一一安装:下载更新 1、安装更新 1、下载更新 2、安装更新 2,等等
这是一个可能的设计:
在您的 WebFileDownloaderThread_TerminatedMethod
中,开始安装刚刚下载的更新(要保持主线程响应,请在单独的线程中执行此操作)。
在安装程序线程的OnTerminate
处理程序中,删除刚刚完成的URL(或将其标记为已处理)并开始下载下一个,再次调用DownloadUpdateFromWeb
,除非列表已经为空(或不再包含未处理的项目)。
(顺便说一句,方法 DownloadUpdateFromWeb
最好命名为类似 BeginDownloadUpdateFromWeb
的名称,以表明其异步性质。)
使用:Delphi 10 Seattle,Win32 VCL 表单应用程序
我正在开发一个更新程序,用于检查一个或多个已安装软件应用程序的更新,并在找到更新时按顺序下载更新。下载每个更新后,它将在继续下载下一个更新之前安装更新。下载位实现为线程class(TThread 的后代),其构造函数如下:
constructor TWebFileDownloaderThread.Create(CreateSuspended: Boolean; const AWebFileURL, ALocalFilePath: String;
ACallBackProc: TProgressCallback; AProxySetting: TProxySetting);
begin
inherited Create(CreateSuspended);
FWorkResult := False;
FWebFileURL := AWebFileURL;
FProxySetting := AProxySetting;
FLocalFilePath := ALocalFilePath;
FUpdateCallbackProc := ACallBackProc;
end;
主线程创建并启动下载线程如下:
procedure TfmMain.DownloadUpdateFromWeb(const AInstallerFileURL: String);
var
internet_file_download_thread: TWebFileDownloaderThread;
begin
internet_file_download_thread := TWebFileDownloaderThread.Create(True, AInstallerFileURL, FUpdateDownloadDir,
UpdateProgressCallback, FProxySetting);
internet_file_download_thread.OnTerminate := WebFileDownloaderThread_TerminatedMethod;
internet_file_download_thread.FreeOnTerminate := True;
internet_file_download_thread.Start;
end;
我的具体问题是:如何让主(调用)UI 线程等到下载线程完成,然后再创建新的下载线程开始下一次下载?
我认为需要某种形式的排队,但不确定如何实施。非常感谢您的提示和建议。
你不应该阻塞主线程。所以不要等到工作线程完成。而是安排工作线程在完成时向主线程发出信号。例如:
- 正在发送消息,或
- 使用
TThread.Synchronize
,或 - 使用
TThread.Queue
,或 - 处理线程的
OnTerminate
事件,或 - 一些其他形式的 inter-thread 交流。
OnTerminate
对我来说是个不错的选择。
您也可以考虑使用更高级别的并行库。例如 RTL 的并行库或 OTL。这样你就可以避免纠结于线程的细节,让并行库来处理这些事情。
如果您这样做,您可以使用 producer/consumer 架构设计您的应用程序:
- 创建线程安全队列。
- 创建一个或多个下载线程,这些是消费者。
- 主线程,即生产者,将下载作业推送到队列中。
- 消费者线程在队列上等待,当它包含作业时,消费者线程通过下载文件来完成作业并处理它们。
这种设计使用高级并行库实现起来非常简单。
如果我没理解错的话,您有一个 URL 列表可供下载和安装(通过先前执行更新检查获得)。您想从这些 URL 下载更新并一一安装:下载更新 1、安装更新 1、下载更新 2、安装更新 2,等等
这是一个可能的设计:
在您的 WebFileDownloaderThread_TerminatedMethod
中,开始安装刚刚下载的更新(要保持主线程响应,请在单独的线程中执行此操作)。
在安装程序线程的OnTerminate
处理程序中,删除刚刚完成的URL(或将其标记为已处理)并开始下载下一个,再次调用DownloadUpdateFromWeb
,除非列表已经为空(或不再包含未处理的项目)。
(顺便说一句,方法 DownloadUpdateFromWeb
最好命名为类似 BeginDownloadUpdateFromWeb
的名称,以表明其异步性质。)