Как TTimer на самом деле работает внутри?

TTimer с интервалом, установленным в 1 секунду, отправляет сообщение каждую 1 секунду. Это сообщение обрабатывается в цикле сообщений приложения, в результате чего вызывается событие OnTimer.
Если приложение занято и не успевает обработать цикл сообщений, событие OnTimer пропускается.

Я знал, что TTimer использует внутри SetTimer.

Мои вопросы:

  1. Использует ли TTimer внутренний / отдельный поток (через SetTimer)?
  2. Почему форма, которая содержит таймер (и даже его OnTimer), все еще может делать вещи, если модальный MessageDlg "блокирует" форму? (см код ниже)
  3. В документации сказано, что SetTimer требует минимум Win2000. Как был реализован TTimer в Win98?

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
 Caption = i;
 i++;
 MessageDlg(stuff);      <----- we "block" application here but form's caption is still updated.
}

2 ответа

Решение

Сообщения WM_TIMER никогда не помещаются в очередь сообщений. Они генерируются, когда очередь пуста и установлен флаг, указывающий, что таймер истек. Таким образом, в очереди не может быть более одного сообщения WM_TIMER за раз, и если ваше приложение слишком загружено для обработки очереди, вы не получите много сообщений WM_TIMER, ожидающих обработки.

Сообщения WM_PAINT работают так же.

Если приложение занято и не успевает обработать цикл сообщений, событие OnTimer пропускается.

Это эффективно правильно. В этом и этом постах блога на MSDN приводятся некоторые подробности внутренней реализации, в частности, упоминается, что истекающий таймер вызывает QS_TIMER флаг состояния очереди сообщений для установки. Никакой дальнейший промежуток времени не заставит флаг состояния очереди быть установленным еще больше. Когда этот флаг установлен и [Peek|Get]Message не может выбрать сообщение с более высоким приоритетом, генерируется сообщение таймера.

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

Использует ли TTimer внутренний / отдельный поток (через SetTimer)?

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

Почему форма, которая содержит таймер (и даже его OnTimer), все еще может делать вещи, если модальный MessageDlg "блокирует" форму?

Модальный цикл продолжает обрабатывать очередь, он вызывает HandleMessage Приложения в цикле, который вызывает ProcessMessage, Следовательно сообщения таймера все еще обрабатываются.

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

В документации сказано, что SetTimer требует минимум Win2000. Как был реализован TTimer в Win98

Так же. Документация постоянно меняется, иногда MSDN отбрасывает неподдерживаемые версии ОС из минимальных требований - довольно непоследовательно. Моя документация по API XE2 гласит:

Минимальные операционные системы Windows 95, Windows NT 3.1

для WM_TIMER сообщение.

Другие вопросы по тегам