2010-07-22 10 views
18

Mam TTimer w mojej aplikacji, który uruchamia się co 2 sekundy i wywołuje moją obsługę zdarzenia, HandleTimerEvent(). Funkcja HandleTimerEvent() modyfikuje udostępnione zasoby i może upłynąć 10 sekund sekundy przed wykonaniem polecenia. Ponadto wywołuję funkcję Sleep() w procedurze obsługi zdarzeń, aby czasami zrezygnować z procesora.Czy program obsługi zdarzeń TTimer.OnTimer jest ponownie wyświetlany?

Nie jestem pewien, jak działa TTimer obiektu budującego C++, jeśli chodzi o wywoływanie zdarzeń, więc scenariusz, który właśnie wyjaśniłem, skłonił mnie do zastanowienia się, w szczególności, czy HandleTimerEvent() zostanie wywołany przed powrotem poprzedniego połączenia.

Pytanie sprowadza się do kilku rzeczy.

Czy obiekt TTimer umieszcza w kolejce zdarzenia?

Czy obiekt TTimer może wywoływać moją funkcję obsługi zdarzenia przed zwróceniem poprzedniego połączenia?

Odpowiedz

31

Ta odpowiedź zakłada, że ​​TTimer jest nadal zaimplementowany, aby używać wiadomości WM_Timer. Jeśli implementacja uległa zmianie (od 2005 r.), Proszę zignorować.

Nie, obiekt TTimer nie kolejkuje zdarzeń. Jest on sterowany przez komunikat Windows WM_Timer, a system Windows nie pozwala komunikować się komunikatom WM_TIMER w kolejce komunikatów. Jeśli pojawi się następny interwał czasowy i Windows zobaczy, że wiadomość WM_Timer jest już w kolejce komunikatów aplikacji, nie dodaje kolejnej wiadomości WM_Timer do kolejki. (Tak samo dla WM_Paint, btw)

Tak, możliwe jest wywołanie zdarzenia TTimer.OnTimer nawet wtedy, gdy poprzednia procedura obsługi zdarzeń nadal jest wykonywana. Jeśli zrobisz cokolwiek w swojej procedurze obsługi zdarzeń, która pozwoli aplikacji na przetwarzanie wiadomości, zdarzenie licznika czasu może zostać ponownie wprowadzone. Oczywistym jest, jeśli twój program obsługi wywoła funkcję Application.ProcessMessages, ale może być znacznie bardziej subtelny - jeśli cokolwiek wywołasz w swojej procedurze obsługi zdarzenia wewnętrznie wywoła Application.ProcessMessages lub wywoła PeekMessage/GetMessage + DispatchMessage lub otworzy modalne okno dialogowe lub wywołuje interfejs COM, który jest powiązany z pozaprocesowym obiektem COM, następnie wiadomości w kolejce komunikatów aplikacji zostaną przetworzone i mogą zawierać następną wiadomość WM_Timer.

Prostym rozwiązaniem jest wyłączenie obiektu timera po wejściu do programu obsługi zdarzeń zegara i ponowne włączenie go po wyjściu z programu obsługi zdarzeń zegara. Zapobiegnie to wystrzeleniu wiadomości z timera, gdy funkcja obsługi zdarzeń będzie nadal działać, niezależnie od właściwości obsługi wiadomości w kodzie.

+10

+1 za wyłączenie timera. Aby zademonstrować skuteczność wyłączenia timera (lub łatwego pokazania, co może pójść nie tak, jeśli tego nie zrobisz), wyświetl komunikat w module obsługi zegara. Jeśli nie wyłączysz timera po wejściu, skrzynki komunikacyjne będą się układać w stosy. –

+2

Można również użyć flagi binarnej, aby zapobiec ponownemu umieszczeniu w sterowniku zdarzeń zegara, ale wyłączenie samego zegara jest znacznie prostsze. – dthorpe

+0

Zobacz https://forums.embarcadero.com/thread.jspa?messageID=171751𩻧 dla użytecznej klasy TTimerGuard, klasy w stylu RAII do używania TTimer. Może wymagać dostosowania użycia FInterval w zależności od implementacji. –

2

Używam ekstensywnie TTimer. Nie kolejkuje zdarzeń. Jeśli chcesz przekazać go do obsługi zdarzenia, utwórz TThread, który obsługuje twoje zdarzenia, aby timer mógł kontynuować pracę. Timer nie działa asychronicznie, ale raczej synchronicznie.

Powiązane problemy