TObject与Delphi的线程列表-如何填充? [英] Threadlist of TObject with Delphi - How to populate?

查看:91
本文介绍了TObject与Delphi的线程列表-如何填充?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我对这一主题的有限了解,以下代码应该可以工作.但是我没有预期的结果:

From my limited knowledge about this subject, the following code should work. But I have not the expected result:

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);

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

My expected result would be 6 and HOST1, but I got 1 and "" (empty)

拜托,我想念的是什么?

Please, what I am missing?

谢谢!

推荐答案

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

习惯用法是通过调用LockList锁定列表,并返回可变列表.因此,您需要在List上调用Add.

The idiom is that you lock the list with a call to LockList and that returns a mutable list. So you need to call Add on List.

List := Clients.LockList;
try
  List.Add(Client);
finally
  Clients.UnlockList;
end;

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

That said, TThreadList does offer an Add method that internally uses LockList. The reason that your call to that Add was failing is that you have used the default value of Duplicates which is dupIgnore. And you were passing the same memory address each time.

为什么每次的内存地址都相同?好吧,您犯的另一个错误是销毁TClient对象并在以后引用它们.我猜内存管理器正在重新使用刚刚释放的内存.

Why was the memory address the same each time? Well, the other mistake you made was to destroy your TClient objects and refer to them later. I guess the memory manager was re-using the memory that you just deallocated.

您可能希望将Duplicates设置为dupAccept.至少您需要意识到它具有潜在的影响.

You might want to set Duplicates to dupAccept. At the very least you need to be aware that it has a potential impact.

该程序会产生所需的输出:

This program produces your desired output:

{$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.

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

Or the loop could be simplified even further:

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

为了简单起见,我忽略了执行任何重新分配.显然,在真实代码中,您不会泄漏这种代码的方式.

I neglected to perform any deallocations for the sake of a simpler exposition. Obviously in real code you wouldn't leak the way this code does.

我个人不喜欢此类.不在这个泛型时代.您确实应该查看TThreadList<T>.

Personally I'm not a fan of this class. Not in this age of generics. You really should be looking at 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.

这篇关于TObject与Delphi的线程列表-如何填充?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆