Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何使主(调用)线程等待子线程完成执行?_Multithreading_Delphi_Delphi 10 Seattle - Fatal编程技术网

Multithreading 如何使主(调用)线程等待子线程完成执行?

Multithreading 如何使主(调用)线程等待子线程完成执行?,multithreading,delphi,delphi-10-seattle,Multithreading,Delphi,Delphi 10 Seattle,使用:Delphi10、Win32 VCL窗体应用程序 我正在开发一个更新程序应用程序,用于检查一个或多个已安装软件应用程序的更新,当发现更新时,将按顺序下载更新。下载每个更新后,它将在继续下载下一个更新之前安装更新。下载位作为thread类(TThread的后代)实现,其构造函数如下: constructor TWebFileDownloaderThread.Create(CreateSuspended: Boolean; const AWebFileURL, ALocalFilePath:

使用:Delphi10、Win32 VCL窗体应用程序

我正在开发一个更新程序应用程序,用于检查一个或多个已安装软件应用程序的更新,当发现更新时,将按顺序下载更新。下载每个更新后,它将在继续下载下一个更新之前安装更新。下载位作为thread类(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;
主线程创建并启动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。这样可以避免陷入线程的细节中,让并行库处理这些问题

如果要这样做,您可以使用生产者/消费者体系结构设计应用程序:

  • 创建线程安全队列
  • 创建一个或多个下载线程,它们是使用者
  • 主线程producer将下载作业推送到队列中
  • 使用者线程在队列上等待,当队列包含作业时,使用者线程通过下载文件来提取作业并处理它们

  • 使用高级并行库实现这种设计非常简单。

    如果我理解正确,您有一个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。