Como posso capturar variáveis pelo método anônimo ao usá-lo no OTL?
O que eu quero fazer:
Eu tenho alguns objetos em uma lista de genria. Eu quero capturar cada um desse objeto no método anônimo e executar esse método como uma tarefa OTL separada.
Este é um exemplo simplificado:
program Project51;
{$APPTYPE CONSOLE}
uses
SysUtils, Generics.Collections, OtlTaskControl, OtlTask;
type
TProc = reference to procedure;
type
TMyObject = class(TObject)
public
ID: Integer;
constructor Create(AID: Integer);
end;
constructor TMyObject.Create(AID: Integer);
begin
ID := AID;
end;
var
Objects: TList<TMyObject>;
LObject: TMyObject;
MyProc: TProc;
begin
Objects := TList<TMyObject>.Create;
Objects.Add(TMyObject.Create(1));
Objects.Add(TMyObject.Create(2));
Objects.Add(TMyObject.Create(3));
for LObject in Objects do
begin
//This seems to work
MyProc := procedure
begin
Writeln(Format('[SameThread] Object ID: %d',[LObject.ID]));
end;
MyProc;
//This doesn't work, sometimes it returns 4 lines in console!?
CreateTask(
procedure(const Task: IOmniTask)
begin
Writeln(Format('[Thread %d] Object ID: %d',[Task.UniqueID, LObject.ID]));
end
).Unobserved.Run;
end;
Sleep(500); //Just wait a bit for tasks to finish
Readln;
end.
E esse é o resultado:
Como você pode ver, a captura parece funcionar bem no thread principal. No entanto, não sei se um ponteiro para um objeto foi capturado ou apenas seu campo de ID?
Quando tento capturar o objeto e passar o método anônimo paraCreateTask
funcionam as coisas se tornam estranhas.
Primeiro de tudo, apenas a terceira instânciaTMyObject
parecia ser capturado. Em segundo lugar, tenho quatro mensagens no log do console, apesar de eu ter apenas três objetos na lista genérica. O segundo comportamento é inconsistente, às vezes eu tenho três mensagens no console, às vezes eu tenho quatro.
Explique-me o motivo de dois problemas mencionados acima e proponha uma solução que elimine o problema e permita que eu passe cada instância do objeto para uma tarefa OTL separada. (Eu não quero usar regularTThread
classe.)