Как вызвать функцию/процедуру асинхронно в Delphi (без компонентов)
Я пытаюсь запустить функцию или процедуру в Delphi асинхронно, но без использования компонента, есть ли способ сделать это с основными функциями программы?
2 ответов
вы также можете выполнить свою процедуру в потоке. Используйте событие OnTerminate для получения результата. Да, в эти дни .NET и C# мы немного испорчены простой и удобной формой выполнения методов асинхронно, но именно так это работает на Delphi.
если вы спрашиваете, есть ли у VCL что-то как BeginInvoke в .NET из коробки, тогда ответ нет. Тем не менее, вы можете получить что-то похожее в виде небольшого блока, который вы ссылаетесь на свою программу,AsyncCalls библиотека по Andreas Hausladen. Это не компонент, поэтому я думаю, что это квалифицируется. Он также поддерживает Delphi с версии 5 и далее. Очень рекомендую.
Edit:
Я добавлю пример, так как вы не запустили его. Если вы получаете блокировку в своем вызывающем коде, ваша проблема заключается в том, что ссылка не сохраняется на 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;
установите таймер для отключения и пусть он имеет очень короткий Interval
, скажем, 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()
.
выше код не является абсолютным минимумом, он предназначен для демонстрации только некоторых идей.