2010-07-22 60 views
18

我在我的應用程序中有一個TTimer,每2秒觸發一次並調用我的事件處理程序HandleTimerEvent()。 HandleTimerEvent()函數修改共享資源,並且在返回之前可能需要10秒才能執行。此外,我在事件處理程序中調用Sleep()以便有時放棄處理器。TTimer.OnTimer事件處理程序是否可重入?

我不確定C++ builder的TTimer對象在調用事件時是如何工作的,所以我剛剛解釋的場景讓我想到了,特別是在事先調用返回之前是否調用HandleTimerEvent()。

這個問題歸結爲幾件事情。

TTimer對象是否排隊事件?

在先前調用返回之前,TTimer對象可以調用我的事件處理程序嗎?

回答

31

此回覆假定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消息。

一個簡單的解決方案是當你進入你的計時器事件處理程序時禁用計時器對象,並在你退出計時器事件處理程序時重新啓用它。這將防止計時器消息在事件處理程序仍在工作時觸發,無論代碼的消息處理特性如何。

+10

+1用於禁用定時器。爲了演示禁用定時器的有效性(或簡單演示如果不這樣做會出錯),請在定時器處理程序中顯示一個消息框。如果您在進入時不禁用定時器,則消息框將疊加起來。 – 2010-07-22 18:26:44

+2

您也可以使用布爾標誌來防止定時器事件處理程序中的重入,但禁用定時器本身要簡單得多。 – dthorpe 2010-07-22 21:23:21

+0

請參閱https://forums.embarcadero.com/thread.jspa?messageID=171751𩻧以獲取有用的TTimerGuard類,TTimer使用的RAII風格類。可能需要根據您的實施情況調整FInterval使用情況。 – 2011-01-27 17:04:50

2

我廣泛使用TTimer。它不排隊事件。如果你想把它交給事件處理程序,那麼創建一個TThread來處理你的事件,這樣Timer就可以繼續工作。定時器不是異步操作,而是同步操作。

相關問題