1

私はそれがどのように機能しているかを追うことができませんでした。

私の状況をよりよく説明するために、最初に非常に単純な例を示します。このコードは、新しいプロジェクトで作成された新しいフォーム Form1 内にあります。ここで、mmo1 はメモ コンポーネントです。

TOb = class
  Name : String;
  constructor Create(Name : String);
  procedure Go();
end;

procedure TOb.Go;
begin
  Form1.mmo1.Lines.Add(Name);
end;

次に、このイベントのボタンがあります。

procedure TForm1.btn4Click(Sender: TObject);
var
  Index : Integer;
begin
  mmo1.Lines.Clear;
  for Index := 1 to 3 do
    TThread.CreateAnonymousThread(TOb.Create('Thread ' + IntToStr(Index)).Go).Start;
end;

メモの私の出力は次のとおりです。
スレッド 4
スレッド 4
スレッド 4

本当にわからない。

最初の質問: なぜ「名前」の出力はスレッド 4 なのですか? 1 から 3 までの For ループです。少なくとも 1 または 3 である必要があります

: 最後のスレッド「スレッド 4」のみを実行する理由は、「スレッド 1」、「スレッド 2」、「スレッド 3」の順に 3 回ではなく?

なぜ私はこれを求めているのですか?プロセスが正常に動作しているオブジェクトがあります。しかし今、私はこのオブジェクトのリストを処理する必要があるという状況に陥っています。確かに1つ1つの処理はうまくいきますが、私の場合は互いに独立しているので、「うーん、それらをスレッドに入れれば、より速く実行できる」と思いました。

オブジェクトを変更してTThreadを拡張し、 Executeをオーバーライドすることを避けるために、TThread から継承するオブジェクトではなくプロシージャを使用してスレッドを実行する方法を調べ、Anonymous Thread を見つけました。1 つのオブジェクトでは非常にうまく機能しますが、オブジェクト リストをループしようとすると、奇妙な動作が発生します。

これは同じ効果があります。

  for Index := 1 to 3 do
    TThread.CreateAnonymousThread(
      procedure
      var
        Ob : TOb;
      begin
        OB := TOb.Create('Thread ' + IntToStr(Index));
        OB.Go;
      end
    ).Start;

確かに私はオブジェクトをきれいにしていません。これは私が実行していたいくつかのテストにすぎません。何か案は?または、この場合、TThreadから継承してExecuteメソッドをオーバーライドする必要がありますか?

面白いことに、これは問題なく動作します。

mmo1.Lines.Clear;
TThread.CreateAnonymousThread(TOb.Create('Thread ' + IntToStr(1)).Go).Start;
TThread.CreateAnonymousThread(TOb.Create('Thread ' + IntToStr(2)).Go).Start;
TThread.CreateAnonymousThread(TOb.Create('Thread ' + IntToStr(3)).Go).Start;

出力:
  スレッド 1
  スレッド 2
  スレッド 3

4

3 に答える 3

0

Remy Lebeauがコメントに投稿した記事を読んだ後、この解決策を見つけました。

呼び出しを行うプロシージャをもう 1 つ追加して、メイン オブジェクトを変更します。メイン ループで匿名スレッドを作成する代わりに、ループを変更します。オブジェクト内に作成されます。

TOb = class
  Name : String;
  constructor Create(Name : String);
  procedure Process();
  procedure DoWork();
end;

procedure TOb.Process;
begin
  TThread.CreateAnonymousThread(DoWork).Start;
end;

procedure TOb.DoWork;
var
  List : TStringList;
begin
  List := TStringList.Create;
  List.Add('I am ' + Name);
  List.Add(DateTimeToStr(Now));
  List.SaveToFile('D:\file_' + Name + '.txt');
  List.Free;
end;

そしてループ:

List := TObjectList<TOb>.Create();
List.Add(TOb.Create('Thread_A'));
List.Add(TOb.Create('Thread_B'));
List.Add(TOb.Create('Thread_C'));
List.Add(TOb.Create('Thread_D'));

for Obj in List do
  //TThread.CreateAnonymousThread(Obj.Go).Start;
  Obj.Process;

これにより、メイン オブジェクトに最小限の変更を加えるだけで問題が解決します。

于 2017-03-07T02:11:26.683 に答える