2012-01-19 84 views
8

形勢
嗯,你可以看到下面,我有一個主要的應用程序,創建一個線程,它創建了一堆背景的工人。當RunWorkerCompleted被解僱了一些BG工人時,我有時候最終放棄了一個未處理的異常,(因爲我明確指出了一個原因,但這不是問題)。
劫持UnhandledException保持多線程應用程序運行

architecture

所以日誌清楚地表明,我的UnhandledException處理程序進入和異常報告。 我知道我故意濫用OnUnhandledException通過使用Console.Read()停止應用程序退出。我特意做了,因爲我想在終止應用之前進行人工干預/檢查。

public static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Logger.log("UNHANDLED EXCEPTION : " + e.ExceptionObject.ToString()); 
     Mail.Sendmail("ADMIN ALERT : " + e.ExceptionObject.ToString()); 
     Console.Read(); // Yes, this is an ungraceful trick, I confess. 
    } 

然而,什麼應該僅僅是一個「暫停」之前手動退出橫空出世,以保持應用程序活着,即線程仍在產生工作者和運行若無其事。甚至Weirder:當它再次發生時,UnhandledException仍然不時被刪除。它每次都被記錄下來,表現得就像是一場純粹的嘗試。 (這是NET 3.0之前默認行爲)

問題
那麼,爲什麼發生的一切彷彿UnhandledException沒有拋出,線程和BG的繼續運轉,好像什麼都沒有發生? 我的猜測是是,只要OnUnhandledException處理程序沒有完成,並且應用程序仍然存在,所有仍在運行的運行線程將繼續生活在一個自由的世界中並執行其工作。

這給了我一個不好的誘惑,這是保持這種設計,作爲try/catch to unHandled異常
我知道這不是一個整潔的想法,因爲你永遠不知道異常是嚴重的還是可以跳過的東西。但是,我真的更喜歡我的程序整天保持運行,並觀察日誌報告/郵件警報,並確定是否需要重新啓動它。 由於這是一個需要24/7全天候運行的服務器應用程序,因此我想避免由於小的仍未處理的異常而導致的錯誤和重複的中斷。 這樣做的最大優勢在於,服務器程序在我們逐一跟蹤未處理的異常並提供補丁以處理它們發生時繼續運行。

感謝您的耐心等待,並隨時給予反饋。

PS:不,我沒有吸鍋。

+0

當然'MessageBox'比'Console.Read'好! – leppie

+2

一個好問題不會被低估,即使你做的都是錯的;-) – Steven

+0

我想你對這種事情發生的猜測是正確的。是否可以將此應用程序作爲Windows服務而不是Console應用程序來實現?這樣,當服務由於未處理的異常而失敗時,可以讓服務自動重啓。 –

回答

3

我的猜測是,只要OnUnhandledException處理程序不 做的,而應用程序還活着,所有正在運行的線程仍然 活着繼續生活在一個自由的世界,做他們的工作。

正確。但是你的其他線程現在在潛在的不穩定的過程中完成他們的工作。發生未處理的異常時,終止應用程序有很好的理由。

我真的喜歡我的程序繼續運行

除了(潛在的)穩定性的問題,你會積累無論是參與未處理操作的暫停狀態。我的猜測是,每當它發生時,你至少會泄漏一個線程。而且你不能把太多的東西放在一邊。

所以這將是一個非常糟糕的設計,只會延遲崩潰。

+0

這是我的Good-Developer Angel告訴我的那種考慮,但他被邪惡開發者惡魔毆打。直到你來報復他:) –

+0

@亨克:如果你已經專門設計了你的BackgroundWorker線程死掉(也許然後重新啓動),如果發生未處理的異常,那麼我不會看到讓他們在保持流程運行的同時死亡。後臺線程更有可能被非致命(進程)異常所擊落,而不是像OutOfMemory這樣的令人討厭的東西。 – RoadWarrior

2

首先,您需要訂閱UnhadledThreadException處理程序。在那裏你不能「劫持」這個異常,但是你可以訪問它,也可以訪問它所屬的線程。你現在可以做的是把拋出的線程掛起。線程將仍然活着! 但這是一個糟糕的,骯髒的黑客!不要這樣做!一些細節請看this article

我建議將線程模型切換到TPL(設計仍然存在)。在那裏,你可以訪問那些醜陋的跨線程excepions,並可以處理/優雅舒適的時間。

+0

這似乎很有趣,但是在表達方面有點不清楚。請介意提供更多細節,來源和/或例子嗎?謝謝 –

+0

我已經添加了一個如何捕獲WinForms中的一個無干擾的線程異常(可以爲WPF,等等)。 – Jaster

+0

http://stackoverflow.com/questions/2707295/how-to-handle-all-unhandled-exceptions-when-using-task-parallel-library tpl處理 – Jaster

1

如果您希望在不殺死整個進程的情況下允許BackgroundWorker線程發生故障,那麼可以採用更簡潔的方式來完成此操作。

首先,攔截RunWorkerCompleted事件。當BackgroundWorker線程終止時引發此事件,通常爲或通過未處理的異常。然後在你的事件處理程序,檢查是否有未處理的異常:

// Runs when the BackgroundWorker thread terminates. 
private void ThreadFinished(object sender, RunWorkerCompletedEventArgs e) 
{ 
    // Process any unhandled exception 
    if (e.Error != null) 
    { 
     this.LogError(e.Error.Message, e.Error.StackTrace, blah, blah); 

通過這種方式,可以讓BackgroundWorker的線程芯片並記錄任何異常而不終止的全過程。

+0

這不是關於_unhandled_異常。 OP沒有透露真實的代碼。假設是一個例外繞過了這個和所有其他形式的捕獲。 –