2016-01-07 2 views
3

Использование: Delphi 10 Seattle, Win32 VCL forms applicationКак заставить основной (вызывающий) поток ждать завершения дочернего потока?

Я разрабатываю приложение для обновления, которое проверяет наличие обновлений для одного или нескольких установленных программных приложений, а также при обнаружении обновлений загружает обновления в последовательности. После того как каждое обновление будет загружено, оно установит обновление, прежде чем приступать к загрузке следующего обновления. Загрузки бит реализован в виде потока класса (потомка 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; 

Мой конкретный вопрос : Как сделать основной (вызывающий) поток пользовательского интерфейса до тех пор, пока поток загрузчика не завершится, перед созданием нового потока загрузчика, чтобы начать следующую загрузку?

Я считаю, что требуется некоторая форма очереди, но не знаете, как ее реализовать. Ваши советы и советы очень ценятся.

+0

Вы должны попробовать так сложно, как можно избежать этой конструкции. Завершение * непосредственно * должно запускать следующее задание без потока, который должен дождаться завершения, чтобы запустить следующее задание. –

+0

@DavidSchwartz не должен быть нитями как независимыми от «внешнего мира», насколько это возможно? Triggering другой поток для загрузки, кажется, не несет ответственности за поток загрузки для меня – mjn

+0

@mjn Это совершенно неправильный способ подумать об этом. Нити - это только те транспортные средства, которые управляют кодом. Это код, который несет ответственность, а не потоки. Независимо от того, какой код загружает, вы должны продолжать делать то, что нужно сделать после загрузки, не требуя нить, чтобы сидеть в ожидании. Нет смысла создавать поток для выполнения работы, а затем ждать завершения этого потока - этот дополнительный поток не имеет никакой цели. –

ответ

3

Если я правильно понял, у вас есть список URL-адресов для загрузки и установки (полученный путем предварительной проверки обновлений). Вы хотите загружать обновления с этих URL-адресов и устанавливать их по одному: загрузить обновление 1, установить обновление 1, загрузить обновление 2, установить обновление 2 и т. Д.

Вот возможный дизайн:

В вашем WebFileDownloaderThread_TerminatedMethod, начать установку только загруженное обновление (чтобы основной поток отзывчивый, сделать это в отдельном потоке).

В OnTerminate обработчик монтажника нити, удалите только что запущенном URL (или пометить его как обработанное) и снова начать загрузку следующего, позвонив по телефону DownloadUpdateFromWeb, если список уже не является пустым (или содержит не более необработанных элементов).

(кстати, метод DownloadUpdateFromWeb бы лучше назвать что-то вроде BeginDownloadUpdateFromWeb, чтобы указать его асинхронный характер.)

+0

Итак, это означает, что TStringList с URL-адресами загрузки передается потоку установщика из основного потока пользовательского интерфейса. ОК. Достаточно хорошо для меня. –

+0

То, что я имел в виду, было то, что поток установщика должен знать только одно обновление для установки (которое только что закончило загрузку). Это похоже на то, как поток загрузчика должен знать только один URL-адрес для загрузки. –

3

Вы не должны блокировать основной поток. Поэтому не ждите, пока рабочий поток не завершится. Вместо этого организуйте, чтобы рабочий поток сигнализировал основному потоку, когда он закончил. Например по:

  • Отправка сообщения или
  • Использование TThread.Synchronize или
  • Использование TThread.Queue или
  • Работа с OnTerminate событие нити или
  • Некоторые другие формы меж- нить связи.

OnTerminate выглядит довольно хорошим вариантом для меня.

Возможно, вы также захотите использовать параллельную библиотеку более высокого уровня. Например, параллельная библиотека RTL или OTL. Таким образом, вы можете избежать путаницы в деталях потоков и позволить параллельной библиотеке заниматься такими вопросами.

Были ли вы сделать это, вы могли бы разработать приложение с производителем/потребительской архитектуры:

  1. Создание очереди THREADSAFE.
  2. Создайте один или несколько загружаемых потоков, это потребители.
  3. Основной поток, производитель, толкает задания загрузки в очередь.
  4. Потребительские потоки ожидают очереди и когда они содержат задания, потребительские потоки снимают задания и обрабатывают их, загружая файл.

Этот вид дизайна очень прост в использовании с использованием параллельной библиотеки высокого уровня.

+3

Он использует 'OnTerminate', поэтому он уже получает уведомление, когда поток завершен. –

+0

Архитектура производителя/потребителя часто делает задачу более содержательной и более легкой для понимания. Большую часть времени я делегирую часть производителя в поток. –

Смежные вопросы