2010-07-22 3 views
18

У меня есть TTimer в моем приложении, который срабатывает каждые 2 секунды и вызывает мой обработчик событий HandleTimerEvent(). Функция HandleTimerEvent() изменяет общие ресурсы и может занять 10 секунд для выполнения перед возвратом. Кроме того, я вызываю Sleep() в обработчике событий, чтобы время от времени отказываться от процессора.Является ли обработчик события TTimer.OnTimer реентерабельным?

Я не уверен, как работает объект TTimer строителя C++, когда дело доходит до вызова событий, поэтому сценарий, который я только что объяснил, заставил меня думать, в частности, вызывает ли HandleTimerEvent() до того, как предыдущий вызов вернулся.

Вопрос сводится к нескольким вещам.

Включает ли объект TTimer события?

Может ли объект TTimer вызвать мой обработчик событий до того, как был возвращен предыдущий вызов?

ответ

31

Этот ответ предполагает, что TTimer все еще используется для использования сообщений WM_Timer. Если реализация изменилась (с 2005 года), пожалуйста, не обращайте внимания.

Нет, объект TTimer не помещает в очередь события. Это обусловлено сообщением Windows WM_Timer, и Windows не позволяет сообщениям WM_TIMER складываться в очереди сообщений. Если следующий интервал таймера происходит, и Windows видит, что сообщение WM_Timer уже находится в очереди сообщений приложения, оно не добавляет в очередь еще одну mess_age WM_Timer. (То же самое для WM_Paint, btw)

Да, возможно, что событие TTimer.OnTimer будет запущено, даже если предыдущий обработчик событий все еще выполняется. Если вы делаете что-либо в своем обработчике событий, что позволяет приложению обрабатывать сообщения, ваше событие таймера может быть повторно введено. Очевидным является то, что обработчик событий вызывает Application.ProcessMessages, но он может быть намного более тонким, чем это - если что-либо, что вы вызываете в обработчике событий, внутренне вызывает Application.ProcessMessages или вызывает PeekMessage/GetMessage + DispatchMessage или открывает модальный диалог , или вызывает COM-интерфейс, привязанный к COM-объекту вне процесса, тогда сообщения в очереди сообщений вашего приложения будут обработаны и могут включать в себя следующее сообщение WM_Timer.

Простым решением является отключение объекта таймера при вводе обработчика события таймера и его повторное включение при выходе из обработчика событий таймера. Это предотвратит запуск сообщений таймера во время работы вашего обработчика событий, независимо от характеристик обработки сообщений вашего кода.

+10

+1 для отключения таймера. Чтобы продемонстрировать эффективность отключения таймера (или простое демонстрацию того, что может пойти не так, если вы этого не сделаете), покажите сообщение в обработчике таймера. Если вы не отключите таймер при входе, будут помещены сообщения. –

+2

Вы также можете использовать булевский флаг для предотвращения повторного размещения в обработчике событий таймера, но отключение самого таймера намного проще. – dthorpe

+0

См. Https://forums.embarcadero.com/thread.jspa?messageID=171751𩻧 для полезного класса TTimerGuard, класса RAII-типа для использования TTimer. Может потребоваться настроить использование FInterval в зависимости от вашей реализации. –

2

Я использую TTimer экстенсивно. Он не ставит в очередь события. Если вы хотите, чтобы он передал обработчик события, создайте TThread, который обрабатывает ваши события, чтобы таймер мог продолжить работу. Таймер не работает асинхронно, а скорее синхронно.

Смежные вопросы