mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Fix CAT TCP server Stop: eliminate up-to-5s hang on shutdown
PurgeLoop used Sleep(5000) — Stop had to wait up to 5 seconds for the purge thread to wake before it could proceed. Fix: add TEvent FStopEvent; Stop signals it before waiting on threads so PurgeLoop exits immediately. Also moved client Disconnect calls before WaitFor so all sockets are unblocked in parallel rather than sequentially. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -75,6 +75,7 @@ type
|
|||||||
FRunning: Boolean;
|
FRunning: Boolean;
|
||||||
FSendWelcome: Boolean;
|
FSendWelcome: Boolean;
|
||||||
FLastError: string;
|
FLastError: string;
|
||||||
|
FStopEvent: TEvent;
|
||||||
|
|
||||||
procedure ServerLoop;
|
procedure ServerLoop;
|
||||||
procedure PurgeLoop;
|
procedure PurgeLoop;
|
||||||
@@ -291,6 +292,7 @@ begin
|
|||||||
FListenSock := SOCK_INVALID;
|
FListenSock := SOCK_INVALID;
|
||||||
FClients := TList.Create;
|
FClients := TList.Create;
|
||||||
FClientsLock := TCriticalSection.Create;
|
FClientsLock := TCriticalSection.Create;
|
||||||
|
FStopEvent := TEvent.Create(nil, True, False, '');
|
||||||
FRunning := False;
|
FRunning := False;
|
||||||
FSendWelcome := True;
|
FSendWelcome := True;
|
||||||
FLastError := '';
|
FLastError := '';
|
||||||
@@ -304,6 +306,7 @@ begin
|
|||||||
Stop;
|
Stop;
|
||||||
FClients.Free;
|
FClients.Free;
|
||||||
FClientsLock.Free;
|
FClientsLock.Free;
|
||||||
|
FStopEvent.Free;
|
||||||
{$IFDEF MSWINDOWS}
|
{$IFDEF MSWINDOWS}
|
||||||
WSACleanup;
|
WSACleanup;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@@ -376,12 +379,23 @@ begin
|
|||||||
if not FRunning then Exit;
|
if not FRunning then Exit;
|
||||||
FRunning := False;
|
FRunning := False;
|
||||||
|
|
||||||
|
// Будим PurgeLoop немедленно, чтобы он не ждал 5 секунд
|
||||||
|
FStopEvent.SetEvent;
|
||||||
|
|
||||||
|
// Закрываем listen socket — разблокирует fpAccept в ServerLoop
|
||||||
if FListenSock <> SOCK_INVALID then begin
|
if FListenSock <> SOCK_INVALID then begin
|
||||||
SockShutdown(FListenSock);
|
SockShutdown(FListenSock);
|
||||||
SockClose(FListenSock);
|
SockClose(FListenSock);
|
||||||
FListenSock := SOCK_INVALID;
|
FListenSock := SOCK_INVALID;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Разрываем всех клиентов до ожидания потоков
|
||||||
|
FClientsLock.Acquire;
|
||||||
|
try
|
||||||
|
for i := 0 to FClients.Count-1 do
|
||||||
|
TCATTcpClientThread(FClients[i]).Disconnect;
|
||||||
|
finally FClientsLock.Release; end;
|
||||||
|
|
||||||
if Assigned(FServerThread) then begin
|
if Assigned(FServerThread) then begin
|
||||||
FServerThread.Terminate;
|
FServerThread.Terminate;
|
||||||
FServerThread.WaitFor;
|
FServerThread.WaitFor;
|
||||||
@@ -393,16 +407,18 @@ begin
|
|||||||
FreeAndNil(FPurgeThread);
|
FreeAndNil(FPurgeThread);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Теперь безопасно ждём завершения клиентских потоков и освобождаем
|
||||||
FClientsLock.Acquire;
|
FClientsLock.Acquire;
|
||||||
try
|
try
|
||||||
for i := 0 to FClients.Count-1 do begin
|
for i := 0 to FClients.Count-1 do begin
|
||||||
cli := TCATTcpClientThread(FClients[i]);
|
cli := TCATTcpClientThread(FClients[i]);
|
||||||
cli.Disconnect;
|
|
||||||
cli.WaitFor;
|
cli.WaitFor;
|
||||||
cli.Free;
|
cli.Free;
|
||||||
end;
|
end;
|
||||||
FClients.Clear;
|
FClients.Clear;
|
||||||
finally FClientsLock.Release; end;
|
finally FClientsLock.Release; end;
|
||||||
|
|
||||||
|
FStopEvent.ResetEvent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCATTcpServer.ServerLoop;
|
procedure TCATTcpServer.ServerLoop;
|
||||||
@@ -440,7 +456,7 @@ begin
|
|||||||
del := TList.Create;
|
del := TList.Create;
|
||||||
try
|
try
|
||||||
while FRunning do begin
|
while FRunning do begin
|
||||||
Sleep(5000);
|
if FStopEvent.WaitFor(5000) <> wrTimeout then Break;
|
||||||
del.Clear;
|
del.Clear;
|
||||||
FClientsLock.Acquire;
|
FClientsLock.Acquire;
|
||||||
try
|
try
|
||||||
|
|||||||
Reference in New Issue
Block a user