Sign in Join
Wiki copytemporary

Asynchronous Calls/ru

English · Français · Русский · 日本語

Постановка задачи

При обработке какого-либо события вам иногда нужно что-то сделать, но вы не можете сделать это сразу. Например, вам нужно освободить объект, но на него ссылаются или будут ссылаться позже где-то в родителе (или в его родителе и т.д.). Или вам нужно обновить элементы графического интерфейса, к которым обращаются несколько потоков, безопасным способом.

Решение

Вызовите Application.QueueAsyncCall:

pascal
TDataEvent = procedure (Data: PtrInt) of object;
pascal
procedure QueueAsyncCall(AMethod: TDataEvent; Data: PtrInt);

Это «поставит» данный метод с заданным параметром для выполнения в очередь в главном цикле событий, когда все остальные события будут обработаны. В приведенном выше примере ссылка на объект, который вы хотели освободить, исчезла, поскольку тогдашний родительский объект завершил выполнение, и объект, который вы хотели освободить, можно безопасно освободить.

Обратите внимание, что это более обобщенная версия ReleaseComponent, и ReleaseComponent вызывает этот метод.

Примеры

Передача в асинхронную функцию простых данных

Следующая программа демонстрирует использование QueueAsyncCall. Если вы нажмете на кнопку CallButton, в LogListBox добавится 'Click 1', 'Click 2' и 'Async 1'. Обратите внимание, что асинхронный вызов выполняется только после завершения события CallButtonClick.

pascal
unit TestQueueAsyncCall;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons,
  StdCtrls;

type

  { TQueueAsyncCallForm }

  TQueueAsyncCallForm = class(TForm)
    CallButton: TButton;
    LogListBox: TListBox;
    procedure CallButtonClick(Sender: TObject);
  private
    { private declarations }
    FCounter: PtrInt;
    procedure Async(Data: PtrInt);
  public
    { public declarations }
  end; 

var
  QueueAsyncCallForm: TQueueAsyncCallForm;

implementation

{$R *.lfm}

{ TQueueAsyncCallForm }

procedure TQueueAsyncCallForm.CallButtonClick(Sender: TObject);
begin
  LogListBox.Items.Add('Click 1');
  FCounter := FCounter+1;
  Application.QueueAsyncCall(@Async,FCounter);
  LogListBox.Items.Add('Click 2');
end;

procedure TQueueAsyncCallForm.Async(Data: PtrInt);
begin
   LogListBox.Items.Add('Async '+ IntToStr(Data));
end;

end.

Передача в асинхронную функцию записи

Вот некоторый код, извлеченный из модуля MemoChannel MultiLog, который используется для потоковой записи сообщений в журнал для управления Memo. Благодаря QueueAsyncCall() все записи в Memo сериализуются. Здесь нет блокировок и конфликтов, даже если сотни потоков вызывают метод Write().

pascal
...
type
  TLogMsgData = record // запись может содержать гораздо больше, чем простая строка :-)
    Text: string;
  end;
  PLogMsgData = ^TLogMsgData;
...
procedure TMemoChannel.Write(const AMsg: string);
var
  LogMsgToSend: PLogMsgData;
begin
  New(LogMsgToSend);
  LogMsgToSend^.Text:= AMsg;
  Application.QueueAsyncCall(@WriteAsyncQueue, PtrInt(LogMsgToSend)); // помещаем содержимое msg в очередь, которая будет обработана в основном потоке сразу после обработки всех других сообщений
end;
...
procedure TMemoChannel.WriteAsyncQueue(Data: PtrInt);
var // вызывается в основном потоке после обработки всех других сообщений, чтобы обеспечить потокобезопасный доступ к TMemo
  ReceivedLogMsg: TLogMsgData;
begin
  ReceivedLogMsg := PLogMsgData(Data)^;
  try
    if (FMemo <> nil) and (not Application.Terminated) then
    begin
      ...
      FMemo.Append(ReceivedLogMsg.Text) // <<< полностью потокобезопасен
    end;
  finally
    Dispose(PLogMsgData(Data));
  end;
end;

См.также


From the Free Pascal wiki, page "Asynchronous Calls/ru", as it stood on 2019-09-27 after a change by FTurtle, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 2, last changed by WikiArchive .

Edited on wiki.freepascal.org by 2 people, 2019

From the official wiki's backup of 26 May 2024: who edited this page there, and when. Edits made there after that date were not recorded, and the earlier versions are not shown here; the main page says why.

WhenWhoWhat changed
ZoltanleoCreated page
ZoltanleoProblem statement
ZoltanleoSolution
ZoltanleoРешение
ZoltanleoExamples
ZoltanleoSee also
FTurtleDeleted English categories

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.