有這么個問題
有個讀者問:當異常發生的時候,如果不知道是否要清理臨界區對象,什么是合適的異常處理方式?
這個讀者的問題是這樣的:
“我正在使用SEH,在代碼中我使用了__try/__except塊來保護那些進入和退出臨界區的代碼。當異常發生的時候,我不知道我是否還在臨界區中還是已經出來了。就算是使用__try/__finally這種方式,也沒能解決我的
問題。”
問題答案:你可以知道你是否擁有臨界區對象,因為你一旦進入了,就表示你獲取到了臨界區對象。
方法1:通過指令指針進行判斷
“如果代碼執行到這里,則表示我肯定在臨界區里。”
請注意,以上這種方法對于嵌套調用EnterCriticalSection的情況也是能正常工作的。
如果你再次獲取到了臨界區,則一定要記得將調用包含在它自身的try/finally結構中。
方法2:通過棧變量進行判斷
“我記得我是否已經進入臨界區”
以上方法也是可以適用于嵌套調用EnterCriticalSection的情況。只是要記得,每次獲取臨界區對象,都要對cEntered進行加1。
方法3:通過對象來進行追蹤
將CRITICAL_SECTION封裝到一個對象中。
這種方法最適合上面那位讀者的情況。
請注意,上面的代碼,不適用于嵌套臨界區的情況。如果你試著獲取臨界區對象兩次,則異常處理器只會退出臨界區一次。
還請注意,我們認為臨界區在初始狀態下為未獲取狀態并添加了斷言。如果恰好已經獲得了臨界區,則我們的清理代碼將會嘗試退出臨界區,但是它實際并沒有進入。(試想一下,如果在第一個”…”中就出現了異常。)
方法4:通過智能對象判斷
通過將CRITICAL_SECTION對象封裝到一個智能對象中。
可以在上面的代碼中添加如下方法:Dword Depth() { return Owned() ? m_dwDepth : 0; }
代碼如下:
當異常發生在臨界區的時候進行清理會導致這樣一個問題:我怎么知道清理操作是安全的?
你使用到了臨界區說明你想獨占的使用一個數據結構,但是如果在獲取臨界區的時候發現了異常,此時數據結構的狀態是不穩定的。如果只是簡單的退出臨界區會導致數據結構進入到一個不一致的狀態,就會導致一個很難診斷的問題:為什么我的引用計數沒有同步了?
后面我還會有更多關于異常的內容。
最后
Raymond Chen的《The Old New Thing》是我非常喜歡的博客之一,里面有很多關于windows的小知識,對于廣大Windows平臺開發者來說,確實十分有幫助。
本文來自:《How do I determine whether I own a critical section if I am not supposed to look at internal fields?》