Delphi的TObject线程列表 - 如何填充?

Guy*_*ush 1 delphi multithreading list object tobject

根据我对此主题的有限知识,以下代码应该有效.但我没有预期的结果:

type
  TClient = class(TObject)
    Host: String;
  end;

var
  Clients: TThreadList;

const
  Hosts: Array[0..5] of String = ('HOST1', 'HOST2', 'HOST3', 'HOST4', 'HOST5', 'HOST6');
var
  I: Integer;
  List: TList;
  Client: TClient;
begin
  try
    for I := Low(Hosts) to High(Hosts) do
    begin
      Client := TClient.Create;
      with Client Do
      try
        Host := Hosts[I];
        List := Clients.LockList;
        try
          Clients.Add(Client);
        finally
          Clients.UnlockList;
        end;
      finally
        Client.Free;
      end;
    end;
  except
    on E:Exception Do ShowMessage(E.Message);
  end;

// RESULT TEST
List := Clients.LockList;
try
  I := List.Count;
  S := TClient(List.Items[0]).Host;
finally
  Clients.UnlockList;
end;
ShowMessage(IntToStr(I));
ShowMessage(S);
Run Code Online (Sandbox Code Playgroud)

我的预期结果是6和HOST1,但我得到1和""(空)

拜托,我错过了什么?

谢谢!

Dav*_*nan 6

List := Clients.LockList;
try
  Clients.Add(Client); // <--- mistake here
finally
  Clients.UnlockList;
end;
Run Code Online (Sandbox Code Playgroud)

成语是你通过调用锁定列表LockList并返回一个可变列表.所以,你需要调用AddList.

List := Clients.LockList;
try
  List.Add(Client);
finally
  Clients.UnlockList;
end;
Run Code Online (Sandbox Code Playgroud)

也就是说,TThreadList确实提供了Add一种内部使用的方法LockList.Add你对它的调用失败的原因是你使用的默认值DuplicatesdupIgnore.而且你每次都传递相同的内存地址.

为什么每次内存地址都相同?好吧,你犯的另一个错误是破坏你的TClient物体并在以后引用它们.我猜内存管理器正在重新使用你刚刚解除分配的内存.

您可能想要设置DuplicatesdupAccept.至少你需要意识到它有潜在的影响.

该程序产生您想要的输出:

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

type
  TClient = class(TObject)
    Host: String;
  end;

const
  Hosts: Array[0..5] of String = ('HOST1', 'HOST2', 'HOST3', 'HOST4', 
    'HOST5', 'HOST6');
var
  I: Integer;
  List: TList;
  Client: TClient;
  Clients: TThreadList;
begin
  Clients := TThreadList.Create;
  Clients.Duplicates := dupAccept;

  for I := Low(Hosts) to High(Hosts) do
  begin
    Client := TClient.Create;
    Client.Host := Hosts[I];
    List := Clients.LockList;
    try
      List.Add(Client);
    finally
      Clients.UnlockList;
    end;
  end;

  List := Clients.LockList;
  try
    Writeln(List.Count);
    Writeln(TClient(List.Items[0]).Host);
  finally
    Clients.UnlockList;
  end;
end.
Run Code Online (Sandbox Code Playgroud)

或者循环可以进一步简化:

for I := Low(Hosts) to High(Hosts) do
begin
  Client := TClient.Create;
  Client.Host := Hosts[I];
  Clients.Add(Client);
end;
Run Code Online (Sandbox Code Playgroud)

为了更简单的阐述,我忽略了执行任何解除分配.显然,在实际代码中,您不会泄漏此代码的方式.

就个人而言,我不是这个班的粉丝.不是在这个泛型的时代.你真的应该看看TThreadList<T>.

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, Generics.Collections;

type
  TClient = class
    Host: string;
    constructor Create(AHost: string);
  end;

constructor TClient.Create(AHost: string);
begin
  inherited Create;
  Host := AHost;
end;

const
  Hosts: array[0..5] of string = ('HOST1', 'HOST2', 'HOST3', 'HOST4',
    'HOST5', 'HOST6');

var
  Host: string;
  List: TList<TClient>;
  Clients: TThreadList<TClient>;

begin
  Clients := TThreadList<TClient>.Create;
  Clients.Duplicates := dupAccept;

  for Host in Hosts do
    Clients.Add(TClient.Create(Host));

  List := Clients.LockList;
  try
    Writeln(List.Count);
    Writeln(List.First.Host);
  finally
    Clients.UnlockList;
  end;
end.
Run Code Online (Sandbox Code Playgroud)