Multithreading 如何使主(调用)线程等待子线程完成执行?
使用:Delphi10、Win32 VCL窗体应用程序 我正在开发一个更新程序应用程序,用于检查一个或多个已安装软件应用程序的更新,当发现更新时,将按顺序下载更新。下载每个更新后,它将在继续下载下一个更新之前安装更新。下载位作为thread类(TThread的后代)实现,其构造函数如下:Multithreading 如何使主(调用)线程等待子线程完成执行?,multithreading,delphi,delphi-10-seattle,Multithreading,Delphi,Delphi 10 Seattle,使用:Delphi10、Win32 VCL窗体应用程序 我正在开发一个更新程序应用程序,用于检查一个或多个已安装软件应用程序的更新,当发现更新时,将按顺序下载更新。下载每个更新后,它将在继续下载下一个更新之前安装更新。下载位作为thread类(TThread的后代)实现,其构造函数如下: constructor TWebFileDownloaderThread.Create(CreateSuspended: Boolean; const AWebFileURL, ALocalFilePath:
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;
主线程创建并启动downloader线程,如下所示:
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
- 其他形式的线程间通信
OnTerminate
看起来是个不错的选择
您也可以考虑使用更高级的并行库。例如,RTL的并行库或OTL。这样可以避免陷入线程的细节中,让并行库处理这些问题
如果要这样做,您可以使用生产者/消费者体系结构设计应用程序:使用高级并行库实现这种设计非常简单。如果我理解正确,您有一个URL列表要下载和安装(通过之前执行更新检查获得)。您希望从这些URL下载更新并逐个安装:下载更新1、安装更新1、下载更新2、安装更新2,等等 以下是一种可能的设计: 在
WebFileDownloaderThread\u TerminatedMethod
中,开始安装刚下载的更新(要保持主线程响应,请在单独的线程中执行此操作)
在安装程序线程的OnTerminate
处理程序中,通过再次调用DownloadUpdateFromWeb
删除刚刚完成的URL(或将其标记为已处理),并开始下载下一个URL,除非列表已为空(或不再包含未处理的项目)
(顺便说一句,方法
DownloadUpdateFromWeb
最好命名为BeginDownloadUpdateFromWeb
,以指示其异步性质。)他使用的是OnTerminate
,因此他在线程完成时已经收到了通知。生产者/消费者体系结构通常会使任务更具包容性,更容易理解。大多数情况下,我也会在一个线程中委托制片人。你应该尽可能避免这种设计。完成本身应该触发下一个作业,而线程不必等待完成触发下一个作业。@DavidSchwartz线程不应该尽可能独立于“外部世界”吗?触发另一个下载线程似乎没有下载线程的责任me@mjn这是完全错误的想法。线程只是运行代码的载体。有责任的是代码,而不是线程。无论下载的代码是什么,下载后都应该继续执行需要执行的操作,而不需要线程等待。创建一个线程来执行工作,然后等待该线程完成是没有意义的——额外的线程没有任何用处。@DavidSchwartz imho这是一个任务,其中“线程队列”是一个解决方案,主线程控制并行执行的线程数(可能取决于CPU负载或核心计数)。混合使用“全局”队列管理和“工作”代码(在线程执行方法中)将是糟糕的imho风格。我不会提前创建所有线程,因此没有线程保持空闲。读我的问题。下载/安装线程完成后,我需要创建一个新线程,依此类推,直到所有URL中的所有安装程序都已下载/安装。因此,这意味着带有下载URL的TStringList将从主UI线程传递到安装线程。好啊对我来说已经足够好了。我的意思是安装程序线程只需要知道要安装的单个更新(刚刚完成下载)。这类似于downloader线程只需要知道要从中下载的单个URL。