上篇博客中提出了一個問題:怎么結束一個定時循環執行的線程,並給出了一個解決方案,但是又出現了一個問題,詳細去參考上一篇博客。
然后出去撒了個尿,突然腦子里出現了一個想法(看來工作和思考久了,出去走走,哪怕是去撒個尿,都可能尿出火花,所以工作和學習的時常根本就不等同於效率靈感不是在那里拼命工作、想就能出來的),需要結合上上篇博客:關於FreeOnTerminate的知識
上面所給出的第一種解決方案:
線程(Execute)在執行定時循環;然后先讓 DestroyAThread設置 Terminated屬性,通知線程去結束執行、釋放資源;然后在線程結束執行、釋放資源之后再去通知DestroyAThread,再由DestroyAThread來顯式調用線程的 Free方法來釋放線程
所以結合 FreeOnTerminate的作用,復習一下:
類 Create 了就要 Free;
但 TThread(的子類) 有特殊性, 很多時候我們不能確定新建的線程什么時候執行完(也就是什么時候該釋放);
如果線程執行完畢自己知道釋放就好了, 所以 TThread 給了一個布爾屬性 FreeOnTerminate, 如果為 True, 線程執行完畢后就會自釋放.
進行改造:
首先在線程的Execute方法里面將 FreeOnTerminate設置為True,然后進行自己的定時循環執行;然后DestroyAThread設置Terminated屬性,通知線程去結束執行、釋放資源;然后在線程結束執行、釋放資源之后,因為FreeOnTerminate設置為True了,所以就不要再通知 DestroyAThread,自己在釋放完資源、結束執行之后,就會自釋放。
同樣DestroyAThread設置Terminated屬性之后,就可以直接退出,因為不需要在DestroyAThread里面顯式釋放線程。
同樣也就不需要線程再有 CanFree這種通知別人來釋放它的屬性了,所以也能簡化線程類的設計(在面向對象的程序設計中一個原則就是:類盡可能小,所以那些能不需要的屬性、方法就不要去定義和使用,把冗余的屬性和方法一定要去掉……)
所以新的代碼可以是這樣的
Execute方法:
procedure TDoSomeThingThread.Execute; var i: Integer; begin inherited; FreeOnTerminate:= True; //CanFree := False; //不再需要 CanFree這樣的屬性了,也就簡化了線程類的設計 try while not Self.Terminated do begin ........ { 在這里編寫該線程具體所要做的事情的代碼邏輯, 如果這里面還是要循環執行一些任務, 最好能在每次循環的時候也都再去檢查一下Terminated的值 如果是True就結束循環, 就是保證在較短的事件內不斷檢查 Terminated標志,保證能夠及時退出 } ........ Sleep(5); Application.ProcessMessages; end; finally //CanFree := True; //不再需要 CanFree這樣的屬性了,也就簡化了線程類的設計 {在這里將線程申請的資源進行釋放……后續操作} end; end;
DestroyAThread方法:
procedure DestroyAThread(testThread: TDoSomeThingThread); stdcall; var itime: Cardinal; begin if Assigned(testThread) then begin testThread.Terminate; //在這里將testThread的 Terminated屬性設置為True { 這里就只需要通過Terminate方法將線程的Terminated設置為True, 去通知線程結束就行了, 不需要關心線程的釋放問題,因為線程會自己釋放 } end; //這個方案中就不需要使用Free方法去顯式釋放線程資源了,因為線程自己會在執行結束后自動釋放 end;