當線程對象的Execute()執行完畢,我們就認為此線程終止了。這時候,它會調用Delphi的一個標准例程EndThread(),這個例程再調用API函數ExitThread()。由ExitThread()來清除線程所占用的棧。
當結束使用TThread對象時,應該確保已經把這個Delphi對象從內存中清除了。這才能確保所有內存占有都釋放掉。盡管在進程終止時會自動清除所有的線程對象,但是及時清除已經不再使用的對象,可以使內存的使用效率提高。利用將FreeOnTerminate的屬性設置為True的方法來及時清除線程對象時最方便的方法,這只需要在Execute()退出之前設置就行了。設置的方法如下
procedure TTestThread.Execute; var i: Integer; begin FreeOnTerminate:= True; for i:=1 to 2000000 do inc(Answer, Round(Abs(Sin(Sqrt(i))))); end;
這樣,當一個線程終止的時候,就會觸發OnTerminate事件,就會有機會在事件處理過程中清除線程對象了。
提示:OnTerminate事件是在主線程的環境中發生的。這就意味着,在處理這個事件的過程中,你可以不需要借助於Synchronize()而自由地訪問VCL
要記住Execute()需要經常地檢查Terminated屬性的值,來確認是否要提前退出。盡管這將意味着當使用線程工作的時候,你必須關心更多的事情,但它能確保在線程結束時,能夠完成必要的清除。下面是一段在Execute()增加處理操作的簡單代碼:
procedure TTestThread.Execute; var i: Integer; begin FreeOnTerminate:= True; for i:= 1 to 2000000 do begin if Terminated then break; inc(Answer, Round(Abs(Sin(Sqrt(i))))); end; end;
注意,在某些緊急情況下,你可以使用Win32 API函數 TerminateThread()來終止一個線程。但是,除非沒有別的辦法了,否則不要使用它。例如,當線程代碼陷入死循環中。TerminateThread()的聲明如下
function TerminateThread(hThread: THandle; dwExitCode: DWORD);
TThread的Handle屬性可以作為第一個參數,因此,TerminateThread()常這樣調用
TerminateThread(MyHosedThread.Handle, 0);
如果選擇這個函數,應該考慮到它的負面影響。首先,此函數在Windows NT與在Windows95/98下並不相同。在Windows95/98下,這個函數能夠自動清除線程所占用的棧;而在Windows NT下,在進程被終止前棧仍被保留。其次,無論線程代碼中是否有try...finally塊,這個函數都會使線程立即終止執行。這意味着,被線程打開的文件沒有被關閉、由線程申請的內存也沒有被釋放等情況。而且,這個函數在終止線程的時候也不通知DLL,當DLL關閉的時候,這也容易出現enti問題