结束处理程序——Windows核心编程学习手札之二十三
結(jié)束處理程序
——Windows核心編程學(xué)習(xí)手札之二十三
使用SEH可以只關(guān)注程序要完成任務(wù),而運(yùn)行中發(fā)生的錯(cuò)誤,系統(tǒng)將會(huì)發(fā)現(xiàn)并通知。Windows引入SHE是為了便于操作系統(tǒng)的開發(fā),使用SHE所造成的負(fù)擔(dān)主要由編譯程序來(lái)承擔(dān),而不是由操作系統(tǒng)承擔(dān)。當(dāng)異常塊(exception block)出現(xiàn)時(shí),編譯程序要生成特殊的代碼,產(chǎn)生一些表(table)來(lái)支持處理SHE的數(shù)據(jù)結(jié)構(gòu),提供回調(diào)(callback)函數(shù),操作系統(tǒng)可以調(diào)用這些函數(shù),保證異常塊被處理。編譯程序還負(fù)責(zé)準(zhǔn)備棧結(jié)構(gòu)和其他內(nèi)部信息,供操作系統(tǒng)使用和參考。在編譯程序中增加SHE支持,不同的編譯商會(huì)以不同的方式實(shí)現(xiàn)SEH。SHE實(shí)際包含兩個(gè)主要功能:結(jié)束處理(termination handling)和異常處理(exception handling)。
一個(gè)結(jié)束處理程序能夠確保去調(diào)用和執(zhí)行一個(gè)代碼塊(結(jié)束處理程序,termination handling),而不管另外一段代碼(保護(hù)體,guarded body)是如何退出,結(jié)束處理程序的文法結(jié)構(gòu)如下:
?????? __try{
???????????????????? //guarded body
??????????? 。。。
???????? }
?????? __finally{
????????????? ?? //termination handler
?????????? 。。。
?????? }
__try和__finally關(guān)鍵字用來(lái)標(biāo)出處理程序兩段代碼的輪廓,操作系統(tǒng)和編譯程序共同確保結(jié)束處理程序中的__finally代碼塊能夠被執(zhí)行,不管保護(hù)體(try塊)是如何退出的,不論保護(hù)體中使用return,還是goto,或者是longjump,結(jié)束處理程序(finally塊)都將被調(diào)用。
盡管結(jié)束處理程序可以捕捉try塊過(guò)早退出的大多數(shù)情況,但當(dāng)線程或進(jìn)程被結(jié)束時(shí),卻不能引起finally塊中的代碼執(zhí)行。當(dāng)調(diào)用ExitThread或ExitProcess時(shí),將立即結(jié)束線程或進(jìn)程,而不會(huì)執(zhí)行finally塊中的任何代碼,另外,由于某個(gè)程序調(diào)用terminateThread或terminateProcess,線程或進(jìn)程將死掉,finally塊中的代碼也不執(zhí)行。某些C運(yùn)行期函數(shù)(如abort)要調(diào)用ExitProcess,也使finally塊中的代碼不能執(zhí)行,雖然沒(méi)有辦法阻止其他程序結(jié)束線程或進(jìn)程,但可以避免過(guò)早調(diào)用ExitThread和ExitProcess,以執(zhí)行finally塊中代碼。最好將return、continue、break、goto等語(yǔ)句從結(jié)束處理程序的try塊和finally塊中移出去,放在結(jié)束處理程序的外面,這樣使編譯程序產(chǎn)生較小的代碼,因?yàn)椴恍枰俨蹲?/span>try塊中的過(guò)早退出,也使編譯程序產(chǎn)生更快的代碼(因?yàn)閳?zhí)行局部展開的指令也不少),另外代碼更容易閱讀和維護(hù)。
為避免在try塊中使用return語(yǔ)句,microsoft在C/C++編譯程序中增加了__leave關(guān)鍵字。在try塊中使用__leave關(guān)鍵字會(huì)引起跳轉(zhuǎn)到try塊的結(jié)尾,即跳轉(zhuǎn)到try塊的右大括號(hào),由于控制流自然地從try塊中退出并進(jìn)入finally塊,不產(chǎn)生系統(tǒng)開銷,不過(guò)需要增加BOOL型變量來(lái)指示函數(shù)的成功或失敗,當(dāng)然這個(gè)代價(jià)是很小的。按照這個(gè)方式利用結(jié)束處理程序來(lái)設(shè)計(jì)函數(shù)時(shí),需要在進(jìn)入try塊之前,將所有資源句柄初始化為無(wú)效的值,然后在finally塊中查看那些資源被成功的分配,就可以知道那些要釋放。另外一種確定需要釋放資源的辦法是對(duì)成功分配的資源設(shè)置一個(gè)標(biāo)志,然后在finally塊中的代碼檢查標(biāo)志的狀態(tài),來(lái)確定資源是否被釋放。
區(qū)分強(qiáng)制執(zhí)行finally塊的情況:
1)從try塊中進(jìn)入finally塊的正常控制流;
2)局部展開:從try塊中過(guò)早退出(goto、longjump、contiune、break、return等)強(qiáng)制控制轉(zhuǎn)移到finally塊,由于系統(tǒng)開銷比較大,盡量避免在try塊中過(guò)早退出,可使用__leave代替return;
3)全局展開(global unwind),發(fā)生時(shí)沒(méi)有明顯標(biāo)識(shí),如引起一個(gè)內(nèi)存訪問(wèn)違規(guī)(memory access violation),一個(gè)全局展就會(huì)在finally塊執(zhí)行。
為了確定是那種情況引起finally塊執(zhí)行,可調(diào)用內(nèi)部函數(shù)(或內(nèi)蘊(yùn)函數(shù),intrinsic function)Abnormal Termination:
?????? BOOL AbnormalTermination();
這個(gè)內(nèi)部函數(shù)只在finally塊中調(diào)用,返回一個(gè)Boolean值,指出與finally塊相結(jié)合的try塊是否過(guò)早退出,如果控制流離開try塊并自然進(jìn)入finally塊,則返回FALSE;如果控制流非正常退出try塊(由于goto/return/break/contiune語(yǔ)句引起的局部展開),或由于內(nèi)部訪問(wèn)違規(guī)或其他異常引起的全局展開,將返回TRUE,這里沒(méi)發(fā)區(qū)別finally塊的執(zhí)行是由于局部展開還是全局展開。
內(nèi)部函數(shù)是編譯程序識(shí)別的一種特殊函數(shù),編譯程序?yàn)閮?nèi)部函數(shù)產(chǎn)生內(nèi)聯(lián)(inline)代碼而不是生成調(diào)用函數(shù)的代碼,例如,memcpy是一個(gè)內(nèi)部函數(shù)(如果指定/Oi編譯程序開關(guān))當(dāng)編譯程序看到一個(gè)對(duì)memcpy的調(diào)用,直接將memcpy的代碼插入調(diào)用memcpy的 函數(shù)中,而不是生成一個(gè)對(duì)memcpy函數(shù)的調(diào)用,其作用是代碼的長(zhǎng)度增加了,但執(zhí)行速度加快了。
利用結(jié)束處理程序的理由:
1)簡(jiǎn)單錯(cuò)誤處理,所有清理工作在一個(gè)位置并且保證被執(zhí)行;
2)提高程序的可讀性;
3)使代碼更加容易維護(hù);
4)如果使用得當(dāng),具有最小的系統(tǒng)開銷。
?
總結(jié)
以上是生活随笔為你收集整理的结束处理程序——Windows核心编程学习手札之二十三的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 插入DLL和挂接API——Windows
- 下一篇: 异常处理程序和软件异常——Windows