简体   繁体   中英

Delphi TIdTcpServer force stop IdSync after someTimeOut

I need to develop a TCP server and client with persistent connections using Indy and Delphi XE2. Almost everything is going well.

This service is a critical service, so I need to put in some protection in the server to prevent unnecessary processing or freezes. Because of this, I create a thread to check a timeout for critical processes.

I made this TIdSync class:

type
  TSync = class(TIdSync)
  protected
    procedure DoSynchronize; override;
  end;

procedure TSync.DoSynchronize;
var
  oTimeOut: TThreadTimeOut;
begin
  ...
  oTimeOut := TThreadTimeOut.Create(AContext, WaitTimeOut*2, Self);
  oTimeOut.Start;
  ...
  // the code below is just a test, **this is the key to my question**
  // if something goes wrong in any subroutine of DoSynchronize, I want
  // to stop execution of this object and destroy it. In the thread above
  // I want to test when the timeout elapses. If this IdSync object still
  // exists and if this routine is still executing, I want to stop execution
  // of any routine or subroutine of this object to avoid freezing the
  // service and stop memory consumption and CPU usage

  while true do begin
    Sleep(100);
  end;

  //If everything is OK
  oTimeOut.Stop;
end;

procedure TThreadTimeOut.execute;
var
  IniTime: DWORD;
begin
  IniTime := GetTickCount;
  while GetTickCount < IniTime + TimeOut  do begin
    Sleep(SleepInterval);
    if StopTimeOut then
       Exit;
  end;

  if ((Terminated = False) or (StopTimeOut)) and (IoHandler <> nil)  then begin
    IOHandler.Connection.IOHandler.Close;
    IdSync.Free; //here I try to make things stop execution but the loop to test is still running
  end;
end;

This code above works fine to stop receiving and sending data when the timeout elapses, but not to stop execution of TIdSync . How can I do that?

There is no timeout logic in TIdSync (largely because there is no timeout logic in TThread.Synchronize() , which TIdSync uses internally).

You cannot destroy a TIdSync object while it is running. A synced procedure cannot be aborted prematurely once it has been queued for execution, or has started running. It must be allowed to run to completion.

TIdSync.DoSynchronize() (or any method synced with TThread.Queue() or TThread.Synchronize() ) is executed in the context of the main UI thread. Long-running code should be executed in its own thread, not in the main UI thread. Make sure the main UI thread is not blocked from processing new messages and sync requests in a timely manner.

If you want to stop a synced procedure, you need to have it handle a TEvent object or other flag which worker threads can signal when needed, and that the procedure checks periodically so it can exit as soon as possible (either gracefully or by raising an exception).

Synched operations of any nature should be short, to prevent blockages/deadlocks, resource starvation, etc. You need to re-think your design. You are doing things the wrong way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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