폼을 닫을 준비가되면 스레드가 계속 실행 중이면 종료하도록 신호를 보내지 만 완전히 종료 될 때까지 기다리지 않고 양식을 실제로 삭제할 때 스레드 개체를 명시 적으로 삭제합니다 FreeOnTerminate=True
을 사용해도 닫힙니다.
명시 적으로 스레드 개체를 삭제하기 전에 TThread.WaitFor()
으로 전화해야하지만 표시되는 오류의 원인이되는 FreeOnTerminate=True
을 사용할 때는 작동하지 않습니다. 그 외에도 스레드가 여전히 실행 중이며 명시 적으로 스레드 객체를 파괴하고있는 경우 TThread
소멸자가 WaitFor()
을 호출합니다. 그래서 어느 쪽이든, 당신은 오류를 일으키고 있습니다.
그래서, 당신이 필요로 다음 중 하나
은 또한 다음과 같은 TIdHTTP.OnWork
사건에서와 같이 GET
요청을 중단 스레드 내에서 확인할 수 있습니다 플래그를 설정하는 스레드의 가상 TerminatedSet()
메서드를 재정 건의 할 것입니다.
해보십시오이, 같은 FreeOnTerminated=True
를 사용하여 :
type
TLoadListThread = class(TThread)
private
FUrl: string;
FOnLoading: TNotifyEvent;
DoAbort: Boolean;
procedure CheckAbort;
procedure DoLoading;
procedure HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
protected
procedure TerminatedSet; override;
public
constructor Create(const AUrl: String);
property OnLoading: TNotifyEvent read FOnLoading write FOnLoading;
end;
constructor TLoadListThread.Create(const AUrl: String);
begin
inherited Create(True);
FreeOnTerminate := True;
FUrl := AUrl;
end;
procedure TLoadListThread.CheckAbort;
begin
if DoAbort then SysUtils.Abort;
end;
procedure TLoadListThread.DoLoading;
begin
if Assigned(FOnLoading) then FOnLoading(Self);
end;
procedure TLoadListThread.HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
CheckAbort;
end;
procedure TLoadListThread.TerminatedSet;
begin
inherited;
DoAbort := True;
end;
procedure TLoadListThread.Execute;
var
HTTP: TIdHTTP;
begin
HTTP := TIdHTTP.Create;
try
st := TStringList.Create;
try
ms := TMemoryStream.Create;
try
if Assigned(FOnLoading) then Synchronize(DoLoading);
CheckAbort;
HTTP.Get(FUrl, ms);
ms.Position := 0;
st.LoadFromStream(ms, TEncoding.UTF8);
finally
ms.Free;
end;
CheckAbort;
// Do something with st
finally
st.Free;
end;
finally
HTTP.Free;
end;
end;
private
procedure CloseOnTerminated(Sender: TObject);
procedure TForm58.FormShow(Sender: TObject);
begin
StopLoadListThread;
LListThread := TLoadListThread.Create(urlserver);
LListThread.OnLoading := LoadListThreadLoading;
LListThread.OnTerminate := LoadListThreadFinished;
LListThread.Start;
end;
procedure TForm58.StopLoadListThread;
begin
if Assigned(LListThread) then
begin
LListThread.OnLoading := nil;
LListThread.OnTerminate := nil;
LListThread.Terminate;
LListThread := nil;
end;
end;
procedure TForm58.LoadListThreadLoading(Sender: TObject);
begin
Label1.Text := 'Loading...';
end;
procedure TForm58.LoadListThreadFinished(Sender: TObject);
begin
if LListThread.FatalException = nil then
// Do something
else
// Do something else
LListThread := nil;
end;
procedure TForm58.CloseOnTerminated(Sender: TObject);
begin
LListThread := nil;
Close;
end;
procedure TForm58.CloseButtonClick(Sender: TObject);
begin
Close;
end;
procedure TForm58.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if Assigned(LListThread) then
begin
LListThread.OnTerminate := CloseOnTerminated;
LListThread.Terminate;
Action := TCloseAction.caNone;
end
else
begin
// Do something
Action := TCloseAction.caFree;
end;
end;
또는이, FreeOnTerminated=False
를 사용하여 :
type
TLoadListThread = class(TThread)
private
FUrl: string;
FOnLoading: TNotifyEvent;
DoAbort: Boolean;
procedure CheckAbort;
procedure DoLoading;
procedure HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
protected
procedure TerminatedSet; override;
public
constructor Create(const AUrl: String);
property OnLoading: TNotifyEvent read FOnLoading write FOnLoading;
end;
constructor TLoadListThread.Create(const AUrl: String);
begin
inherited Create(True);
FreeOnTerminate := False;
FUrl := AUrl;
end;
procedure TLoadListThread.CheckAbort;
begin
if DoAbort then SysUtils.Abort;
end;
procedure TLoadListThread.DoLoading;
begin
if Assigned(FOnLoading) then FOnLoading(Self);
end;
procedure TLoadListThread.HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
CheckAbort;
end;
procedure TLoadListThread.TerminatedSet;
begin
inherited;
DoAbort := True;
end;
procedure TLoadListThread.Execute;
var
HTTP: TIdHTTP;
begin
HTTP := TIdHTTP.Create;
try
st := TStringList.Create;
try
ms := TMemoryStream.Create;
try
if Assigned(FOnLoading) then Synchronize(DoLoading);
CheckAbort;
HTTP.Get(FUrl, ms);
ms.Position := 0;
st.LoadFromStream(ms, TEncoding.UTF8);
finally
ms.Free;
end;
CheckAbort;
// Do something with st
finally
st.Free;
end;
finally
HTTP.Free;
end;
end;
procedure TForm58.FormShow(Sender: TObject);
begin
StopLoadListThread;
LListThread := TLoadListThread.Create(urlserver);
LListThread.OnLoading := LoadListThreadLoading;
LListThread.OnTerminate := LoadListThreadFinished;
LListThread.Start;
end;
procedure TForm58.StopLoadListThread;
begin
if Assigned(LListThread) then
begin
LListThread.OnLoading := nil;
LListThread.OnTerminate := nil;
LListThread.Terminate;
LListThread.WaitFor;
FreeAndNil(LListThread);
end;
end;
procedure TForm58.LoadListThreadLoading(Sender: TObject);
begin
Label1.Text := 'Loading...';
end;
procedure TForm58.LoadListThreadFinished(Sender: TObject);
var
Thread: TThread;
begin
Thread := TThread(Sender);
if Thread.FatalException = nil then
// Do something
else
// Do something else
// if using 10.1 Berlin or earlier:
TThread.CreateAnonymousThread(
procedure
begin
TThread.Queue(nil,
procedure
begin
Thread.Free;
end
);
end;
).Start;
// if using 10.2 Tokyo or later:
TThread.ForceQueue(nil,
procedure
begin
Thread.Free;
end
);
end;
procedure TForm58.CloseButtonClick(Sender: TObject);
begin
Close;
end;
procedure TForm58.FormClose(Sender: TObject; var Action: TCloseAction);
begin
StopLoadListThread;
// Do something
Action := TCloseAction.caFree;
end;
다른 전략을 사용해보십시오. get이 끝날 때까지 양식을 닫지 마십시오. – nolaspeaker
스레드 세이프 전략을 사용하십시오 : Execute 메서드 내에서만 TIdHTTP를 생성하고 사용하십시오 – mjn42
다음 연습을 심각하게 고려해야합니다 : 폼 단위를 사용하지 않는 * 자체 * 단위로 스레드를 작성하거나 그 문제에 대한 VCL 단위. VCL은 스레드로부터 안전하지 않습니다. 스레드 내에서 양식에 직접 액세스하는 것은 허위입니다. –