![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Использование TTimer
JaoDa © (2005-02-18 13:51:00)Копался в чужом коде и обнаружил такую строку:
TForm1.Timer1Timer(Sender: TObject);
begin
длительный процесс, превышающий время установленного интервала
end;
Обычно сам всегда делаю так:
TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled:=false;
длительный процесс, превышающий время установленного интервала
Timer1.Enabled:=true;
end;
Как правильно? не ведет ли первый способ к множественной попытке выполнения одних и тех же вычислений?
Alexander Panov (2005-02-18 19:23:00) [1]XP (18.02.05 19:05) [33]
Абсолютно согласен.
Спасибо за развернутый анализ.
XP (2005-02-18 19:05:00) [2]2 Alexander Panov
Пожалуйста. :)
Теперь надо разобраться, что же происходит, когда в обработчике появляется ProcessMessage
А происходит следующее.
В случае, когда в обработчике события от таймера нет вызова ProcessMessages, и даже если время обработки события многократнопревышает интервал таймера, в очереди все равно хранится только односообщение.
После выхода из метода обработки события из очереди извлекается это сообщение, и снова вызывается метод обработки события таймера.
К слову, так как приоритет событий от таймера невысокий, то за этот период успевают обработаться практически все события, имеющиеся в очереди. Хотя, с приоритетом я могу путать. Но это к слову.
Таким образом, имеем метод обработки события таймера, после выхода из которого гарантированно иммеем в очереди сообщение от таймера.
Теперь рассмотрим вызов ProcessMessages внутри метода обработки события таймера.
Вызов ProcessMessages безусловный. По крайней мере, мы сейчас рассматриваем именно этот случай.
При вызове ProcessMessages происходит извлечение сообщения от таймера, и, как следствие - повторный вызов метода обработки события таймера.
При этом, и я на этом акцентирую внимание, происходит удаление сообщения от таймера из очереди. А при одном из очередных вызовов ProcessMessages, когда наступит время, нас опять будет ждать новое сообщение от таймера. Если бы мы не вызывали ProcessMessages, то имели бы в очереди одно единственное сообщение от таймера. А так - мы его обрабатываем, удаляем, а оно появляется вновь и вновь.
Так что же это за "повторный вызов метода обработки событий таймера"? Я подозреваю (а я очень в таких делах подозрителен), что это случай обыкновенной, хотя и завуалированной, рекурсии. Причем, рекурсии безусловной(так как ProcessMessages вызывается безусловно).
При коротком интервале срабатывания таймера и длительной обработке его сообщения - имеем постоянный вложенный вызов метода таймера. И, как следствие - медленное (хотя кто сказал, что медленное?) заполнение стека вплоть до его переполнения.
Да, в большинстве случаев метод обработки события успевает завершится до переполнения стека. Но при этом уже имеем несколько вложенных вызовов этого же метода. Короче, получаются "танцы в стеке": сто шагов вперед, один назад.
Переполнение наступит все равно.
Резюмируя сказанное:
Во избежание переполнения стека, ProcessMessages внутри метода обработки события от таймера вызывать не следует. Даже если длительность выполнения метода значительно меньше интервала срабатывания таймера, не исключена ситуация, когда получим "наложение". Какая ситуация? Да любая! Длительность выполнения метода зависит от быстродействия процессора, приоритета основного потока приложения, занятости процессора и многого другого. В то время, как интервал срабатывания таймера остается (с некоторой натяжкой) постоянным. Вот вам и повод переполнить стек.
Все же, MS не зря сделал эту самую "consolidation" сообщений от таймера. Ибо, в противном случае могут быть проблемы с переполнением очереди сообщений, стеком и пр.
С уважением...
Alexander Panov (2005-02-18 18:23:00) [3]XP (18.02.05 18:17) [31]
Во!
Теперь то, что нужно-)
Спасибо за инфу!
Теперь надо разобраться, что же происходит, когда в обработчике появляется ProcessMessage...
XP (2005-02-18 18:17:00) [4]Вот, нашел все-таки. :)
http://support.microsoft.com/default.aspx?scid=kb;en-us;78599
Timer event processing will not be interrupted by new timer events. This is because of the way that Windows notifies an application that a timer event has occurred. Instead of interrupting the application, Windows places a WM_TIMER message in its message queue. If there is already a WM_TIMER message in the queue from the same timer, the new message will be consolidatedwith the old one.
After the application has completed processing the current timer event, it checks its message queue for any new messages. This queue may have new WM_TIMER messages to process. There is no way to tell if any WM_TIMER messages have been consolidated.
XP (2005-02-18 18:06:00) [5]2 Alexander Panov
Ага. Я тоже поэкспериментирую.
Хотя, я уже давно экспериментировал, и обнаружил, что сообщения от таймера в очереди не накапливаются.
Исчерпывающей документации по WM_TIMER я не нашел, и есть несколько "но".
Одно из них - из Help'а:
The KillTimer function does not remove WM_TIMER message salready posted to the message queue.
И это "но" говорит о том, что сообщения должны вроде бы как накапливаться. Но... не накапливаются. Что, в свою очередь, говорит о том, что в очередь дублирующие сообщения просто не добавляются.
Это практические наблюдения над поведением Windows Timer.
Именно это дает мне основание утверждать, что, если обработка события таймера по длительности превышает интервал срабатывания таймера, то никаких побочных эффектов (кроме увеличения интервала между вызовами метода обработки события) не наблюдается.
То-есть, никакого переполнения очереди, памяти, стека и прочих "чувствительных" к переполнению объектов.
P.S. А насчет недобавления повторного сообщения от таймера в очередь - так я это еще во времена Windows 3.1 слыхал. Правда, не помню от кого...
Alexander Panov (2005-02-18 16:43:00) [6]XP (18.02.05 15:41) [25]
Чуток поэкспериментирую, результат доложу-)
BlackTr (2005-02-18 16:34:00) [7]А об этом не спрашивали :)
Digitman (2005-02-18 16:28:00) [8]
> BlackTr (18.02.05 15:37) [24]
ой-ой..
а если "ждущий" трэд не есть осн.трэд ?
Sandman25 (2005-02-18 15:45:00) [9][20] BlackTr (18.02.05 15:13)
Спасибо
XP (2005-02-18 15:41:00) [10]Оно придет ровно по истечении интервала, заданного в TTimer.(плюс-минус, естественно). Вот когда оно из очереди будет выбрано - другой вопросНо то, что будет выбрано - можешь быть уверен.
Timer.Interval := 100;
Timer1.Enabled := TRUE;
Sleep(5000);
Timer1.Enabled := FALSE;
В обработчике события таймера напишите что угодно, ну, хотя бы увеличивайте значение некоей переменной, и посмотрите, сколько раз оно выполнится.
BlackTr (2005-02-18 15:37:00) [11]
> Оно придет ровно по истечении интервала, заданного в TTimer.(плюс-минус,
> естественно).
Во время обработчика Timer1Timer оно не придет никогда, если только не ипользовать умную конструкцию Application.ProcessMessages. :))
Которая сама вызывает выборку сообщений из очереди...
Alexander Panov (2005-02-18 15:17:00) [12]BlackTr (18.02.05 15:15) [22]
Оно придет когда ты выйдешь из обработчика Timer1Timer,
Оно придет ровно по истечении интервала, заданного в TTimer.(плюс-минус, естественно).
Вот когда оно из очереди будет выбрано - другой вопрос. Но то, что будет выбрано - можешь быть уверен.
BlackTr (2005-02-18 15:15:00) [13]
> Ну значит, еще увеличь время работы for.
> Смысл в том, что через некоторое время следующее сообщение
> из очереди сообщений все равно будет выбрано и обработано.
Оно придет когда ты выйдешь из обработчика Timer1Timer, увеличивай время работы for на скоко хош...
Alexander Panov (2005-02-18 15:13:00) [14]Digitman © (18.02.05 15:12) [18]
Так это не автору. XP привел цитату из SDK. Это ему был экивок.
BlackTr (2005-02-18 15:13:00) [15][10]
> Если я не выключу таймер в начале обработки, следующая обработка
> начнется через 4 секунды после начала предыдущей обработки.
> А если выключу, то через 5 секунд после начала предыдущей
> обработки. Так?
Ага
Digitman (2005-02-18 15:12:00) [16]
> Alexander Panov © (18.02.05 15:02) [15]
ой ну ты в дебри полез) .. с эти WM_TIMER и его приоритетом ..
а завтра у автора вожжа под хвост с неким WM_ХРЕНАЙВЕР - тоже про "приоритеты" разглагольствовать будем с ним ?...
Alexander Panov (2005-02-18 15:12:00) [17]BlackTr (18.02.05 15:09) [16]
и если это не случилось за достаточно короткий промежуток времени, это не значит, что этого не произойдет никогда.
Alexander Panov (2005-02-18 15:11:00) [18]BlackTr (18.02.05 15:09) [16]
Че-то не появилось. :))))
Ну значит, еще увеличь время работы for.
Смысл в том, что через некоторое время следующее сообщение из очереди сообщений все равно будет выбрано и обработано.
BlackTr (2005-02-18 15:09:00) [19]
> for i := 0 to 500 do на for i := 0 to 5000000 do(Допустим)
> и убрать ProcessMessage, то в очереди сообщений за время
> работы for может появиться(и появится)
Че-то не появилось. :))))
Alexander Panov (2005-02-18 15:02:00) [20]XP (18.02.05 14:57) [13]
Remarks
The DispatchMessage function forwards this message when no other messages are in the thread's message queue.
WM_TIMER + F1
Речь идет всего лишь о том, что сообщение таймера имеет более низкий приоритет перед друними сообщениями, и не более того.
Еще есть какая-либо информация?