![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Загоны с таймером
Loginov Dmitry © (2008-07-02 23:50:00)Может кто сталкивался.
Не то, чтобы проблему нельзя было решить, но не понимаю, какого хр. она вообще возникает (либо не возникает)
Есть обработчик таймера. Для упрощения содержимое следующее:
procedure TMyForm.MyTimerTimer(Sender: TObject);
begin
ALog.LogStr('before MyTimerTimer');
MyTimer.Enabled := False;
Sleep(10); // реально здесь выполняется ряд "полезных" действий
ALog.LogStr('after MyTimerTimer');
end;
по умолчанию MyTimer.Enabled=False
MyTimer.Interval=50
В событии FormShow на ряду с прочими "полезными" действиями осуществляется вызов MyTimer.Enabled := True;
Собственно все. В логе при этом вижу следующее:
before MyTimerTimer
after MyTimerTimer
before MyTimerTimer
after MyTimerTimer
before MyTimerTimer
after MyTimerTimer
т.е. таймер вместо одного раза срабатывает 3 раза.
С этим столкнулся на работе. Дома ситуация не воспроизводится.
Компилю на Delphi2007 SP2 с пакетами.
Мое мнение насчет причины данной проблемы такое: В событии FormShow после вызова MyTimer.Enabled := True продолжается инициализация, вешающая основной поток некоторое время, в течение которого в очередь окна таймера успевает поступить 3 сообщения WM_TIMER, и установка MyTimer.Enabled=False не в силах повлиять на это. Однако пытаюсь эмулировать задержку в FormShow дома (Delphi7) - никаких проблем не возникает. Как ни бьюсь, OnTime вызывается только один раз. Завтра разбирусь с этим вопросом, однако может кто-нибудь с этим уже разбирался, где правда?
Loginov Dmitry (2008-07-05 09:04:00) [1]> Есть только мысль, что в DCOM все сообщения берутся из очереди,
> а потом возвращяются в нее без учета этой особенности.
Наверно так и есть. Ведь есть же костыль, когда в обработчике SendMessage(), вызванном из дополнительного потока (понято о чем речь? :)) нельзя вызывать функции DCOM (вернее, пока такой обработчик не отработает, вообще ниоткуда нельзя обращаться к DCOM). Так может и с таймером что-то из той же оперы.
GrayFace (2008-07-05 03:01:00) [2]Как я помню, сообщение WM_TIMER в нормальном случае в очередь не поступает, а передается оконной процедуре при выборке сообщений, если установлен флаг. (или я путаю с WM_PAINT?) Есть только мысль, что в DCOM все сообщения берутся из очереди, а потом возвращяются в нее без учета этой особенности.
Юрий Зотов © (03.07.08 11:43) [34]
Напиши обработчик по-человески и забудь о "глюках":
procedure TMyForm.MyTimerTimer(Sender: TObject);
begin
MyTimer.Enabled := False;
try
... // Здесь делай что угодно и сколько угодно, только не трогай таймер
finally
MyTimer.Enabled := True;
end;
end;
Почему это более "по-человечески"? Иногда лучше так, иногда по-простому. У меня, вроде, не было ситуации, когда такое полезно.
Игорь Шевченко (2008-07-03 23:31:00) [3]
> Если кому еще интересно:
запусти Spy++ или WinSignt и посмотри, какие сообщения каким окнам приходят, узнаешь много интересного.
Loginov Dmitry (2008-07-03 20:13:00) [4]Если кому еще интересно:
http://matrix.kladovka.net.ru/dcomandtimersrc.zip (39 Кб, исходники)
http://matrix.kladovka.net.ru/dcomandtimer.zip(546 Кб, исходники и EXE)
MsGuns (2008-07-03 18:43:00) [5]>Игорь Шевченко © (03.07.08 17:37) [57]
>Плохому учишь. Зря
Забыл добавить имху
Игорь Шевченко (2008-07-03 17:37:00) [6]MsGuns © (03.07.08 14:33) [55]
Плохому учишь. Зря
Юрий Зотов (2008-07-03 14:34:00) [7]Microsoft Windows CE 3.0 ?
http://msdn.microsoft.com/en-us/library/ms644901(VS.85).aspx
MsGuns (2008-07-03 14:33:00) [8]>Riply © (03.07.08 11:18) [30]
>"Разбирательство" помогает понять суть происходящего и не допускать
>обидных и досадных ляпов в будущем.
В тех случаях, когда оно (разбирательство) способствует решению проблемы и только. Иначе "лыжи на асфальте"
>Грош цена "ПРАКТИКУ", который, столкнувшись с непонятной ему вещью,
>путем шаманства (потому что не понял) убирает странный эфект и идет дальше.
Грош цена повару, который чтобы убедиться, что борщ пересолен (недосолен) не слопает весь котел
Loginov Dmitry (2008-07-03 14:16:00) [9]
> Плиз, уточни интерпретируемую статью.
http://msdn.microsoft.com/en-us/library/ms927685.aspx
Leonid Troyanovsky (2008-07-03 14:01:00) [10]
> Loginov Dmitry © (03.07.08 12:15) [43]
> для того же самого таймера в очередь не заносятся, пока
> не будет обработано первое сообщение WM_TIMER. Или я неверно
> интерпретирую MSDN?
Плиз, уточни интерпретируемую статью.
AFAIK, окну не передаются WM_TIMER, WM_PAINT, WM_QUIT,
_до тех пор_, пока не будут обработаны более приоритетные сообщения.
Про WM_PAINT известно, что несколько из присутствующих
в очереди объединяют. А вот про выбрасывание из очереди
experied WM_TIMER я чего-то не припомню.
--
Regards, LVT.
Loginov Dmitry (2008-07-03 13:53:00) [11]
> Отправил пример на adm@delphimaster.ru
Не знаю, дошло ли оно. На всякий случай выслал еще одно с паролем.
Anatoly Podgoretsky (2008-07-03 13:48:00) [12]
> McSimm © (03.07.08 13:38) [48]
А нет ли там потоков случайно, прямо или косвенно.
Loginov Dmitry (2008-07-03 13:47:00) [13]
> Но разобраться хотелось бы. У меня всегда всякое необъясненное
> чешется
Отправил пример на adm@delphimaster.ru
Loginov Dmitry (2008-07-03 13:42:00) [14]Мне удалось сделать минимальное приложение без единой кнопки, в котором данная проблема отлично воспроизводится. Ошибка действительно из-за DCOM.
Если кому хочется проверить, могу скинуть на мыло.
McSimm (2008-07-03 13:38:00) [15]Мне кажется, что в таком случае лог был бы другим.
Там есть временные отметки есть - практически одномоментно выполняются два десятка сообщений.
Кроме того, мне кажется, что последовательность записей в логе была бы иной, т.е. сначала 20 Before а потом 20 After.
А тут мы видим, что после After (т.е. таймер уже деактивирован) еще куча обработок происходит, при этом таймер по приведенному коду повторно не активируется. Да и нет задержки 50 мс, даже если где-то активируется в неприведенном коде.
В общем, мне лично трудно увязать приведенный лог с моим представлением о работе таймера, разумеется, я понимаю, что это ничего не означает.
Но разобраться хотелось бы. У меня всегда всякое необъясненное чешется :)
Юрий Зотов (2008-07-03 13:26:00) [16]> McSimm © (03.07.08 12:54) [46]
В логе написано, что обработчик OnTimer был вызван N раз подряд. Больше в логе не написано ничего.
Но N идущих подряд вызовов обработчика OnTimer НЕ означают, что в очереди одновременно присутствовало несколько сообщений WM_TIMER.
1. В очередь поступает сообщение WM_TIMER.
2. Оно выбирается и удаляется из очереди (и с этого мгновения ничто не мешает приходу в очередь нового сообщения WM_TIMER).
3. Вызывается обработчик события OnTimer (а в очереди, возможно, уже есть новое сообщение WM_TIMER, либо оно может поступить туда во время выполнения кода обработчика).
4. В обработчике события пишется лог.
Как видим, эта последовательность действительно может повторяться. И в логе действительно будет написано, что обработчик события OnTimer сработал N раз подряд - что вовсе не означает накопления сообщений в очереди WM_TIMER.
McSimm (2008-07-03 12:54:00) [17]
> Еще раз: в очереди его уже нет. Раз сработал обработчик
> OnTimer (а он сработал), то вызвавшее его сообщение WM_TIMER
> из очереди уже удалено.
>
Юрий, он имеено так и сказал:
> > Именно этого сообщения в очереди нет. Но есть другие (вопреки
> MSDN)
И судя по логам (я не склонен расценивать всю это ветку как мистификацию), очень похоже, что так и происходит - на момент обработки одного сообщения в очереди есть также и другие 19 штук. Что, если я не ошибаюсь, действительно противоречит MSDN
Юрий Зотов (2008-07-03 12:42:00) [18]> Loginov Dmitry © (03.07.08 12:15) [43]
> если для данного таймера уже есть сообщение WM_TIMER в очереди, то...
Еще раз: в очереди его уже нет. Раз сработал обработчик OnTimer (а он сработал), то вызвавшее его сообщение WM_TIMER из очереди уже удалено.
McSimm (2008-07-03 12:19:00) [19]
> пока не будет обработано первое сообщение WM_TIMER
да, с маленьким уточнением термина "обработано" - в контексте события OnTimer - оно уже обработано при входе в событие.
Впрочем, я не вижу, чтобы это относилось к данному случаю
Loginov Dmitry (2008-07-03 12:15:00) [20]в соответствии с MSDN: если для данного таймера уже есть сообщение WM_TIMER в очереди, то новые сообщения WM_TIMER для того же самоготаймера в очередь не заносятся, пока не будет обработано первое сообщение WM_TIMER. Или я неверно интерпретирую MSDN?