使用var参数的匿名线程过程

时间:2019-11-19 00:06:11

标签: multithreading delphi parameter-passing

这不是我第一次遇到与此类似的问题:如何从匿名线程(或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

感谢您的帮助!

1 个答案:

答案 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.