我有已知问题的另一个TIdTCPServer死锁的情况
问题描述:
:IdTCPServer挂起,而试图将其停用。我读过很多关于这个问题的文章,并且我意识到发生了这种僵局。但是我很难理解哪个代码确实会导致问题。我的应用程序甚至没有窗口,所以对VCL组件的同步调用不是原因。有2个事件处理程序OnConnect和OnExecute。问题出现在OnConnect中。代码:
我有已知问题的另一个TIdTCPServer死锁的情况
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的代码是相当巨大的,所以我不会在这里发布。除了我想这个问题不在其中。
当客户端连接到服务器和条件是假的服务器尝试断开该客户端和挂就行了FServer.Active := false;
我已经排除了所有的记录从代码(我认为这个问题是在线程访问日志文件)。所以在事件处理程序中只有计算和没有任何可能导致死锁的事情)。我读过关于重新提高Indy例外的内容,但这对我也没有帮助。
因为我觉得我没有完全理解这种情况的目的,我希望得到任何帮助和解释。
答
您试图从其某个事件处理程序中取消激活服务器。这就是为什么你的代码处于死锁状态。
将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;
BTW,你不需要手动调用StartListening()
和StopListening()
方法。 Active属性设置器在内部为你做。
非常感谢雷米。你的回答已经让我明白了一切。 – gator88