{ $HDR$} {**********************************************************************} { Unit archived using Team Coherence } { Team Coherence is Copyright 2002 by Quality Software Components } { } { For further information / comments, visit our WEB site at } { http://www.TeamCoherence.com } {**********************************************************************} {} { $Log: 10383: IdThreadMgrPool.pas { { Rev 1.0 2002.11.12 10:56:22 PM czhower } { 2002-06-23 -Andrew P.Rybin -2 deadlock fix (and also in IdThread) } unit IdThreadMgrPool; interface uses Classes, IdThread, IdThreadMgr; type TIdThreadMgrPool = class(TIdThreadMgr) protected FPoolSize: Integer; FThreadPool: TThreadList; // procedure ThreadStopped(AThread: TIdThread); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetThread: TIdThread; override; procedure ReleaseThread(AThread: TIdThread); override; procedure TerminateThreads; override; published property PoolSize: Integer read FPoolSize write FPoolSize default 0; End; implementation uses IdGlobal, SysUtils; { TIdThreadMgrPool } constructor TIdThreadMgrPool.Create(AOwner: TComponent); begin inherited Create(AOwner); FThreadPool := TThreadList.Create; end; destructor TIdThreadMgrPool.Destroy; var i: integer; LThreads: TList; begin FPoolSize := 0; LThreads := FThreadPool.LockList; try for i:=0 to LThreads.Count-1 do begin with TIdThread(LThreads[i]) do begin //thread can use ComponentStreamSystem, we must prevent deadlock //Best way for IdUser's: calling TcpServer.Active:=FALSE & TerminateThreads from OnDestroy FreeOnTerminate := TRUE; Terminate; Start; end;//with end; finally FThreadPool.UnlockList; end; FreeAndNil(FThreadPool); inherited Destroy; end; function TIdThreadMgrPool.GetThread: TIdThread; var LThreadPool: TList; begin LThreadPool := FThreadPool.LockList; try if LThreadPool.Count > 0 then begin Result := TIdThread(LThreadPool[0]); LThreadPool.Delete(0); end else begin Result := CreateNewThread; Result.StopMode := smSuspend; end; finally FThreadPool.UnlockList; end; ActiveThreads.Add(Result); end; procedure TIdThreadMgrPool.ReleaseThread(AThread: TIdThread); var LThreadPool: TList; begin with ActiveThreads.LockList do try // To avoid ReleaseThread-code is if IndexOf(AThread)=-1 then exit; // executed multiple times, because finally // AThread.Free call ReleaseThread ActiveThreads.UnlockList; // again. Now we will detect the 2nd end; // time, and jump out of the routine ActiveThreads.Remove(AThread); // here. LThreadPool := FThreadPool.LockList; try // PoolSize = 0 means that we will keep all active threads in the thread pool if ((PoolSize > 0) and (LThreadPool.Count >= PoolSize)) or AThread.Terminated or AThread.Suspended then begin AThread.OnStopped := NIL; AThread.FreeOnTerminate := TRUE; AThread.Terminate; AThread.Start;//if suspended end else begin AThread.OnStopped := ThreadStopped; AThread.Stop;//go sleep end; finally FThreadPool.UnlockList; end; End;//ReleaseThread procedure TIdThreadMgrPool.TerminateThreads; begin inherited TerminateThreads; with FThreadPool.LockList do try while Count > 0 do begin with TIdThread(Items[0]) do begin FreeOnTerminate := TRUE; Terminate; Start; //Stopped==TRUE because Terminated end;//with Delete(0); end; finally FThreadPool.UnlockList; end; end; procedure TIdThreadMgrPool.ThreadStopped(AThread: TIdThread); begin AThread.OnStopped := NIL; //work is done. prevent from unexpected usage if Assigned(FThreadPool) and NOT AThread.Terminated then begin FThreadPool.Add(AThread); end else begin AThread.Terminate; //abnormal situation: application termination or what? end; end; end.