Глава 5. Снова о разрушении потока. Тупик или зацикливание (Deadlock).
Содержание:
- Метод WaitFor.
- Контролируемое завершение потока - Подход 2.
- Введение в обработку сообщений и отложенное уведомление.
- WaitFor может вызвать долгую задержку.
- Вы заметили ошибку?
- Как избежать такого тупика.
Метод WaitFor.
OnTerminate, как обсуждалось в предыдущей части, полезно, если вы используете поток в режиме "выполнить и забыть", с автоматическим разрушением. Но что, если в некий момент выполнения главного потока VCL вы должны быть уверены, что все остальные потоки завершены? Решение состоит в использовании метода WaitFor, который пригодится в следующих случаях:
- Главному потоку VCL нужен доступ к объекту рабочего потока после его остановки для чтения или записи содержащихся в нем данных .
- Принудительное завершение потоков при закрытии программы неприемлемо.
Попросту говоря, когда поток А вызывает метод WaitFor потока B, сам он приостановливается, пока поток B не завершится. И когда поток А продолжит свое выполнение, можно быть уверенным, что результаты из потока B можно прочесть, и что объект потока B можно уничтожать. Обычно при завершении программы основной поток VCL вызывает Terminate всех вторичных потоков, и затем ожидает их завершения (WaitFor), после чего осуществляется выход из программы.
Контролируемое завершение потока - Подход 2.
В этом примере мы модифицируем код программы для простых чисел так, чтобы в каждый момент выполнялся только один поток, и программа перед выходом будет ждать завершения потока. Хотя в этой программе и не обязательно основному потоку ждать завершения других, но упражнение будет полезным и продемонстрирует несколько свойств WaitFor, которые не всегда желательны, а также проиллюстрирует пару довольно тонких моментов, которые могут быть упущены новичками в программировании потоков. Сначала код главной формы
Можно увидеть несколько отличий от предыдущего примера:
- В начале модуля объявлено "магическое число" . Это относительный номер сообщения, а значение его не важно, главное, чтобы оно было уникальным.
- Вместо счетчика потоков мы следим только за одним потоком, которому отвечает переменная FThread главной формы.
- Мы хотим, чтобы в каждый момент исполнялся только один поток, поскольку имеется единственная переменная, указывающая на рабочий поток. Поэтому код перед созданием потока проверяет, нет ли уже запущенных потоков.
- Код создания потока не устанавливает свойство FreeOnTerminate в True, вместо этого основной поток VCL будет освобождать рабочий поток позже.
- У главной формы есть обработчик сообщения, который ждет завершения рабочего потока, и затем разрушает его.
- Соответственно, код, исполняемый, когда пользователь хочет закрыть программу, ожидает завершения рабочего потока и освобождает его.
Учтите эти пункты, а здесь код рабочего потока
В нем тоже есть небольшие отличия от того, что было в Главе 3:
- Функция IsPrime теперь проверяет запросы на завершение потока, обеспечивая быстрый выход, если установлено свойство Terminated.
- Процедура Execute делает проверку на нештатное завершение.
- При нормальном завершении используется Synchronize для показа результатов и главной форме посылается сообщение - запрос на освобождение потока.
Введение в обработку сообщений и отложенное уведомление
При нормальном ходе дел поток выполняется, использует Synchronize для показа результатов, а затем посылает сообщение главной форме. Это сообщение асинхронно: главная форма получит его в некоторый момент чуть позже. PostMessage не приостанавливает рабочий поток, он продолжает свою работу до завершения. Это очень полезное свойство: мы не можем использовать Synchronize для того, чтобы сообщить главной форме, что пора освободить поток, потому что тогда мы бы "вернулись" из вызова Synchroni… Продолжение »