Search code examples
multithreadingdelphiinternet-connection

Delphi: check internet connection in a separated thread


In my form, when the Ontimer event occurs, a new thread is created that checks if internet connection is active. This is my code:

type
TMain = class(TForm)
...
...

TThread_Check = class(TThread)
  private
    TCPClient : TIdTCPClient;
    procedure InternetCheck;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

var Main: TMain;
    Internet, THRD_RUNNING: Boolean;
    OGGI: TDate;
...
...

constructor TThread_Check.Create;
begin
  inherited Create(True);
  TCPClient := TIdTCPClient.Create (NIL);
  try
    try
      TCPClient.ReadTimeout := 2000;
      TCPClient.ConnectTimeout := 2000;
      TCPClient.Port := 80;
      TCPClient.Host := 'google.com';
      TCPClient.Connect;
      TCPClient.Disconnect;
      INTERNET:= true;
    except
      INTERNET:= False;
    end;
  finally
    TCPClient.Free;
  end;
end;

procedure TThread_Check.Execute;
begin
  Synchronize(InternetCheck);
end;

destructor TThread_Check.Destroy;
begin
  THRD_RUNNING:=false;
end;

procedure TThread_Check.InternetCheck;
begin
  if INTERNET then
    begin
      main.idt.Active:=true;
      OGGI:=main.idt.DateTime;     // Pick internet Date ad assign to OGGI
      main.idt.Active:=false;
    end;
end;

procedure TMain.OnTimerEvent(Sender: TObject);
Var THD : TThread_Check;
begin
  if (THRD_RUNNING = False) then
    begin
      THRD_RUNNING := True;
      thd := TThread_Check.Create;
      thd.FreeOnTerminate := true;
      thd.Priority := tpNormal;
      Thd.Resume;
   end;
end;

procedure TMain.OnCreate(Sender: TObject);
begin
  THRD_RUNNING:=false;
end;

Initially it seems to work; my application starts and if internet go down, it notices (in the main form, if INTERNET=false something happens...).

The problem is that after some time the application is active, it freezes and in Windows Task Manager, the Analyze Wait Chain shows me another Thread pending, and this time if internet go down my application does not react!

What's the problem?? Please, help me! Thanks! Emanuele


Solution

  • The TThread constructor runs in the thread that calls it, which in your case is the main UI thread. The only thing you are running in your worker thread is Synchronize(), which runs its code in the main UI thread, defeating the purpose of using a worker thread at all.

    You need to move your TCP connect/disconnect logic from the constructor into Execute instead. Use Synchronize() only to update the UI. In which case, you could just use the OnTerminate event instead, which is already synchronized for you.

    For example:

    type
      TMain = class(TForm)
        ...
      end;
    
      TThread_Check = class(TThread)
      private
        TCPClient : TIdTCPClient;
      protected
        procedure Execute; override;
      public
        constructor Create;
        destructor Destroy; override;
      end;
    
    var
      Main: TMain;
      Internet, THRD_RUNNING: Boolean;
      OGGI: TDate;
    
    ...
    
    constructor TThread_Check.Create;
    begin
      inherited Create(True);
      TCPClient := TIdTCPClient.Create (NIL);
      TCPClient.ReadTimeout := 2000;
      TCPClient.ConnectTimeout := 2000;
      TCPClient.Port := 80;
      TCPClient.Host := 'google.com';
    end;
    
    procedure TThread_Check.Execute;
    begin
      try
        TCPClient.Connect;
        TCPClient.Disconnect;
        INTERNET := True;
      except
        INTERNET := False;
      end;
    end;
    
    destructor TThread_Check.Destroy;
    begin
      TCPClient.Free;
      inherited;
    end;
    
    procedure TMain.OnInternetCheckDone(Sender: TObject);
    begin
      THRD_RUNNING := False;
      if INTERNET then
      begin
        Main.idt.Active := true;
        OGGI := Main.idt.DateTime;
        Main.idt.Active := false;
      end;
    end;
    
    procedure TMain.OnTimerEvent(Sender: TObject);
    var
      THD : TThread_Check;
    begin
      if (not THRD_RUNNING) then
      begin
        thd := TThread_Check.Create;
        thd.FreeOnTerminate := True;
        thd.OnTerminate := OnInternetCheckDone;
        Thd.Resume;
        THRD_RUNNING := True;
      end;
    end;
    
    procedure TMain.OnCreate(Sender: TObject);
    begin
      THRD_RUNNING := False;
    end;