delphi - завершить все потоки (TThread) при закрытии приложения

Мое приложение - это tcp / ip-сервер, основной поток которого создается только один раз и постоянно прослушивает. Когда подключается новый клиент, основной поток создает новый поток типа TClientThread. Однако нет списка запущенных клиентских потоков, так как это сделало бы мое приложение немного сложным ... есть ли способ выполнить метод "terminate" для всех потоков, даже если поток занят (в моем случае "занят" означает, что он ждет данных, где установлен тайм-аут около 30 секунд ... так что мне все равно придется убить его, не дожидаясь.)? Простое приложение закрытия, похоже, не запускает метод "terminate" в потоках, что приводит к утечкам памяти, о которых сообщает FastMM ...


person migajek    schedule 29.07.2009    source источник


Ответы (3)


Утечки памяти при завершении работы - не о чем беспокоиться - проблема с освобождением памяти перед возвратом управления операционной системе является пустой тратой времени и излишне замедляет выход из приложения. Все, что вам действительно нужно сделать, это убедиться, что все данные были сохранены, и все межпроцессорные дескрипторы (такие как семафоры и мьютексы) правильно освобождены, и выйти.

Лучшее, что вы можете сделать для уведомления клиентов, - это примерно такая стратегия:

  • Добавьте где-нибудь все потоки обработки клиентов в какой-нибудь список (с подходящей блокировкой при создании, уничтожении и итерации)
  • Сделайте так, чтобы клиентские потоки удалялись из списка при завершении, а последний элемент, удаленный из списка, устанавливал событие (событие ручного сброса, например, TEvent в SyncObjs), если сервер завершает работу.
  • Ввести опрос (например, select или эквивалент с тайм-аутом) или другой вид прерывания (например, SO_RCVTIMEO / SO_SNDTIMEO) в том, что в противном случае было бы долго выполняющимися подпрограммами блокировки, отслеживая свойство Terminated
  • При завершении работы заблокируйте список и выполните итерацию по нему, вызвав Terminate, а затем дождитесь сигнала события; конечно, прослушивающий сокет, который добавляет элементы в список, должен быть закрыт и заведомо закрытым до итерации по списку.
person Barry Kelly    schedule 29.07.2009
comment
ну, на самом деле поток должен быть правильно завершен, чтобы приложение знало, что его состояние клиента отключено ... так что мне все равно нужно знать, как это сделать! - person migajek; 30.07.2009
comment
Утечки памяти при завершении работы - не о чем беспокоиться: возможно, поэтому я получаю катастрофический сбой почти каждый раз, когда выключаю Delphi IDE. - person Tihauan; 30.07.2009
comment
Тихауан - при выгрузке пакетов это другое дело, например, пакеты могут многократно загружаться и выгружаться. Что касается того, почему IDE дает сбой при выключении, я не могу рассуждать без дополнительных данных. - person Barry Kelly; 30.07.2009
comment
Утечки памяти при выключении - это повод для беспокойства. Это своего рода сигнал о том, что в вашем коде могут быть проблемы. Вы не можете игнорировать их, НО, если вы знаете, почему и когда происходят эти утечки и что они не опасны, вы можете принять их. - person Tom Hagen; 28.03.2012

Похоже, эта статья может помочь

Что вы увидите, если перейдете по этой ссылке:

Использование семафоров в Delphi, часть 2: Пул соединений

Автор: Кэри Дженсен

Аннотация: Семафоры используются для координации нескольких потоков и процессов. То, что семафоры обеспечивают несколько потоков с одновременным доступом к общему ресурсу, выделено классом TFixedConnectionPool, описанным в этой статье.

person Community    schedule 29.07.2009
comment
Семафоры представляют собой конструкцию синхронизации и имеют мало общего с проблемой OP (завершение потоков при завершении работы). - person jpfollenius; 30.07.2009

Я использую глобальный 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

person Meta Mussel    schedule 18.12.2013
comment
= Правда это круто! - person Nashev; 17.10.2019