windows终止处理程序( __try __finally) 简单解析
本文大部分來自《windows核心編程》。
例1
//二話不說,直接上代碼int Funcenstein2() {__try{return 3;}__finally{//在函數返回之前會處理__finally里的內容cout<<"finally executed"<<endl;}return 4;//此函數返回3而不是4 }
?
通過使用終止處理程序可以防止過早的執行return語句。當return語句試圖退出try塊的時候,編譯器會讓finally代碼在它。即編譯器保證finally代碼塊在出try塊的時候return之前執行。
者可以想知道,編譯器是如何保證此功能的呢?原來當編譯器檢查程序代碼時,會發現try代碼里有一個return語句。于是,編譯器就會生成一些代碼先將返回值(例子中的 3)保存在一個由它創建的一個臨時變量里,然后再執行finally語句塊。這個過程被稱之前為局部展開(LOCAL UNWIND)。更確切的說,當系統因try代碼提前退出finally時就會發生局部展開。一旦finally代碼塊執行完畢,編譯器所創建的臨時變量值就會返回給函數調用者。
?
由此可見,為了讓整個機制運行起來,編譯器必須生成一些額外的代碼,而系統也要很執行一些額外的工作。在不同的cpu結構上,讓終止處理工作起來的步驟也不同。需要注意的是,應該避免在try代碼中使用return語句,因為這是對程序性能有害的。__leave關鍵字,它可以幫助我們發現那些有局部展開開銷的代碼
?
?例2
int Funcenstein3() {//在try中使用goto語句時,就會產生局部展開以執行finally代碼塊。//這一次當finally執行完之后。因為try和finally中都沒有函數返回語句,//所以ReturnValue標簽后面的代碼也會執行。因此這函數返回4。//但是由于代碼破壞了try塊到finally的正常執行流程,可能有比較大的性能損失,其程序取決于cpu體系結構。int ret=0;__try{ret=5;goto ReturnValue;}__finally{cout<<"finally executed"<<endl;} ReturnValue:return 4; }?
?例3
在這個例子中,終止處理將真正證明它的價值。首先看一下代碼
DWORD Funcfurter1() {DWORD dwTemp;//1. do any processing here __try{WaitForSingleObject(g_hSem,INFINITE);dwTemp=Funcinator(g_dwProtectedData);}__finally{ReleaseSemaphore(g_hSem,1,NULL);}return dwTemp; }假設try代碼塊中Funcinator函數存在一個缺陷會導致程序訪問非法的內存。如果沒有SEH這種情況下最絡導致Windows錯誤報告(WER)彈出一個對話框:“Application has stopped working”。這個對話框在Windows上經常可以見到。一旦用戶取消這個對話框,進程就會終止。但信號量依然被占用并再也得不到釋放。其他進程中的純種就會因為無休止的等待這個信號量而得不到CPU時間片。如果把信號量放在finally之中,即使用try中調用的函數發生了內存訪問違規這樣的異常,這個信號量也可以被釋放。但是,請注意,從Windows Vista開始,須顯式地保護try/finally框架,以確保在異常拋出時,finally代碼會執行。
?
?例4
現在不防做一個實驗,判斷一下這個函數的返回值
DWORD FuncalDoodLeDoo() {DWORD dwTemp=0;while (dwTemp<10){__try{if(dwTemp==2)continue;if(dwTemp==3)break;}__finally{dwTemp++;}dwTemp++;}dwTemp+=10;return dwTemp; }讓我們逐步分析這個函數執行的過程:一開始將dwTemp賦值為0,然后try塊中的代碼開始執行,但是兩個if語句都為false。于是程序正常進入到finally代碼塊,在這里給dwTemp的值上加1,而finally塊后面的代碼又將dwTemp加1。
?
下一次循環開時,dwTemp=2,第一個if為true,程序試如果沒有__finally程序會跳到while條件判斷處執行,但dwTemp值班不會改變,這將會是一個死循環。但是現在我們有終止處理程序,系統注意到continue語句將會導致提前跳出try塊,于是強制執行finally語句塊。 在finally語句塊中dwTemp被增加到3.這次finally之后的代碼塊沒有機會執行。因此finally執行完之后程序跳到循環頂部執行。
?
現在我們分析第三次迭代,這次第一個if判斷表達式的值為false,第二個表達式的值為true,系統再次偵測到程序流想要提前跳出try塊,于是調用finally代碼塊,這里的dwTemp增加到4.因為break語句的執行程序控制流從whhile循環后開始繼續。因而finally塊之后循環以內的代碼就不會被執行了。而循環之后的代碼將dwTemp的值設置為14。這是程序最終返回的結果。不用我指明,請教也不會寫出FuncalDoodleDoo這樣的代碼。此處只是為了演示終止處理程序是如何工作的。‘
?
絕大多數部情況下,try塊中的提前退出都會被終止處理程序所捕獲,但是在進程或線程提前終止的情況下,系統沒法保證finally代碼塊的執行。調用ExitThread或者ExitProcess可以馬上終止純種或進程,而不會引發finally執行。同樣如果當前純種或者進程因為另一個程序調用TerminateThread或TerminateProcess而不得不結束,finally代碼塊也不會被執行,有一些c運行期函數比如(abort),因為在其內部最絡調用的是ExitProcess,也會導致finally塊不能執行。我們沒法阻止別的線程殺死我們的線程或進程,但是可以在自己的代碼中盡量避免對ExitThread或ExitProces的草率調用。
?
例5
DWORD Funcenstein4() {DWORD dwTemp;//1. do any processing here __try{WaitForSingleObject(g_hSem,INFINITE);g_dwProcectedData=5;dwTemp=g_dwProcectedData;//return the new valuereturn dwTemp; }__finally{ReleaseSemaphore(g_hSem,1,NULL);return 103;}dwTemp = 9;return dwTemp; }在上面的函數中,try中的代碼試圖用return 返回給調用者。正如我們前面提到的那樣,試圖在try塊中提前退出函數導致編程器生成一些額外代碼,將函數返回結果保存在一個臨時變量中,然后執行finally中又多了一個return,那么導致103被寫入到編譯器生成的臨時變量時。從而覆蓋了原先的值5。而返回103
?
出處:http://www.cnblogs.com/zhangdongsheng/ 作者:張東升 QQ:290387340總結
以上是生活随笔為你收集整理的windows终止处理程序( __try __finally) 简单解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: __declspec(naked)详解
- 下一篇: Socket重叠IO