delphi - завершать все потоки (TThread) при закрытии приложения - PullRequest
4 голосов
/ 30 июля 2009

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

Ответы [ 3 ]

16 голосов
/ 30 июля 2009

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

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

  • Добавить все потоки обработки клиента в некоторый список где-нибудь (с подходящей блокировкой при создании, уничтожении и итерации)
  • Заставить клиентские потоки удалить себя из списка после завершения, а последнему удаленному элементу из списка установить событие (событие ручного сброса, например, TEvent в SyncObjs), если сервер завершает работу
  • Ввести опрос (например, select или эквивалентный с тайм-аутом) или другой вид прерывания (например, SO_RCVTIMEO / SO_SNDTIMEO) в том, что в противном случае было бы долго выполняющимися процедурами блокировки, отслеживая свойство Termination
  • При завершении работы заблокируйте список и выполните итерацию по нему, вызывая Terminate, а затем дождитесь, когда событие будет сигнализировано; конечно, сокет прослушивания, который добавляет элементы в список, должен быть закрыт и, как известно, должен быть закрыт до итерации по списку
2 голосов
/ 19 декабря 2013

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

2 голосов
/ 30 июля 2009

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...