我遇到了已知问题: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异常的文章,但这对我也没有帮助
我会感谢任何帮助和解释,因为我认为我不完全理解这种情况的目的。
答案 0 :(得分:2)
您正尝试从其中一个事件处理程序中停用服务器。这就是你的代码陷入僵局的原因。
将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()
方法。 Active属性设置器在内部为您完成。