Reputation: 103
I do write an app, that uses Indy 10 TCP/IP Client and TThread
. The app connects to the server on Form.OnCreate
event and disconnects from it on Form.OnClose
event. Connection to the server is realized in 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:
type
connThread = class (TThread)
protected
procedure Execute ; override;
private
procedure Sinchronizuot(zinute : string; spalva : TColor; tmrNormalReconn : Boolean);
end;
Form.OnCreate
code:
procedure TForm1.FormCreate(Sender: TObject);
begin
fellnerConn := connThread.Create(True);
fellnerConn.FreeOnTerminate := True;
fellnerConn.Start;
end;
Form.OnClose
code:
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;
Upvotes: 1
Views: 1718
Reputation: 596352
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. The thread object is being destroyed, closing its handle, while WaitFor
is still using it.
You should not be using FreeOnTerminate
like this. 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.
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.
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;
Upvotes: 2