很多人说:TThreadList不是存储了copy,而是reference,那么就象TList一样,可以存储对象指针。如果一个TThread对象execute结束了,并且freeonterminate:=false,那么把它放到ThreadList以后在再后来得到他的时候,怎样让他resume?也就是说怎样再让他执行一遍execute?既然是存储的reference,那就相当于一个thread execute以后再调用resume不会在执行execute一样啊!confused....

解决方案 »

  1.   

    copy_paste当然最明白:copy and reference 的意思了copy:
      是指新建一个对象,或什么的,然后将另外一个对象的所有属性copy过来,那么新建的对象则有所有另外一个对象的属性,但是它是另外一个不同的值。reference:
      一个引用关系,定义了一个对象,这个对象起到一个转接的关系,如果你访问它,其实就是访问它所指向的对象,所以你如果Free,也就是Free所指向的对象(不建议这么做)  TThreadList一般说是: reference,指的就是引用已存在的对象,如Form1.Edit, Form1.Listbox2之类的东东,你会去Free这些东东吗?Thread.FreeOnTerminate 属性:
      它是用于当一个线程完成后,定义是否消亡的标志,为什么,因为线程的execute如果执行完了,也就是一个线程的生命结束了,我们一般指定FreeOnTerminate为True,那么线程就会随Execute的完成而Free,所以当我们不需要可以设为True,让它自动Free,
      但有时结束后,需要访问线程里面的值,如一些public的类型保存了一些我们需要的值,想在execute完成后使用,或想用进使用,那这个FreeOnTerminate := False了,它就不会因Execute而Free了,那就不会访问出错了。一般线程结束(execute)后会触发:
      procedure OnTerminate; override; //写它的override事件
      procedure OnTerminate; override; //写它的override事件
    begin
      inherited OnTerminate; //触发OnTerminated(Sender: Tobject)事件;
      //do you code
    end;execute完成就是一个线程完成,所以不存在Execute重复执行就能运行一个线程的说法,一般我们是在Execute来个大循环,通过Suspend,Resume来控制它Stop,run
      

  2.   

    这位帅哥,我想知道的是TThreadList的用法,为什么用它存储线程对象,而不直接 freeonterminate:=false ??? 拜托看清题目好么?谢了!之所以要存储线程对象,并且用TThreadList来存储,目的不就是为了减少线程的create次数么?下次再创建这个线程类的对象时,就不用create了,直接从threadlist里面得到先前已经创建好的,并且运行结束的线程对象。(因为同一个类的execute是一样的)这就是tthreadlist的作用?如果是这样,那么再次得到的先前创建好并执行完(freeonterminate:=false)的对象的时候怎样当作一个新创建的对象一样处理?
    让他resume?否则怎么使用这个已经execute结束的thread?////////////////////////////
    注意:
    当tthread.execute结束以后,线程运行结束了,但是freeonterminated:=false,则不会自动的释放线程对象,在这种情况下,再想让他执行一遍execute 用resume是不行的!/////////////////////////////////
    我之所以不想在execute里面用循环检测terminated属性的办法,是因为我要先后使用多个线程对象,并且创建的时机使用户决定的,难道tthreadlist就是个摆设???
      

  3.   

    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
    堂堂csdn没人会?
      

  4.   

    一:
      请不要说什么:CSDN没人,CSDN没高手会之类的话。
    二:
      如果别人回答的不好,请指出,请不要讥讽别人。
    三:
      我记得以前回答过你的问题,但没有结贴,使我“记得你”TThreadList只是一个收集器,收集一些会导致线程安全的控件、对象的容器,可以这么理解。使用时,只有两个重要的方法:
    private
      FLock: TThreadList;
    ...
    end;
    procedure SomeProc;
    begin
      FList.LockList;       
      try
        这里进行线程对FList里面对象的访问,这里是线程安全。
        FList通过Add, Remove方法进行对象的Add, Remove操作
      finally
        FList.UnlockList;
      end;
    end;注意:
      SomeProc是全局函数,它是供线程访问的函数,而不是线程里面的函数/方法如果你看VCL源码,你会发现TThreadList其实就是TList and TCriticalSection的集成操作
      

  5.   

    一:
      我也不想这样说,可现状不得不让我这样说,要是在以前,这样的问题根本不会贴这么长时间!!难道就是因为你这个星级大侠给我回答过,就以为我在说你不是高手吗?二:
      我没有讽刺你,哪个字看出来的?“帅哥”?你觉得在讽刺你什么?你帮我回答了,虽然没看清楚题目,但是我后面没谢你吗?三:
      不但你回答我的问题,我不结贴,任何人回答我的问题我都可以不结贴!为啥??要是我能得到想要得答案,我会结贴的(我问的问题很多,少数顾不上结的除外,比起很多人来已经够意思了)!!就象这个问题一样,要我怎么结?tthreadlist用法help里面能查到,但是我最想知道的是:如果一个TThread对象execute结束了,并且freeonterminate:=false,那么把它放到ThreadList以后在再后来得到他的时候,怎样让他resume?也就是说怎样再让他执行一遍execute?既然是存储的reference,那就相当于一个thread execute以后再调用resume不会在执行execute一样啊!
    之所以要存储线程对象,并且用TThreadList来存储,目的不就是为了减少线程的create次数么?下次再创建这个线程类的对象时,就不用create了,直接从threadlist里面得到先前已经创建好的,并且运行结束的线程对象。(因为同一个类的execute是一样的)这就是tthreadlist的作用?如果是这样,那么再次得到的先前创建好并执行完(freeonterminate:=false)的对象的时候怎样当作一个新创建的对象一样处理?
    让他resume?否则怎么使用这个已经execute结束的thread?////////////////////////////////////////为什么就没人看清楚这些话呢?还有,即便会得罪人,我也想说出来,不吐不快!给别人回答问题为了什么?1。得分,让自己上星级,上专家榜。
    2。帮助别人自己也快乐。
    3。both of above.大家想想,自己为了什么?case the very purpose of
    1:
    begin
    劝各位陌生气,即便故意不结你贴搂主的可用分也不会收回!我到想呢,csdn让吗?你不得分,别人回答的就会得分??大家都不得分你怕啥?上榜是按名次的!又不是按分!!
    end;
    2:
    begin
    热心帮助了别人,也要看看自己是不是真的帮助了,不要打着帮助的旗号,为了赚分!哪个问问题的不着急??
    end;
    3:
    begin
    既然想主观为得分+自己心里爽,客观帮别人,那就真正把问题回答好,能让搂主结贴!大家本来谁都不认识,又不是要你无偿回答!
    end;
    end;
    /////////////////////////////////////////
      

  6.   

    无论如何, copy_paste(木石三) 兄弟,你帮我回答了那么多,我还是感激你的!
      

  7.   

    to crywolfwang:
      我以前也上过段DFW,但发现那边气氛也不怎么样,怎么是除“非技术版”的,如果你是DFW来的,我可以体会。to stanely:
      1: 我从来没说自已是高手,相反很多时间我是在看CSDN的贴子,因为我觉得我很菜
      2:你不如看看我发的贴子,不管怎么样,我都会结贴,我觉得如果问题无解或回的不理想,我不会呆过一段时间的,不管如何。我不会因为别人做得怎么样,说:你看看他们,100个还没结过一个,就自已放任之。我理解你的意思,你所说的是线程池的实现,可你理解不够。
      
    线程池这个概念从书上我也没看过,只是看过VCL的一些实现,知道一些情况。
    大概的意思是说:实现线程取出,放回的功能,取出时从已有空闲的线程池里面取,如没有空闲则创建,创建数量和你设置的数量有关(要设个最大值,不能无限制),其中线程池我们可以看成是TList对象
      
      还有我再说明:当TThread.Execute运行完成后,线程的生命就完了,不可能通过Resume进行恢复。
      Windows线程是给VCL.TThread类封装了,将它的ThreadFunc封装到Execute 方法中,所以当Execute执行退出时,即是一个线程退出,线程完成。而ResumeThread, SuspendThread的使用是在ThreadFunc中,即在Execute。
      
      线程池的实现有点复杂,有时间我帮你写个。如果你有空,可以到VCL\ScktComp.pas,就是那TServerSocket那个类看看,那有个线程池的实现。
      

  8.   

    to: copy_paste(木石三) 各有各的原则,我不认为我放分请人回答的没得到正确答案,也应该结贴,我只会自己up,说不定哪天有人看到了,能帮我,或者我自己琢磨明白了。可用分再多我也会珍惜的!/////////////////////////////////////////////我的确不理解所谓线程缓冲池是怎么运作的,怎样从那里面得到一个已经创建过的线程对象,并使用。好的,我看看ScktComp.pas,有问题再贴上来。/////////////////////////////////////////////感谢各位关注!
      

  9.   

    各有各的原则吧,虽然我很看不惯老提问题但从不结贴的人,因为他们损害了别人积极性。我来CSDN两年多了,很多同来的,我以前像他们样,也每天疯狂来这看/回答问题,可是现在很少了,嘿嘿,我不是说你,只是看到你上面所说的有感而发。如果我喜欢分的话,两年,时间不长也不短,嘿嘿...  还有你说一下,你为了那线程池是做什么用的,因为如果写线程池的话都是专门完成一个功能,如果要写通用的话,好像有点难,我先试试。
      

  10.   

    你看ScktComp.pas只看这两个类即可:
    TServerClientThread 
      它有一个KeepInCache的标志和Event: TEvent,注意这两个属性的动作
    TServerWinSocket
      管理上面Thread 的Pooler功能的
      

  11.   

    unit ThreadPooler;interfaceuses
      Windows, Messages, SysUtils, Classes, SyncObjs, ShellAPI;//{$DEFINE __EXIT}type
      TPoolerManager = class;  TPoolerThread = class(TThread)
      private
        FData: Pointer;
        FEvent: THandle;
      {$IFDEF __EXIT}
        FExit: THandle;
      {$ENDIF}
        FKeepInCache: Boolean;
        FManager: TPoolerManager;
        procedure HandleException;
      protected
        function StartThread: Boolean;
        function EndThread: Boolean;
        procedure Run(Data: Pointer); virtual;
        procedure Execute; override;
      public
        constructor Create(CreateSuspended: Boolean; AManager: TPoolerManager);
        destructor Destroy; override;
        procedure ReActive(Data: Pointer);
        property Data: Pointer read FData;
        property Event: THandle read FEvent;
        property KeepInCache: Boolean read FKeepInCache write FKeepInCache;
      end;  TThreadEvent = procedure(AThread: TPoolerThread) of object;
      TGetThreadEvent = procedure(AManager: TPoolerManager;
        var AThread: TPoolerThread) of object;  TPoolerManager = class
      private
        FMaxCount: Byte;
        FThreadEnd: TThreadEvent;
        FThreadStart: TThreadEvent;
        FList: TList;
        FLock: TCriticalSection;
        FOnGetThread: TGetThreadEvent;
        procedure DoThreadStart(Thread: TPoolerThread);
        procedure DoThreadEnd(Thread: TPoolerThread);
        procedure AddThread(Thread: TPoolerThread);
        procedure RemoveThread(Thread: TPoolerThread);
        procedure SetMaxCount(const Value: Byte);
        function GetThreadCount: Integer;
        function GetActiveThreadCount: Integer;
        function GetItem(const Index: Integer): TPoolerThread;
      public
        constructor Create;
        destructor Destroy; override;
        function GetPoolerThread(Data: Pointer): TPoolerThread; virtual;
        property OnGetThread: TGetThreadEvent read FOnGetThread write FOnGetThread;
        property ThreadStart: TThreadEvent read FThreadStart write FThreadStart;
        property ThreadEnd: TThreadEvent read FThreadEnd write FThreadEnd;
        property Item[const Index: Integer]: TPoolerThread read GetItem;
        property MaxCount: Byte read FMaxCount write SetMaxCount default 10;
        property ThreadCount: Integer read GetThreadCount;
        property ActiveThreadCount: Integer read GetActiveThreadCount;
      end;implementation{ TPoolerThread }constructor TPoolerThread.Create(CreateSuspended: Boolean; AManager: TPoolerManager);
    begin
      FManager := AManager;
      FKeepInCache := False;
      FreeOnTerminate := True;
      FEvent := CreateEvent(nil, True, False, nil);
    {$IFDEF __EXIT}
      FExit := CreateEvent(nil, False, False, nil);
    {$ENDIF}
      inherited Create(True);
      ReActive(nil);
      FManager.AddThread(Self);
      if not CreateSuspended then Resume;
    end;destructor TPoolerThread.Destroy;
    begin
      if Assigned(FManager) then
      begin
        FManager.RemoveThread(Self);
      {$IFDEF __EXIT}
        SetEvent(FExit);
      {$ENDIF}  
      end;
      CloseHandle(FEvent);
    {$IFDEF __EXIT}
      CloseHandle(FExit);
    {$ENDIF}
      inherited Destroy;
    end;function TPoolerThread.EndThread: Boolean;
    begin
      FData := nil;
      Result := Terminated or not FKeepInCache;
    end;function TPoolerThread.StartThread: Boolean;
    begin
      if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then
        ResetEvent(FEvent);
      Result := not Terminated and Assigned(FData);
    end;procedure TPoolerThread.HandleException;
    var
      E: Exception;
    begin
      E := Exception(ExceptObject);
      if E is EAbort then Exit;
      if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
      if E is Exception then
      begin
        if Assigned(ApplicationShowException) then
          ApplicationShowException(E);
      end else
        SysUtils.ShowException(E, nil);
    end;procedure TPoolerThread.Run(Data: Pointer);
    begin
      // 重载此方法
      // 保留一个Data: Pointer作为参数使用
    end;procedure TPoolerThread.ReActive(Data: Pointer);
    begin
      FData := Data;
      SetEvent(FEvent);
    end;procedure TPoolerThread.Execute;
    begin
      FManager.DoThreadStart(Self);
      try
        try
          while True do
          begin
            if StartThread then Run(FData);
            if EndThread then break;
          end;
        except
          KeepInCache := False;
          Synchronize(HandleException);
        end;
      finally
        FManager.DoThreadEnd(Self);
      end;
    end;{ TPoolerManager }procedure TPoolerManager.AddThread(Thread: TPoolerThread);
    begin
      FLock.Enter;
      try
        if FList.IndexOf(Thread) = -1 then
        begin
          FList.Add(Thread);
          Thread.KeepInCache := FList.Count <= FMaxCount;
        end;
      finally
        FLock.Leave;
      end;
    end;procedure TPoolerManager.RemoveThread(Thread: TPoolerThread);
    begin
      FLock.Enter;
      try
        FList.Remove(Thread);
      finally
        FLock.Leave;
      end;
    end;procedure TPoolerManager.DoThreadEnd(Thread: TPoolerThread);
    begin
      FLock.Enter;
      try
        if Assigned(FThreadEnd) then FThreadEnd(Thread);
      finally
        FLock.Leave;
      end;
    end;procedure TPoolerManager.DoThreadStart(Thread: TPoolerThread);
    begin
      FLock.Enter;
      try
        if Assigned(FThreadStart) then FThreadStart(Thread);
      finally
        FLock.Leave;
      end;
    end;constructor TPoolerManager.Create;
    begin
      inherited Create;
      FLock := TCriticalSection.Create;
      FList := TList.Create;
      FMaxCount := 10;
    end;destructor TPoolerManager.Destroy;
    {$IFDEF __EXIT}
    var
      I: Integer;
    {$ENDIF}  
    begin
    {$IFDEF __EXIT}
      for I := FList.Count - 1 downto 0 do  { do not localize }
        with TPoolerThread(FList[I]) do
        begin
          Terminate;
          ReActive(nil);
          WaitForSingleObject(FExit, INFINITE);
        end;
    {$ENDIF}    
      FList.Free;
      FLock.Free;
      inherited Destroy;
    end;function TPoolerManager.GetPoolerThread(Data: Pointer): TPoolerThread;
    var
      I: Integer;
    begin
      Result := nil;
      FLock.Enter;
      try
        for I := 0 to FList.Count - 1 do
          if not Assigned(TPoolerThread(FList[I]).FData) then
          begin
            Result := FList[I];
            break;
          end;
      finally
        FLock.Leave;
      end;
      if not Assigned(Result) then
      begin
        if Assigned(FOnGetThread) then FOnGetThread(Self, Result);
        if not Assigned(Result) then
          Result := TPoolerThread.Create(False, Self);
      end;
      Result.ReActive(Data);
    end;procedure TPoolerManager.SetMaxCount(const Value: Byte);
    var
      I, Start: Integer;
    begin
      if FMaxCount <> Value then
      begin
        if Value < FMaxCount then
          Start := Value else
          Start := FMaxCount;
        FMaxCount := Value;
        FLock.Enter;
        try
          for I := 0 to FList.Count - 1 do
            TPoolerThread(FList[I]).KeepInCache := I < Start;
        finally
          FLock.Leave;
        end;
      end;
    end;function TPoolerManager.GetThreadCount: Integer;
    begin
      FLock.Enter;
      try
        Result := FList.Count;
      finally
        FLock.Leave;
      end;
    end;function TPoolerManager.GetActiveThreadCount: Integer;
    var
      I: Integer;
    begin
      Result := 0;
      FLock.Enter;
      try
        for I := 0 to FList.Count - 1 do
          if Assigned(TPoolerThread(FList[I]).FData) then
            Inc(Result);
      finally
        FLock.Leave;
      end;
    end;function TPoolerManager.GetItem(const Index: Integer): TPoolerThread;
    begin
      Result := FList[Index];
    end;end.