Reputation: 1567
Using: Delphi 10 Seattle, Win32 VCL forms application
I'm developing an updater application that checks for updates to one or more installed software applications, and when updates are found will download the updates in sequence. After each update is downloaded, it will install the update before proceeding to download the next update. The downloading bit is implemented as a thread class (descendant of TThread) and its constructor is as follows:
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;
The main thread creates and starts the downloader thread as follows:
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;
My specific question is: How to make the main (calling) UI thread wait until a downloader thread completes, before creating a new downloader thread to start the next download?
I believe that there is some form of queuing required, but not sure how to implement it. Your tips and advice are much appreciated.
Upvotes: 4
Views: 590
Reputation: 37211
If I understood it correctly, you have a list of URLs to download and install (obtained by previously performing a check for updates). You want to download updates from these URLs and install them one by one: download update 1, install update 1, download update 2, install update 2, etc.
Here's a possible design:
In your WebFileDownloaderThread_TerminatedMethod
, start installing the just downloaded update (to keep the main thread responsive, do this in a separate thread).
In the OnTerminate
handler of the installer thread, remove the just completed URL (or mark it as processed) and start downloading the next one, by calling DownloadUpdateFromWeb
again, unless the list is already empty (or contains no more unprocessed items).
(BTW, the method DownloadUpdateFromWeb
would better be named something like BeginDownloadUpdateFromWeb
, to indicate its asynchronous nature.)
Upvotes: 3
Reputation: 612804
You should not block the main thread. So do not wait until the worker thread completes. Instead arrange for the worker thread to signal to the main thread when it has finished. For instance by:
TThread.Synchronize
, orTThread.Queue
, orOnTerminate
event of the thread, orThe OnTerminate
looks like a pretty good option to me.
You might also consider using a higher level parallel library. For instance the RTL's parallel library, or OTL. That way you can avoid getting tangled up in the details of threads, and let the parallel library deal with such matters.
Were you to do this you could design your application with a producer/consumer architecture:
This sort of design is very simple to implement using a high level parallel library.
Upvotes: 3