[英]Stopping thread and disconnecting indy tcp client on form close
I do write an app, that uses Indy 10 TCP/IP Client and TThread
. 我确实编写了一个使用Indy 10 TCP / IP Client和
TThread
的应用程序。 The app connects to the server on Form.OnCreate
event and disconnects from it on Form.OnClose
event. 该应用程序连接到服务器
Form.OnCreate
事件并断开与它Form.OnClose
事件。 Connection to the server is realized in TThread
. 与服务器的连接是在
TThread
实现的。
When I do start the app while ethernet cable is disconnected and try to close app until connection time out, then I do get these two exeptions: 当我在断开以太网电缆连接的情况下启动应用程序并尝试关闭应用程序直到连接超时时,我确实得到了以下两个提示:
If I try to close app while it is connected to client, then I get only this exeption: 如果在连接到客户端时尝试关闭应用程序,那么我只会得到以下示例:
If I close the app while thread executes sleep, then no exeptions I do get. 如果我在线程执行睡眠时关闭了该应用程序,则不会得到任何异常。
What am I doing wrong, or it is normal behavior? 我在做什么错,还是正常行为?
TThread
class code: TThread
类代码:
type
connThread = class (TThread)
protected
procedure Execute ; override;
private
procedure Sinchronizuot(zinute : string; spalva : TColor; tmrNormalReconn : Boolean);
end;
Form.OnCreate
code: Form.OnCreate
代码:
procedure TForm1.FormCreate(Sender: TObject);
begin
fellnerConn := connThread.Create(True);
fellnerConn.FreeOnTerminate := True;
fellnerConn.Start;
end;
Form.OnClose
code: Form.OnClose
代码:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if fellnerConn <> nil then
fellnerConn.Terminate;
if idCl.Connected then
begin
try
idCl.Disconnect;
idCl.IOHandler.Free;
finally
if fellnerConn <> nil then
begin
fellnerConn.WaitFor;
fellnerConn := nil;
end;
end;
end;
end;
Thread execute code: 线程执行代码:
procedure connThread.Execute;
var
zinute : string;
spalva : TColor;
begin
inherited;
while not Form1.fellnerConn.Terminated do
begin
zinute := 'Jungiamasi prie Moxa serverio ' + Form1.idCl.Host;
spalva := clYellow;
Synchronize(procedure
begin
Sinchronizuot(zinute, spalva, False);
end
);
try
Form1.idCl.Connect;
except
on E: Exception do
begin
zinute := e.Message + ' Nepavyko prisijungti.';
spalva := clWebRed;
Synchronize(procedure
begin
Sinchronizuot(zinute, spalva, False);
end);
Sleep(1000);
end;
end;
end;
end;
The socket error is to be expected. 预计套接字错误。 The main thread is closing the socket while the worker thread is still using it.
主线程正在关闭套接字,而工作线程仍在使用它。
But, you cannot use TThread.WaitFor()
with FreeOnTerminate=True
, that is why you keep getting "the handle is invalid" errors. 但是,您不能将
TThread.WaitFor()
与FreeOnTerminate=True
,这就是为什么您不断收到“句柄无效”错误的原因。 The thread object is being destroyed, closing its handle, while WaitFor
is still using it. 在
WaitFor
仍在使用线程对象的同时,该线程对象被销毁,关闭其句柄。
You should not be using FreeOnTerminate
like this. 您不应该这样使用
FreeOnTerminate
。 It should only be used for start-and-forget type of threads. 它仅应用于“开始忘记”类型的线程。 As soon as you need to keep a reference to a thread object, you should not use its
FreeOnTerminate
property anymore. 一旦需要保留对线程对象的引用,就不应再使用其
FreeOnTerminate
属性。
Either way, you should be using the thread's OnTerminate
event so you can nil
your reference to the thread as soon as the thread has terminated. 无论哪种方式,你应该使用线程的
OnTerminate
事件,所以你可以nil
的参考线,一旦线程终止。
Try something more like this: 尝试更多类似这样的方法:
type
connThread = class (TThread)
protected
FClient: TIdTCPClient;
procedure Execute; override;
private
procedure Sinchronizuot(zinute : string; spalva : TColor; tmrNormalReconn : Boolean);
public
constructor Create(Client: TIdTCPClient); reintroduce;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
fellnerConn := connThread.Create(IdCl);
fellnerConn.OnTerminate := ThreadTerminated;
fellnerConn.Start;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if fellnerConn <> nil then
fellnerConn.Terminate;
try
idCl.Disconnect;
finally
if fellnerConn <> nil then
begin
fellnerConn.OnTerminate := nil;
fellnerConn.WaitFor;
FreeAndNil(fellnerConn);
end;
end;
end;
procedure TForm1.ThreadTerminated(Sender: TObject);
begin
fellnerConn := nil;
TThread.ForceQueue(nil, Sender.Free);
end;
constructor connThread.Create(Client: TIdTCPClient);
begin
inherited Create(True);
FClient := Client;
end;
procedure connThread.Execute;
var
zinute : string;
spalva : TColor;
begin
while not Terminated do
begin
zinute := 'Jungiamasi prie Moxa serverio ' + FClient.Host;
spalva := clYellow;
Synchronize(procedure
begin
Sinchronizuot(zinute, spalva, False);
end
);
try
FClient.Connect;
except
on E: Exception do
begin
zinute := e.Message + ' Nepavyko prisijungti.';
spalva := clWebRed;
Synchronize(procedure
begin
Sinchronizuot(zinute, spalva, False);
end
);
if Terminated then Exit;
Sleep(1000);
Continue;
end;
end;
try
// use FClient as needed...
finally
FClient.Disconnect;
end;
end;
end;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.