1

動的に作成された に一意の識別子を格納する方法について、学術的な関心がありますTThread

私はこのようなものを作成します:

procedure TForm1.Button1Click(Sender: TObject);
var thrn:word;
begin
for thrn := 0 to 5 do//<--- this is a loop variable that should give the unique numbers
  TThread.CreateAnonymousThread(
    procedure()
    var
      i: longint;
      r: double;
      thrns:string;
    begin
      thrns:=inttostr(thrn);//in this thread? variable I try to store the ID as string
      repeat
        for i := 0 to 100000000 do
        begin
          r := random(high(i));//this loop gives some dummy job 
          r := sqr(r);         //to the thread to slow it down
        end;
        TThread.Synchronize(nil,
          procedure()
          begin
            memo1.Text:=memo1.Text+#13#10+
              'done'+thrns;//it returns strange IDs including '6'
          end);
      until false;
    end).Start;
end;

同期メソッドで表示できるように、動的に作成されたスレッドに一意の識別子を渡すことはできますか?

4

2 に答える 2

5

これは古典的な誤解です。匿名メソッドがキャプチャすることは理解していますが、匿名メソッドは何をキャプチャするのでしょうか? 値または変数?

答えは後者です。それらは変数をキャプチャします。thrn6 つの匿名メソッドのそれぞれがキャプチャする単一の変数 があります。変数は 1 つなので、値は常に 1 つだけです。

もちろん、コードをスレッドで実行しているため、この変数でデータ競合が発生します。したがって、私の「いつでも」但し書きです。そのため、再現不可能で予測不可能な結果が得られます。また、ループが完了した後にループ変数にアクセスする可能性が高く、値は未定義です。

匿名メソッドごとに異なる値が必要な場合は、匿名メソッドごとに新しい変数を作成する必要があります。別の質問に対する私の答えは、次のことを示しています。匿名メソッド - 変数のキャプチャと値のキャプチャ

したがって、あなたのコンテキストで説明するには、さらに足場が必要です。

function GetThreadProc(thrn: Integer): TProc;
begin
  Result := 
    procedure
    begin
      // thrn is passed by value, so a copy is made, i.e. a new variable
      ....
    end;
end;

....

procedure TForm1.Button1Click(Sender: TObject);
var 
  thrn: Integer;
begin
  for thrn := 0 to 5 do
    TThread.CreateAnonymousThread(
      GetThreadProc(thrn)).Start;
end;
于 2015-12-12T16:11:13.140 に答える
2

識別子の値を取得する必要があります。これを行う方法の例を次に示します。

procedure TForm1.Button1Click(Sender: TObject);
  function GetAnonProc( ID: Word): TProc;
  begin
    Result :=
      procedure
      var
        i: longint;
        r: double;
        thrns:string;
      begin
        thrns:= inttostr(ID);// Capture value
        repeat
          for i := 0 to 100000000 do
          begin
            r := random(high(i));//this loop gives some dummy job
            r := sqr(r);         //to the thread to slow it down
          end;
          TThread.Synchronize(nil,
            procedure()
            begin
              memo1.Text:=memo1.Text+#13#10+
                'done'+thrns;//it returns strange IDs including '6'
            end);
        until false;
      end;

  end;
var
  thrn:word;
  p: TProc;
begin
  for thrn := 0 to 5 do
  begin
    p := GetAnonProc(thrn); // Capture thrn value
    TThread.CreateAnonymousThread(p).Start;
  end;
end;

上記のコードは、ローカルID変数への 6 つの異なる参照をキャプチャします。それぞれ価値が違います。

問題のコードは、単一の変数参照をキャプチャします。スレッドがいつ実行されているかを制御できないため、スレッドが変数参照から取得する値を予測する方法はありません。観測された値6は、ループ変数の値がループの完了後に未定義であるという事実によるものです。

匿名メソッドがどのように機能し、変数バインディングを使用するかをさらに理解するには、Variable Binding Mechanismをお読みください。

于 2015-12-12T15:49:26.187 に答える