不要TThread.FreeOnTerminate=True
使用TThread.WaitFor()
。
當Execute()
退出時,如果TThread.FreeOnTerminate=True
那麼TThread
對象自行破壞,關閉TThread.WaitFor()
等待的線程句柄。所以你可能看到「無效句柄」錯誤。或者您可能會遇到訪問衝突,或者由於競爭條件造成未定義的行爲,或者WaitFor()
可能會在無效對象上被調用,或者通常該對象被銷燬,而WaitFor()
爲仍在運行。並且WaitFor()
會在任何操作系統錯誤(包括「無效句柄」錯誤)上引發異常。
設置TThread.FreeOnTerminate=True
主要用於與一旦被啓動時被遺忘的線程一起使用。如果在啓動後需要引用線程,請根本不要使用FreeOnTerminate
。你不希望線程消失在你的背後。
而且,Execute()
不應該通過外部對象指針訪問其Terminated
屬性。改用Self
指針。
試試這個:
procedure TForm1.Button1Click(Sender: TObject);
begin
ProccesSupervisor := TMyThread0.Create(False);
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if ProccesSupervisor <> nil then
begin
ProccesSupervisor.Terminate;
ProccesSupervisor.WaitFor;
FreeAndnil(ProccesSupervisor);
end;
end;
procedure TMyThread0.Execute;
begin
while not Terminated do
begin
//some code here
end;
end;
如果你絕對必須設置TThread.FreeOnTerminate=True
,那麼你應該使用TThread.OnTerminate
事件,知道什麼時候該線程消失,但仍TThread.WaitFor()
走就走,做自己的錯誤處理,如:
procedure TForm1.Button1Click(Sender: TObject);
begin
ProccesSupervisor := TMyThread0.Create(True);
ProccesSupervisor.FreeOnTerminate := True;
ProccesSupervisor.OnTerminate := ThreadTerminated;
ProccesSupervisor.Resume;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
H: array[0..1] of THandle;
Msg: TMsg;
begin
if ProccesSupervisor <> nil then
begin
ProccesSupervisor.Terminate;
//ProccesSupervisor.WaitFor;
H[0] := ProccesSupervisor.Handle;
H[1] := Classes.SyncEvent;
WaitResult := 0;
repeat
case MsgWaitForMultipleObjects(2, H, False, INFINITE, QS_SENDMESSAGE) of
WAIT_OBJECT_0, WAIT_FAILED: Break;
WAIT_OBJECT_0 + 1: CheckSynchronize;
WAIT_OBJECT_0 + 2: PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
end;
until ProccesSupervisor = nil;
end;
end;
procedure TForm1.ThreadTerminated(Sender: TObject);
begin
ProccesSupervisor := nil;
end;
procedure TMyThread0.Execute;
begin
while not Terminated do
begin
//some code here
end;
end;
什麼是「一些代碼在這裏」在做什麼? – Blorgbeard
使用'嘗試除外' – Sami
@Blorgbeard即使簡單的睡眠(100)它崩潰。 @ Sami它必須比簡單的嘗試更優雅的方式,除了 –