2011-04-05 91 views
1

下載源代碼編譯的可執行文件(221 KB(226925個字節)):前http://www.eyeclaxton.com/download/delphi/skeleton.zip線程摧毀永遠不會被執行

爲什麼不一樣,如果我關閉應用程序的破壞析構函數被調用(單擊X按鈕)該線程已終止? FastMM4使用FPauseEvent事件報告內存泄漏。

我應該如何銷燬線程?如果有人在線程結束之前關閉應用程序。

unit SkeletonThread; 

interface 

uses 
    Windows, Classes, SysUtils, SyncObjs; 

type 
    TOnInitialize = procedure(Sender: TObject; const AMaxValue: Integer) of object; 
    TOnBegin = procedure(Sender: TObject) of object; 
    TOnProgress = procedure(Sender: TObject; const APosition: Integer) of object; 
    TOnPause = procedure(Sender: TObject; const APaused: Boolean) of object; 
    TOnFinish = procedure(Sender: TObject) of object; 
    TOnFinalize = procedure(Sender: TObject) of object; 

    TMasterThread = class(TThread) 
    private 
    { Private declarations } 
    FPaused: Boolean; 
    FPosition: Integer; 
    FMaxValue: Integer; 
    FOnBegin: TOnBegin; 
    FOnProgress: TOnProgress; 
    FOnFinish: TOnFinish; 
    FOnInitialize: TOnInitialize; 
    FOnFinalize: TOnFinalize; 
    FPauseEvent: TEvent; 
    FOnPause: TOnPause; 
    procedure BeginEvent(); 
    procedure ProgressEvent(); 
    procedure FinishEvent(); 
    procedure InitializeEvent(); 
    procedure FinalizeEvent(); 
    procedure PauseEvent(); 
    procedure CheckForPause(); 
    protected 
    { Protected declarations } 
    procedure DoInitializeEvent(const AMaxValue: Integer); virtual; 
    procedure DoBeginEvent(); virtual; 
    procedure DoProgress(const APosition: Integer); virtual; 
    procedure DoPauseEvent(const APaused: Boolean); virtual; 
    procedure DoFinishEvent(); virtual; 
    procedure DoFinalizeEvent(); virtual; 
    public 
    { Public declarations } 
    constructor Create(const CreateSuspended: Boolean; const theValue: Integer); 
    destructor Destroy(); override; 
    procedure Pause(); 
    procedure Unpause(); 
    published 
    { Published declarations } 
    property IsPaused: Boolean read FPaused write FPaused default False; 
    property OnInitialize: TOnInitialize read FOnInitialize write FOnInitialize default nil; 
    property OnBegin: TOnBegin read FOnBegin write FOnBegin default nil; 
    property OnProgress: TOnProgress read FOnProgress write FOnProgress default nil; 
    property OnPause: TOnPause read FOnPause write FOnPause default nil; 
    property OnFinish: TOnFinish read FOnFinish write FOnFinish default nil; 
    property OnFinalize: TOnFinalize read FOnFinalize write FOnFinalize default nil; 
    end; 

    TSkeletonThread = class(TMasterThread) 
    private 
    { Private declarations } 
    procedure DoExecute(const theValue: Integer); 
    protected 
    { Protected declarations } 
    procedure Execute(); override; 
    public 
    { Public declarations } 
    published 
    { Published declarations } 
    end; 

implementation 

{ TMasterThread } 
constructor TMasterThread.Create(const CreateSuspended: Boolean; const theValue: Integer); 
begin 
    inherited Create(CreateSuspended); 
    Self.FreeOnTerminate := True; 

    Self.FPosition := 0; 
    Self.FMaxValue := theValue; 
    Self.FPaused := False; 
    Self.FPauseEvent := TEvent.Create(nil, True, True, ''); 
end; 

destructor TMasterThread.Destroy(); 
begin 
    FreeAndNil(FPauseEvent); 
    if (Pointer(FPauseEvent) <> nil) then Pointer(FPauseEvent) := nil; 
    inherited Destroy(); 
end; 

procedure TMasterThread.DoBeginEvent(); 
begin 
    if Assigned(Self.FOnBegin) then Self.FOnBegin(Self); 
end; 

procedure TMasterThread.BeginEvent(); 
begin 
    Self.DoBeginEvent(); 
end; 

procedure TMasterThread.DoProgress(const APosition: Integer); 
begin 
    if Assigned(Self.FOnProgress) then Self.FOnProgress(Self, APosition); 
end; 

procedure TMasterThread.ProgressEvent(); 
begin 
    Self.DoProgress(Self.FPosition); 
end; 

procedure TMasterThread.DoFinishEvent(); 
begin 
    if Assigned(Self.FOnFinish) then Self.FOnFinish(Self); 
end; 

procedure TMasterThread.FinishEvent(); 
begin 
    Self.DoFinishEvent(); 
end; 

procedure TMasterThread.DoInitializeEvent(const AMaxValue: Integer); 
begin 
    if Assigned(Self.FOnInitialize) then Self.FOnInitialize(Self, AMaxValue); 
end; 

procedure TMasterThread.InitializeEvent(); 
begin 
    Self.DoInitializeEvent(Self.FMaxValue); 
end; 

procedure TMasterThread.DoFinalizeEvent(); 
begin 
    if Assigned(Self.FOnFinalize) then Self.FOnFinalize(Self); 
end; 

procedure TMasterThread.FinalizeEvent; 
begin 
    Self.DoFinalizeEvent(); 
end; 

procedure TMasterThread.DoPauseEvent(const APaused: Boolean); 
begin 
    if Assigned(Self.FOnPause) then Self.FOnPause(Self, APaused); 
end; 

procedure TMasterThread.PauseEvent(); 
begin 
    Self.DoPauseEvent(Self.FPaused); 
end; 

procedure TMasterThread.Pause(); 
begin 
    Self.FPauseEvent.ResetEvent(); 
    Self.FPaused := True; 
    Self.Synchronize(Self.PauseEvent); 
end; 

procedure TMasterThread.Unpause(); 
begin 
    Self.FPaused := False; 
    Self.Synchronize(Self.PauseEvent); 
    Self.FPauseEvent.SetEvent(); 
end; 

procedure TMasterThread.CheckForPause(); 
begin 
    if (not (Self.Terminated)) then Windows.Sleep(1); 
    Self.FPauseEvent.WaitFor(INFINITE); 
end; 

{ TSkeletonThread } 
procedure TSkeletonThread.DoExecute(const theValue: Integer); 
var 
    X: Integer; 
begin 
    Self.Synchronize(InitializeEvent); 
    try 
    Self.Synchronize(BeginEvent); 
    try 
     for X := 0 to (theValue - 1) do 
     begin 
    Self.CheckForPause(); 

    if (not Self.FPaused) and (not Self.Terminated) then 
    begin 
     Self.FPosition := Self.FPosition + 1; 
     Self.Synchronize(ProgressEvent); 
    end 
    else begin 
     Break; 
    end; 
     end; 

     for X := Self.FPosition downto 1 do 
     begin 
    Self.CheckForPause(); 

    if (not Self.FPaused) and (not Self.Terminated) then 
    begin 
     Self.FPosition := X; 
     Self.Synchronize(ProgressEvent); 
    end 
    else begin 
     Break; 
    end; 
     end; 
    finally 
     Self.Synchronize(FinishEvent); 
    end; 
    finally 
    Self.Synchronize(FinalizeEvent); 
    end; 
end; 

procedure TSkeletonThread.Execute(); 
begin 
    Self.DoExecute(Self.FMaxValue); 
end; 

end. 
+0

不回答,但只是一個想法。在你的代碼中使用單獨的線程有什麼意義,如果你做的所有事情都是在主線程中執行的(你正在使用同步)? – Linas 2011-04-05 11:09:36

+5

是的,我總是從陌生人下載並運行.exe的。 – cHao 2011-04-05 11:10:36

+0

當你關閉應用程序時,你是在線程上調用Terminate並等待它停止? – 2011-04-05 11:11:03

回答

2

你必須自己終止線程(告訴它停止)。一種方法是使用線程的Terminate過程,但您必須在線程Execute方法中檢查這一點。這樣的事情:

procedure Execute; 
begin 
    inherited; 

    while not Terminated do 
    begin 
    // do your job 
    end; 
end; 

procedure TForm1.StopThread; 
begin 
    MyThread.Terminate; 

    // wait and block until the scheduling thread is finished 
    AResult := WaitForSingleObject(MyThread.Handle, cShutdownTimeout); 

    // check if we timed out 
    if AResult = WAIT_TIMEOUT then 
    TerminateThread(MyThread.Handle, 0); 
end; 

或者你可以使用信號建立到窗口,所以你不必循環。

procedure Execute; 
begin 
    inherited; 

    while not Terminated do 
    begin 
    WaitStatus := WaitForSingleObject(FTermEvent, Max(0, SleepInterval)); 

    // check what was the cause for signalization 
    if WaitStatus <> WAIT_TIMEOUT then 
     Terminate; 
    end; 
end; 

procedure TForm1.StopThread; 
begin 
    // Terminate the thread 
    SetEvent(FTermEvent); 
    // close the handle 
    CloseHandle(FTermEvent); 

    // wait and block until the scheduling thread is finished 
    AResult := WaitForSingleObject(MyThread.Handle, cShutdownTimeout); 

    // check if we timed out 
    if AResult = WAIT_TIMEOUT then 
    TerminateThread(MyThread.Handle, 0); 
end; 

燈號可以終止信令非常簡潔的方式,因爲你可以使用WaitForMultipleObjects的和釋放等待在不同的條件。我使用WaitForSingleObject來使事情不復雜。

另外一定要在線程構造函數中設置「FreeOnTerminate:= True」。哦,當然,最後的硬終端是可選的。這可能是危險的。如果你會使用它,你最瞭解自己。如果您確定線程最終會停止,您還可以等待更長的時間或無限的時間。

+0

當然它確實解釋了。它永遠不會被調用,因爲線程在應用程序之前未被銷燬。當你關閉你的應用程序時,線程不會自行破壞。是的,當操作系統破壞這個過程時,他們最終會被清理乾淨,但是你的調試器永遠不會看到這一點。 – Runner 2011-04-05 12:07:45

+0

嗯,很明顯我引用的評論已被刪除:) – Runner 2011-04-05 12:08:23

+0

好的,如果你在delphi IDE中運行應用程序,在TMasterThread.Destroy()的第一行添加一個斷點,點擊main中的「start」按鈕形成並等待線程完成後,您會看到程序將在您的中斷點停止。如果你做同樣的事情,並且這次在線程結束之前,只需單擊關閉按鈕,斷點將不會被執行。 – eyeClaxton 2011-04-05 12:14:55

1
+0

-1。你爲什麼這樣回答這個問題?檢測當前進程的結束與檢測外部進程的結束完全不同。 – 2011-04-05 13:58:26

+0

我誤解了這個問題,道歉 – Amey 2011-04-05 16:34:08