2017-04-15 8 views
0

私はTParallelを持っています。 &ループのため。このループでは、TMyClassオブジェクトを作成して使用して計算を行います。結果はResultListに格納されます。TParallel。&Forループでスレッドセーフなオブジェクトのデータとメソッドを使用する方法?

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オブジェクトからデータを読み取るためにOKですか?

  2. TMyCommonClassは、TListの子孫です。 Items [i]を使用してデータを読み取ることはできますか?

  3. TMyCommonClass.DoCalculationを使用した私の例のように、TMyCommonClassのメソッドを呼び出すことはできますか?ここでローカル変数とメソッドパラメータはどうなりますか?スレッドセーフであるように、すべてのスレッドがローカル変数とメソッドパラメータのための独自のメモリ空間を確保することが保証されていますか?

答えて

2

それはTMyCommonClassオブジェクトからデータを読み取るためにOKですか?

読み取りは常にスレッドセーフです。この問題は、commonクラスに書き込むときに発生します。書き込みを行う場合は、他のスレッドが書き込み前のデータか、か、または書き込み後のデータをにする必要があるかどうかを確認する必要があります。
危険は、他のスレッドが書き込みの途中でデータを取得する(破損したデータなど)ことです。
ロック、クリティカルセクション、アトミック書き込み、またはその他のメカニズムを使用して安全に対処する必要があります。

TMyCommonClassはTListの子孫です。 Items [i]を使用してデータを読み取ることはできますか?

上記のとおり、読解は問題ありませんが、TCommonに書くと対策が必要です。 TListにはスレッドセーフガードが組み込まれていないので、TThreadList(ロックを使用する)のようなスレッドセーフリストを使用する必要があります。あなたは、より高度なニーズを持っている場合は、以下を参照してください。How can I implement a thread-safe list wrapper in Delphi?

それは私がTMyCommonClass.DoCalculationと私の例で行うようTMyCommonClassのメソッドを呼び出すためにOKですか?ここでローカル変数とメソッドパラメータはどうなりますか?スレッドセーフであるように、すべてのスレッドがローカル変数とメソッドパラメータのための独自のメモリ空間を確保することが保証されていますか?

はい、DoCalculationは、{TMyCommonClass.}Items[AValue]が有効なデータを返すと常に信じることができます。
ローカル変数はスタック上にあり、すべてのスレッドは他のスタックと決して衝突しないことが保証された独自のスタックを取得します。
メソッドパラメータはレジスタとスタックに渡されるため、これらも安全です。

関連する問題