目录
一、bug症状
在使用indy的TIdTCPServer控件时,我们打开服务时会设置控件属性Active为True,关闭服务时自然是设置控件属性Active为False。当我们打开TIdTCPServer服务,如果有一些客户端已经连接上,此时如果我们需要关闭TCP服务时,自然会设置控件属性Active为False,,大概率会导致程序死机,非常恼人。此时需要手工关闭进程才可以重新启动。这样使用起来就很不方便,当然我们也可以通过别的办法回避(我们先一个一个线程关闭,然后再让Active设置为False就可以回避这个问题)。导致这个问题的原因是有几个客户端连接,就会有几个对应的服务线程服务客户端,此时TIdTCPServer在设置Active为False的时候并没有清除干净这些线程,线程列表清除有Bug,就会导致程序死机。
二、Bug存在的版本
我修复的是下面的版本,其它版本是否存在问题不得而知,同学们可以根据这个版本对比自己的版本进行修复!
修复后文件下载连接:IdScheduler.pas
delphi版本:
Indy版本:
三、Bug解决方案
查找indy的源程序文件IdScheduler.pas单元,在这个文件单元中,对文件进行修改,修改前和修改后的代码如下:
修改前代码(为了看清楚,我是用的是截图):
procedure TIdScheduler.TerminateAllYarns;
var
i: Integer;
LList: TIdYarnList;
begin
Assert(FActiveYarns<>nil);
while True do begin
// Must unlock each time to allow yarns that are terminating to remove themselves from the list
LList := FActiveYarns.LockList;
try
if LList.Count = 0 then begin
Break;
end;
for i := LList.Count - 1 downto 0 do begin
TerminateYarn(
{$IFDEF HAS_GENERICS_TList}LList.Items[i]{$ELSE}TIdYarn(LList.Items[i]){$ENDIF}
);
end;
finally
FActiveYarns.UnlockList;
end;
IndySleep(500); // Wait a bit before looping to prevent thrashing
end;
end;
修改后代码:
procedure TIdScheduler.TerminateAllYarns;
var
i: Integer;
LList: TIdYarnList;
begin
Assert(FActiveYarns<>nil);
while True do begin
// Must unlock each time to allow yarns that are terminating to remove themselves from the list
LList := FActiveYarns.LockList;
try
if LList.Count = 0 then begin
Break;
end;
for i := LList.Count - 1 downto 0 do begin
TerminateYarn(
{$IFDEF HAS_GENERICS_TList}LList.Items[i]{$ELSE}TIdYarn(LList.Items[i]){$ENDIF}
);
//sensor 2019-06-12
LList.Delete(i); //增加了这一句,因为上面循环使用的是 downto 所以可以直接删除!!!!
end;
finally
FActiveYarns.UnlockList;
end;
IndySleep(500); // Wait a bit before looping to prevent thrashing
end;
end;