Delphi 另一种TIdTCPServer死锁情况

Delphi 另一种TIdTCPServer死锁情况,delphi,deadlock,delphi-xe,indy,Delphi,Deadlock,Delphi Xe,Indy,我遇到了一个已知的问题:IdTCPServer在尝试停用它时挂起。我读过很多关于这个问题的文章,我意识到僵局正在发生。但我很难理解到底是哪种代码导致了问题。我的应用甚至没有窗口,所以对VCL组件的同步调用不是原因。有两个事件处理程序OnConnect和OnExecute。问题出现在OnConnect中。代码: TMyServer = class ... private FServer: TIdTCPServer; ... end; TMyServer.ServerConnect(AContex

我遇到了一个已知的问题:IdTCPServer在尝试停用它时挂起。我读过很多关于这个问题的文章,我意识到僵局正在发生。但我很难理解到底是哪种代码导致了问题。我的应用甚至没有窗口,所以对VCL组件的同步调用不是原因。有两个事件处理程序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的代码非常庞大,所以我不会在这里发布。此外,我想问题不在其中。
当客户端连接到服务器且条件为false时,服务器尝试断开此客户端的连接,并挂起行
FServer.Active:=false
我已经从代码中排除了所有日志记录(我认为问题在于线程对日志文件的访问)。因此,在事件处理程序中,只有计算,而没有任何东西会导致死锁)。我读过关于重新提出印地岛例外情况的报道,但这对我也没有帮助。

如果您能提供任何帮助和解释,我将不胜感激,因为我认为我不完全理解这种情况的目的。

您正试图从服务器的事件处理程序中停用服务器。这就是代码死锁的原因

Active
属性设置为False将终止所有正在运行的客户端线程,并等待它们完全终止。在这些线程的上下文中触发
OnConnect
OnDisconnect
OnExecute
事件。因此,最终会出现一个线程,该线程试图自行等待并死锁

要使服务器安全地自行停用,必须异步执行,例如使用
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()
方法。活动属性设置器在内部为您完成此操作。

非常感谢Remy。你的回答让我明白了一切。