简体   繁体   English

在表单关闭时停止线程并断开Indy TCP客户端

[英]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: 当我在断开以太网电缆连接的情况下启动应用程序并尝试关闭应用程序直到连接超时时,我确实得到了以下两个提示:

  • Socket.Error #10038Socket operation on non-socket. Socket.Error#10038非套接字上的套接字操作。
  • Thread Error: The handle is invalid(6). 线程错误:句柄无效(6)。

If I try to close app while it is connected to client, then I get only this exeption: 如果在连接到客户端时尝试关闭应用程序,那么我只会得到以下示例:

  • Thread Error: The handle is invalid(6). 线程错误:句柄无效(6)。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM