Является ли обработчик событий TTimer.OnTimer реентерабельным? - PullRequest
18 голосов
/ 22 июля 2010

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

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

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

Поставляет ли объект TTimer в очередь события?

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

Ответы [ 2 ]

32 голосов
/ 22 июля 2010

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

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

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

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

2 голосов
/ 22 июля 2010

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

...