Требуется выполнение асинхронной функции одна за другой с помощью AsyncCalls и невозможность воспроизведения демонстрации - PullRequest
0 голосов
/ 10 ноября 2018

Моя основная задача - запускать две трудоемкие функции или процедуры, одну за другой, после того как завершится выполнение. Мой текущий подход заключается в том, чтобы поместить второй вызов функции после цикла while (при условии, что я передал ему один объект типа Interface в параметре массива AsyncMultiSync) в приведенном ниже коде, который я получил из AsyncCalls Documentation.md в Github. Кроме того, когда я пытаюсь запустить приведенный ниже точный код, я вижу, что потоки выполняют свою работу, и выполнение достигает первого доступа к заметке о потоке vcl, но второй доступ к заметке останавливает приложение (для каталогов, имеющих довольно много файлов в вызове GetFiles) PS Английский не мой родной язык, и у меня могут возникнуть проблемы с его объяснением, но если вы понизите его для заголовка или MCVE, это будет мой последний вопрос здесь согласно правилам SO.

uses
  ..AsyncCalls;

{ Ex - 2 using global function }
function GetFiles(Directory: string; Filenames: TStrings): Integer;
var
  h: THandle;
  FindData: TWin32FindData;
begin
  h := FindFirstFile(PChar(Directory + '\*.*'), FindData);
  if h <> INVALID_HANDLE_VALUE then
  begin
    repeat
      if (StrComp(FindData.cFileName, '.') <> 0) and (StrComp(FindData.cFileName, '..') <> 0) then
      begin
        Filenames.Add(Directory + '\' + FindData.cFileName);
        if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
          GetFiles(Filenames[Filenames.Count - 1], Filenames);
      end;
    until not FindNextFile(h, FindData);
    Winapi.Windows.FindClose(h);
  end;
  Result := 0;
end;

procedure TForm1.ButtonGetFilesClick(Sender: TObject);
var
  i: integer;
  Dir1Files, Dir2Files: TStrings;
  Dir1, Dir2 IAsyncCall;
begin
  Dir1Files := TStringList.Create;
  Dir2Files := TStringList.Create;
  ButtonGetFiles.Enabled := False;
  try
    Dir1 := TAsyncCalls.Invoke<string, TStrings>(GetFiles, 'C:\portables\autoit-v3', Dir1Files);
    Dir2 := TAsyncCalls.Invoke<string, TStrings>(GetFiles, 'E:\mySyntax-Repository-works', Dir2Files);    


    { Wait until both async functions have finished their work. While waiting make the UI
      reacting on user interaction. }
    while AsyncMultiSync([Dir1, Dir2], True, 10) = WAIT_TIMEOUT do
      Application.ProcessMessages;
{    Form1.Caption := 'after file search';}

    MemoFiles.Lines.Assign(Dir1Files);
    MemoFiles.Lines.AddStrings(Dir2Files); {-->causes freeze}
  finally
    ButtonGetFiles.Enabled := True;
    Dir2Files.Free;
    Dir1Files.Free;
  end;
end;

1 Ответ

0 голосов
/ 11 ноября 2018

Одним из альтернативных решений является JvThread, поскольку он содержит хорошо прокомментированные демонстрации. Несколько объектов JvThread могут быть связаны через события onFinish, чтобы запускаться один за другим. При необходимости может быть создано много функций синхронизации для связи с потоком VCL, где существует риск гонки (между потоком и потоком VCL). И если требуется, каждый JvThread может быть принудительно завершен, то есть «разбит», завершив его, основываясь на некоторой логике, внутри кода выполнения потока или в связанной функции Sync в потоке VCL. Чем он отличается от использования таймеров или многопоточных таймеров, запускающих друг друга, в первую очередь, учитывая, что мы используем довольно много глобальных полей формы? Ответ заключается в том, что для таймеров нет эквивалента onFinish, и для достижения этого потребуется больше усилий и меньше элегантности. Omnithread несколько ограничивает лицензию BSD, нативные потоки побеждают дух RAD Delphi, а библиотека задач недоступна в более легких установках, таких как XE5.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...