var
  myCs : TRTLCriticalSection;//临界区//用户类
type
  TSimpleClient = class
    ListLink : integer;
    Thread   : pointer;
end;procedure TfrmServer.FormCreate(Sender: TObject);
begin
  // 创建用户列表.
  ClientList := TList.Create;  // 创建用户对象.
  Client := TSimpleClient.Create;  InitalizeCriticalSection(myCs);  
end;// 将用户添加进ClientList中
procedure Add(myThread : TThread)
begin
  EnterCriticalSection(myCs);  try
    Client.ListLink := ClientList.Count;    Client.Thread := myThread;    // 将用户资料放入线程的Data中.
    myThread.Data := Client;    // 将用户加入用户列表中.
    ClientList.Add(Client);
  finally
    LeaveCriticalSection(myCs);
end;//将用户从ClientList中删除 
procedure Del(myThread : TThread);
var
  i : integer;
begin
  EnterCriticalSection(myCs);
  try   
    i := TSimpleClient(myThread.Data).ListLink;    // 把列表中最后一个结点提前.
    ClientList.Items[i] := ClientList.Items[ClientList.Count - 1];    // 修改这个结点的ListLink为结点在ClientList的index.
    TSimpleClient(ClientList.Items[i]).ListLink := i;    // 删除最后一个结点.
    ClientList.Delete(ClientList.Count - 1);
    
  finally
    if Client <> nil then
    begin
      Client.Free;
      Client := nil;
      myThread.Data := nil;
    end;
    LeaveCriticalSection(myCs);
end;为什么我TList中的结点有时候删除不完全呢?当结点少的时候删除很正常,结点一多就出问题了,总会有少数结点未能够正常删除.
原来用TList.Delete(),也不能完全删除TList中的所有结点.
到底是什么原因导致这种情况呢?该怎么解决呢?谢谢.

解决方案 »

  1.   

    for i:=0 to ClientList.Items.Count-1 do
      ClientList.Delete(ClientList.Items.Count-1);这样不行吗?
      

  2.   

    不要直接用索引值来删除,而是根据你的判断条件,如Thread值相同等等,循环整个List,找到你要的Item后,再得到它的索引值来删除。这样会安全点。
      

  3.   

    对了,如果“不要直接用索引值来删除,而是根据你的判断条件,如Thread值相同等等,循环整个List,找到你要的Item后,再得到它的索引值来删除。这样会安全点。”那原来结点所在的空间怎么办??还是没被释放啊!
      

  4.   

    你的这种结构和算法是比较快的,不错,Del的时候,能够判断一下i <> ClientList.Count-1再做移动和重设Index就更好
    你的问题估计是你的Client字段或变量造成的procedure Del(myThread : TThread);
    var
      i, Count_1 : integer;
      Client: TSimpleClient; //不要用全局的,用临时变量
    begin
      EnterCriticalSection(myCs);
      try   
        Client := TSimpleClient(myThread.Data);
        I := Client.ListLink;
        Count_1 := ClientList.Count-1;    if I <> Count_1 then
        begin
          // 把列表中最后一个结点提前.
          ClientList.Items[i] := ClientList.Items[Count_1];      // 修改这个结点的ListLink为结点在ClientList的index.
          TSimpleClient(ClientList.Items[i]).ListLink := i;
        end;    // 删除最后一个结点.
        ClientList.Delete(Count_1);
        Client.Destroy();    
        myThread.Data := nil;
      finally
        LeaveCriticalSection(myCs);
      end;
    end;
      

  5.   

    为什么Client用临时变量而不用全局变量呢?会有什么影响吗?谢谢。
      

  6.   

    很简单,主要是add和del的次序问题,举个例子吧
    按照你原来的代码,顺序做三个操作:
    1.Client := Add(ThreadA);   //ClientA ListLink = 0; Client = ClientA
    2.Client := Add(ThreadB);   //ClientB ListLink = 1; Client = ClientB
    3.Del(ThreadA);
    本应Free ClientA,可是你Del的最后那段代码却是,
    if Client <> nil then
        begin
          Client.Free; 
          Client := nil;
          myThread.Data := nil;
        end;
    因为这时Client = ClientB,所以实际上Free的是ClientB
    所以你应该Free的是myThread.Data所指向的Client,而不要Free全局变量那个Client