开发者

Another TIdTCPServer deadlock situation

I'm having the known issue: IdTCPServer hangs while trying to deactivate it. I've read lots of articles concerning such problem and I'm aware of the deadlock happening. But it's difficult for me to understand which code exactly 开发者_运维问答causes the problem. My app doesn't have even a window so the synchronized call to VCL component isn't the reason. Got 2 event handlers OnConnect and OnExecute. The problem appears in OnConnect. The code:

TMyServer = class
...
private
FServer: TIdTCPServer;
...
end;

TMyServer.ServerConnect(AContext...);  //onconnect
begin
  try
    if not Condition then
    begin
      ...
      AContext.Connection.Disconnect;
      Stop;
    end
    else Start;
  except
    on E: Exception do
      if E is EIdException then raise;
      ...  
  end;

TMyServer.Start;
begin
  ...
  FServer.active := true;
  FServer.StartListening;
  ...
end;

TMyServer.Stop;
begin
  ...
  FServer.StopListening;
  FServer.Active := false;
  ...
end;

TMyServer.ServerExecute(AContext...);  //onexecute
begin
  LLine := AContext.Connection.IOHandler.ReadLn;
  case (LLine) of
  ...
  end;
end;

The code of ServerExecute is quite huge so I won't post it here. Besides I suppose the problem isn't in it.

When the client connects to the server and Condition is false the server tries to disconnect this client and hangs on the line FServer.Active := false;

I've already excluded all the logging from the code (I thought the problem was in the threads access to log file). So in the event handlers there are only calculations and nothing which can cause the deadlock). I've read about re-raising of Indy exceptions but that didn't help me too.

I would appreciate any help and explanation cause I think I don't fully understand the purpose of this situation.


You are trying to deactivate the server from inside one of its event handlers. That is why your code is deadlocking.

Setting the Active property to False terminates all running client threads and waits for them to fully terminate. The OnConnect, OnDisconnect, and OnExecute events are triggered in the context of those threads. So you end up with a thread that is trying to wait on itself and deadlocks.

To have the server deactivate itself safely, you must do it asynchronously, such as by using the TIdNotify class, for example:

uses
  ..., IdSync;

TMyServer.ServerConnect(AContext...);  //onconnect
begin
  try
    if not Condition then
    begin
      ...
      AContext.Connection.Disconnect;
      TIdNotify.NotifyMethod(Stop);
    end
    else
      TIdNotify.NotifyMethod(Start);
  except
    on E: Exception do
      if E is EIdException then raise;
      ...  
  end;
end;

BTW, you do not need to call the StartListening() and StopListening() methods manually. The Active property setter does that internally for you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜