Мое приложение - это tcp / ip-сервер, основной поток которого создается только один раз и постоянно прослушивает. Когда подключается новый клиент, основной поток создает новый поток типа TClientThread
. Однако нет списка запущенных клиентских потоков, так как это сделало бы мое приложение немного сложным ... есть ли способ выполнить метод "terminate" для всех потоков, даже если поток занят (в моем случае "занят" означает, что он ждет данных, где установлен тайм-аут около 30 секунд ... так что мне все равно придется убить его, не дожидаясь.)? Простое приложение закрытия, похоже, не запускает метод "terminate" в потоках, что приводит к утечкам памяти, о которых сообщает FastMM ...
delphi - завершить все потоки (TThread) при закрытии приложения
Ответы (3)
Утечки памяти при завершении работы - не о чем беспокоиться - проблема с освобождением памяти перед возвратом управления операционной системе является пустой тратой времени и излишне замедляет выход из приложения. Все, что вам действительно нужно сделать, это убедиться, что все данные были сохранены, и все межпроцессорные дескрипторы (такие как семафоры и мьютексы) правильно освобождены, и выйти.
Лучшее, что вы можете сделать для уведомления клиентов, - это примерно такая стратегия:
- Добавьте где-нибудь все потоки обработки клиентов в какой-нибудь список (с подходящей блокировкой при создании, уничтожении и итерации)
- Сделайте так, чтобы клиентские потоки удалялись из списка при завершении, а последний элемент, удаленный из списка, устанавливал событие (событие ручного сброса, например,
TEvent
в SyncObjs), если сервер завершает работу. - Ввести опрос (например,
select
или эквивалент с тайм-аутом) или другой вид прерывания (например, SO_RCVTIMEO / SO_SNDTIMEO) в том, что в противном случае было бы долго выполняющимися подпрограммами блокировки, отслеживая свойство Terminated - При завершении работы заблокируйте список и выполните итерацию по нему, вызвав
Terminate
, а затем дождитесь сигнала события; конечно, прослушивающий сокет, который добавляет элементы в список, должен быть закрыт и заведомо закрытым до итерации по списку.
Похоже, эта статья может помочь
Что вы увидите, если перейдете по этой ссылке:
Использование семафоров в Delphi, часть 2: Пул соединений
Автор: Кэри Дженсен
Аннотация: Семафоры используются для координации нескольких потоков и процессов. То, что семафоры обеспечивают несколько потоков с одновременным доступом к общему ресурсу, выделено классом TFixedConnectionPool, описанным в этой статье.
Я использую глобальный KillThreadList: TList. Я отслеживаю это в своей ветке как:
while (Not Terminated) do
begin
inc(Inker);
if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
Begin
if Inker >= 10 then
Begin
ProcessTables;
Inker := 0;
sleep(1000);
End;
if KillThreadList.Contains(ThreadID) = True then Terminate;
End;
end;
Я также проверяю KillThreadList в своих процессах, чтобы я мог отказаться от них до завершения, где это безопасно.
Я передаю событие OnTerminate в основной поток и удаляю ThreadID из списка KillList. Я активно использую эту модель, и она меня еще не подвела.
procedure TfrmProcessQualcommLocations.OnTerminateThread;
var
ThreadID : Cardinal;
i : integer;
aStatusBar :TStatFrame;
begin
ThreadID := (Sender as Tthread).ThreadID;
for i := 0 to StatusBarList.Count -1 do
Begin
if StatusBarList.Items[i].ThreadID = ThreadID then
Begin
aStatusBar := StatusBarList.Items[i];
KillThreadList.Extract(ThreadID);
StatusBarList.Extract(aStatusBar);
aStatusBar.Free;
break;
End;
End;
self.Refresh;
end;
В приведенном выше случае я также удаляю некоторые элементы графического интерфейса.
Надеюсь, это поможет. SpringerRider