这不是我第一次遇到与此类似的问题:如何从匿名线程(或TTask)中获取返回参数值的var参数?
我需要运行一个过程,该过程花费时间并消耗大量CPU,在运行过程中,该过程将在记录中填充处理的LOG信息,稍后将在其他模块中使用该信息。一旦有其他进程要同时运行,我将这个过程放在AnoynymousThread中。不幸的是,完成后,我无法使用LOG的记录数据,因为它为空。
我应该怎么做才能在Thread内部进行处理时填充此记录?
查看我的代码: [UNIT]
unit UntStringThread;
interface
uses
System.Classes,
System.SysUtils,
System.Threading;
TYPE
TRCLog = record
logprocess : Tstringlist;
logrecord : Array of Tstringlist;
end;
Procedure DoBigProcess (var pRecLog : TRClog; piterations : integer);
Procedure MajorProcessing (var pmainLog : TRCLog);
implementation
Procedure DoBigProcess (var pRecLog : TRClog; piterations : integer);
Var
localLog : TRCLog;
lrows,lrecs, ltotalrecs : integer;
strlogrecords : string;
begin
//Define pRecLog.logrecord array size
setlength(precLog.logrecord, piterations);
// Starts the piterations of the main process which will generates a LOG
for lrows := 1 to piterations do
begin
// ... here goes critial processing that generates
// Generate Log for the current iteration
pRecLog.logprocess.Add('Iteration : ' + lrows.Tostring + ' ... log data about current iteration ...');
// ... other processing goes here. Suppose total records is 10
ltotalrecs := 10;
// Generate Log for each record
pRecLog.logrecord[lrows-1] := Tstringlist.Create;
for lrecs := 1 to ltotalrecs do
begin
// some additionl processing here that generates detail log of records being processed
strlogrecords := ' Record : ' + lrecs.tostring + '... log data about current record being processed';
pRecLog.logrecord[lrows-1].Add(strlogrecords);
end;
pRecLog.logrecord[lrows-1].Add(' ');
end;
end;
Procedure MajorProcessing (var pmainLog : TRCLog);
var
llog : TRClog;
litems : integer;
begin
// some initialization processing here
// ...
litems := 10;
// Runs BigProcess in an Anonymous Thread
llog := pmainlog;
TThread.CreateAnonymousThread(procedure
begin
DoBigProcess (lLog, litems);
end).Start;
// Continuing process other stuff here
end;
end.
主程序
program ProjThreadParameter;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Classes,
UntStringThread in 'UntStringThread.pas';
var
idxlog, idxrecord: integer;
logmain : TRClog;
begin
try
logmain.logprocess := Tstringlist.Create;
MajorProcessing (logmain);
{==> This call, without Thread, works fine}
//DoBigProcess(logmain,10);
for idxlog :=0 to logmain.logprocess.Count-1 do
begin
Writeln(logmain.logprocess[idxlog]);
for idxrecord :=0 to logmain.logrecord[idxlog].count-1 do
Writeln(logmain.logrecord[idxlog][idxrecord])
end;
Readln;
// PROBLEM ==> when using Thread logmain record returned empty !!
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
我研究了几年前的一个先前的问题,但是这次我无法使其起作用。 iTask - values parameters to anonymous procedure
感谢您的帮助!
答案 0 :(得分:0)
这个问题类似于How do I pass a context inside a loop into a TTask.IFuture in Delphi?
IFuture是ITask并发过程的并发函数。
如果我们创建一个依赖于循环索引的函数变量,则可以将索引值绑定到要用作Future的函数中。
此版本创建字符串数组。 对于您的TRCLog记录也是如此。
program ProjThreadLogging;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes,
System.Threading;
const
procs = 8;
var
idxlog : integer;
s : string;
futurefunc : TFunc<string>;
logstrs : array [1..procs] of IFuture<string>;
function CreateIdxLogFunc(idxlog:integer):TFunc<string>;
begin
Result := function:string
begin
{Some calculation that takes time}
Sleep(1000*idxlog);
Result:='Proc ' + idxlog.ToString;
end;
end;
begin
for idxlog in [1..procs] do begin
futurefunc := CreateIdxLogFunc(idxlog);
logstrs[idxlog] := TTask.Future<string>( futurefunc );
end;
for idxlog in [1..procs] do begin
writeln(logstrs[idxlog].Value);
end;
Readln;
end.