Как вызвать функцию асинхронно в Delphi (Без компонентов)

ScottGu имеет набор приемов в http://weblogs.asp.net/scottgu/archive/2006/04/03/441787.aspx

9
задан Sebastian 2 December 2009 в 04:06
поделиться

2 ответа

Вы также можете захотеть выполнить свою процедуру в потоке. Затем используйте событие OnTerminate, чтобы получить результат. Да, в наши дни .NET и C # мы в некотором роде избалованы простой и удобной формой асинхронного выполнения методов, но именно так это работает в Delphi.

5
ответ дан 4 December 2019 в 09:36
поделиться

Если вы спрашиваете, есть ли в VCL что-то вроде BeginInvoke в .NET из коробки, то ответ отрицательный. Однако вы можете получить нечто очень похожее в виде небольшого модуля, который вы подключаете к своей программе, библиотеки AsyncCalls Андреаса Хаусладена. Это не компонент, поэтому я полагаю, что он подходит. Он также поддерживает Delphi, начиная с версии 5. Очень рекомендуется.

Изменить:

Я добавлю пример, так как вы не запустили его. Если вы получаете блокировку в вызывающем коде, ваша проблема заключается в том, что не сохраняется ссылка на указатель интерфейса IAsyncCall , который функция вернула. Следовательно, объект, реализующий интерфейс, будет немедленно уничтожен, когда временная ссылка выйдет за пределы области видимости. Деструктор будет вызван в контексте потока VCL, и он вызовет WaitForSingleObject () или аналогичную функцию для ожидания завершения рабочего потока. Результатом этого является то, что ваш поток VCL блокируется.

Вы получите правильное поведение, если сохраните ссылку на указатель интерфейса:

type
  TForm1 = class(TForm)
    Button1: TButton;
    Timer1: TTimer;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    fAsyncCall: IAsyncCall;
    procedure WaitForIt(ADelay: integer);
  end;

Отключите таймер и дайте ему очень короткий интервал , скажем, 50 мс. Щелчок по кнопке запускает асинхронную операцию:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := FALSE;
  fAsyncCall := AsyncCall(WaitForIt, 1000);
end;

procedure TForm1.WaitForIt(ADelay: integer);
begin
  Sleep(ADelay);

  EnterMainThread;
  try
    Randomize;
    Color := RGB(Random(256), Random(256), Random(256));
    Timer1.Enabled := TRUE;
  finally
    LeaveMainThread;
  end;
end;

Пока операция активна, никакие другие запускать нельзя. По завершении он позволяет таймеру уведомить форму и сбросить ссылку на интерфейс:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := FALSE;
  Assert((fAsyncCall <> nil) and fAsyncCall.Finished);
  fAsyncCall := nil;
  Button1.Enabled := TRUE;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := (fAsyncCall = nil) or fAsyncCall.Finished;
end;

Обратите внимание, как можно даже получить доступ к форме непосредственно из вызываемого метода, используя EnterMainThread () и LeaveMainThread () .

Приведенный выше код не является абсолютным минимумом,

17
ответ дан 4 December 2019 в 09:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: