另一个TIdTCPServer死锁情况

时间:2011-08-05 11:12:43

标签: delphi deadlock delphi-xe indy

我遇到了已知问题:IdTCPServer在尝试停用时挂起。我已经阅读了很多关于这个问题的文章,我知道发生了僵局。但是我很难理解哪些代码确切地导致了问题。我的应用程序甚至没有窗口,因此同步调用VCL组件不是原因。有2个事件处理程序OnConnect和OnExecute。问题出现在OnConnect中。代码:

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;

ServerExecute的代码非常庞大,所以我不会在这里发布。此外,我认为问题不在其中 当客户端连接到服务器并且Condition为false时,服务器会尝试断开此客户端并挂起FServer.Active := false;行。 我已经从代码中排除了所有日志记录(我认为问题出在线程访问日志文件中)。所以在事件处理程序中只有计算,没有什么可以导致死锁)。我已经阅读过有关重新提出Indy异常的文章,但这对我也没有帮助 我会感谢任何帮助和解释,因为我认为我不完全理解这种情况的目的。

1 个答案:

答案 0 :(得分:2)

您正尝试从其中一个事件处理程序中停用服务器。这就是你的代码陷入僵局的原因。

Active属性设置为False将终止所有正在运行的客户端线程,并等待它们完全终止。 OnConnectOnDisconnectOnExecute事件在这些线程的上下文中触发。所以你最终得到了一个试图等待自己和死锁的线程。

要让服务器安全地停用,您必须异步执行,例如使用TIdNotify类,例如:

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;

顺便说一句,您无需手动调用StartListening()StopListening()方法。 Active属性设置器在内部为您完成。