From 3a5dced17c681587d1653b1d79e4d567e4dee844 Mon Sep 17 00:00:00 2001 From: Uladzimir Karpenka Date: Thu, 20 Aug 2026 16:06:53 +0300 Subject: [PATCH] =?UTF-8?q?fix(tci):=20=D1=81=D1=87=D1=91=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D1=81=D0=BA?= =?UTF-8?q?=D0=B8=D1=85=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BA=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B6=D0=B8=D0=B2=D0=B0=D0=BB=20=D0=BD?= =?UTF-8?q?=D0=B5=D1=83=D0=B4=D0=B0=D1=87=D0=BD=D1=8B=D0=B9=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D1=80=D1=82=20=E2=80=94=20Stop=20=D0=B2=D0=B8=D1=81?= =?UTF-8?q?=D0=B5=D0=BB=20=D0=B2=D0=B5=D1=87=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AcceptLoop делал InterLockedIncrement(FThreadCount) и следом создавал поток безо всякой защиты. Не родился поток (память, лимит потоков в системе) — исключение уходило из AcceptLoop и TTCIAcceptThread.Execute, accept-поток умирал при FRunning = True, а счётчик оставался ≥ 1 навсегда. Ждут его на шаге 4 TTCIServer.Stop БЕЗ таймаута (и намеренно: следом освобождаются и клиенты, и сам сервер), так что программа зависала и на выходе, и на любой смене настроек TCI. Инкремент остался до старта — переносить его после Start нельзя, там гонка с ThreadDone уходящего потока. Спавн обёрнут в try/except: счётчик возвращается назад, сокет гасится Kill, клиент метится FClosed и достаётся тик-потоку (ReapClients), как при обычном отключении. Объект потока уносит себя сам — упавший конструктор сразу, поднявшийся по FreeOnTerminate. Co-Authored-By: Claude Opus 5 --- TCIServer.pas | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/TCIServer.pas b/TCIServer.pas index c639b7c..e6bb7f6 100644 --- a/TCIServer.pas +++ b/TCIServer.pas @@ -1009,9 +1009,23 @@ begin Continue; end; + // Счётчик — ДО старта: иначе Stop успел бы проскочить шаг 4 между Start и + // первой строкой потока. ★А не родился поток (память, лимит потоков) — + // сразу возвращаем счётчик назад: ждут его на шаге 4 без таймаута, и + // лишняя единица подвешивала бы и выход из программы, и любую смену + // настроек TCI. Объект потока уносит себя сам: упавший конструктор — сразу, + // а поднявшийся — по FreeOnTerminate. InterLockedIncrement(FThreadCount); - T := TTCIClientThread.Create(Self, Client); - T.Start; + try + T := TTCIClientThread.Create(Self, Client); + T.Start; + except + InterLockedDecrement(FThreadCount); + // Обслуживать клиента больше некому: гасим сокет и метим на освобождение + // — заберёт тик-поток (ReapClients), как и обычное отключение. + Client.Kill; + Client.FClosed := True; + end; end; end;