如何在TParallel中使用对象线程安全的数据和方法。& For循环?

时间:2017-04-15 17:05:36

标签: multithreading delphi parallel-processing

我有一个TParallel。& For循环。在这个循环中,我创建并使用TMyClass对象来进行计算。结果存储在ResultList中。

type
  TMyCommonClass=class(TList<Real>)
  private
    function DoCalculation(const AValue: Integer): Real;
  end;

type
  TMyClass=class(TList<Real>)
  private
    MyCommonClass: TMyCommonClass;
    function DoCalculation(const AValue: Integer): Real;
  end;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    MyCommonClass: TMyCommonClass;
  end;


function TMyCommonClass.DoCalculation(const AValue: Integer): Real;
var
  r: Real; //some local vars
begin
  r:=Items[AValue]*100; //some example calculations using local vars
  Result:=r;
end;

function TMyClass.DoCalculation(const AValue: Integer): Real;
begin
  Result:=MyCommonClass.DoCalculation(AValue);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  MyCommonClass:=TMyCommonClass.Create;
  for i := 0 to 1000000 do //add some example data to the list
  begin
    MyCommonClass.Add(i*0.01);
  end;
end;    

procedure TForm1.Button1Click(Sender: TObject);
var
  ALock: TCriticalSection;
  LoopResult: Tparallel.TLoopResult;
  ResultList: TList<Real>;
  i: Integer;
begin
  ResultList:=TList<Real>.Create;
  try
    ALock:=TCriticalSection.Create;
    try
      LoopResult:=TParallel.&For(0, 100000,
        procedure(AIndex: Integer)
        var
          MyClass: TMyClass;
          r: Real;
        begin
          MyClass:=TMyClass.Create;
          MyClass.MyCommonClass:=MyCommonClass;
          try
            r:=MyClass.DoCalculation(AIndex);
            begin
              ALock.Enter;
              try
                ResultList.Add(r);
              finally
                ALock.Leave;
              end;
            end;
          finally
            MyClass.Free;
          end;
        end);
    finally
      ALock.Free;
    end;

    ResultList.Sort;

    //show the result list
    for i := 0 to ResultList.Count-1 do
    begin
      Memo1.Lines.Add(FloatToStr(ResultList[i]));
    end;

  finally
    ResultList.Free;
  end;
end;

我的示例代码有效。但我不确定它是否正确并且始终有效。

方法MyClass.DoCalculation调用在程序启动时创建的TMyCommonClass对象的DoCalculation方法。

为每个循环创建和销毁TMyClass。但是,TMyCommonClass对象只存在一次,因此不同的线程将并行访问它。

据我所知,我不能在不考虑同步的情况下写入TMyCommonClass,但我不确定是否读取数据和使用方法。

问题是:

  1. 从TMyCommonClass对象读取数据是否可以?

  2. TMyCommonClass是TList的后代。使用Items [i]?

  3. 读取数据是否可以
  4. 可以像我在TMyCommonClass.DoCalculation的示例中一样调用TMyCommonClass的方法吗?这里局部变量和方法参数会发生什么?是否保证每个线程都为局部变量和方法参数获取自己的内存空间,以便它是线程安全的?

1 个答案:

答案 0 :(得分:2)

  

TMyCommonClass对象读取数据是否可以?

阅读始终是线程安全的。当您写入common课程时会出现问题。如果你做了任何写操作,你需要确保其他线程在写入之前写入之前获取数据。
危险在于其他线程在写入中途获得数据(即损坏的数据) 您需要使用锁定,关键部分,原子写入或其他一些机制来防范这种情况。

  

TMyCommonClass是TList的后代。使用Items [i]?

读取数据是否可以

正如我上面所述,阅读没问题,但如果你写信TCommon,你需要采取措施。 TList没有内置的线程安全措施,你需要使用像TThreadList这样的线程安全列表(它使用锁定)。如果您有更高级的需求,请参阅:How can I implement a thread-safe list wrapper in Delphi?

  

可以像我在TMyCommonClass.DoCalculation的示例中那样调用TMyCommonClass的方法吗?这里局部变量和方法参数会发生什么?是否保证每个线程都为局部变量和方法参数获取自己的内存空间,以便它是线程安全的?

是的,DoCalculation没问题,前提是您始终可以信任{TMyCommonClass.}Items[AValue]返回有效数据。
局部变量存在于堆栈中,每个线程都有自己的堆栈,保证永远不会与其他堆栈发生冲突 方法参数通过寄存器和堆栈传递,因此这些也是安全的。