1. 程式人生 > >如何防止後臺執行緒丟擲的異常讓程式崩潰退出

如何防止後臺執行緒丟擲的異常讓程式崩潰退出

如果你的程式拋了異常,你是怎麼處理的呢?等待程式崩潰退出?還是進行補救?

如果是做 UI 開發,很容易就找到 Dispatcher.UnhandledException 事件,然後在事件中進行補救。如果補救成功,可以設定 e.Handled = true 來阻止異常繼續讓程式崩潰退出。但是,如果是後臺執行緒丟擲了異常呢?並沒有 Dispatcher 可以用。所以我們就束手就擒讓程式自己退出嗎?

WPF 和 Windows Forms 都是微軟的框架,為了照顧初學者,微軟會預設每一個開發者都不會正確地處理異常。於是在異常發生之後,微軟 Windows 會假設開發者並不知道如何應對以便讓應用程式正常工作,就擅自將應用程式程序結束掉,以便防止應用程式自己內部產生奇怪的狀態和錯誤,避免對系統環境造成不可逆的嚴重後果。

能夠寫出異常處理程式碼的開發者,微軟會預設他們懂了異常處理。

寫出了監聽 Dispatcher.UnhandledException 事件的開發者,微軟會認為他們已經學會了如何在 UI 執行緒中處理異常。於是允許開發者設定 e.Handled = true 來標記異常已被正確處理,程式可以不用退出了。

還有一個事件 Appdomain.CurrentDomain.UnhandledException,然而這個事件卻並不允許開發者標記 e.Handled = true。因為微軟認為,應用程式域中所有的執行緒發生異常都會進入這個事件中,大多數開發者都不明白這些執行緒這些異常是怎麼回事,所以不認為這些開發者具備正確處理這些異常的能力。比如 WPF 的觸控模組發生了異常,開發者知道如何恢復嗎?並不知道,還不如結束掉程式然後重啟呢!

在這個事件中,有一個屬性 IsTerminating 指示是否應用程式正因為這次異常準備退出,不過開發者並不能拿這個屬性做些什麼。

但還是要照顧更高階的開發者的,於是祭出新的配置——legacyUnhandledExceptionPolicy

app.config 檔案的 <runtime> 節點中新增如下程式碼:

<legacyUnhandledExceptionPolicy enabled="1"/>  

加上了這個配置之後,Appdomain.CurrentDomain.UnhandledException 事件的 IsTerminating 就變成了 false

啦!也就是說,程式並不會因為這次的異常而崩潰退出。

既然你通過這個配置節點於微軟達成了契約,你就需要好好地在 Appdomain.CurrentDomain.UnhandledException 事件中寫好異常的恢復邏輯。如果不好好恢復,小心有些致命的異常會導致你的程式出現雪崩式的錯誤,最終 Windows 還是會通過 CorruptedStateException 把你幹掉的!

參考資料