2009-09-21 28 views
1

我有一個靜態類在其構造函數中創建了幾個工作線程。如果在工作人員創建之前發生異常,我的Application.ThreadException處理程序(用於在發生不可恢復的錯誤時關閉應用程序)會正常觸發,並且一切正常。一旦創建了第一個工作線程,除了處理程序觸發外,我還會收到一個「MYAPP遇到問題並需要關閉,我們對此造成的不便表示抱歉。」 MS錯誤報告對話框。在多線程應用程序中處理靜態構造函數異常

在這個特定的實例中,我可以重新排列代碼以最後創建線程(在任何可能觸發異常的資源初始化/訪問問題之後),但這只不過是對問題的一種繃帶而不能給我有關實際發生的任何信息。

希望我已經從我的應用程序中刪除了足夠的代碼,以顯示我在這裏要做的事情。

class Program 
{ 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main(string[] args) 
    { 
     try 
     { 
      Application.Run(theForm); 
      theForm.Dispose(); 

     } 
     catch (Exception e) 
     { 
      //doing this to use the same handler here and for Application.ThreadException 
      ThreadExceptionEventArgs argsEx = new ThreadExceptionEventArgs(e); 
      FatalExceptionHandler(null, argsEx); 

     } 
     finally 
     { 
      MyStaticClass.KillThreads(); 
     } 
    } 

    public static void FatalExceptionHandler(object sender, System.Threading.ThreadExceptionEventArgs ex) 
    { 
     Exception e = ex.Exception; 
     try 
     { 
      //lots of stuff to give more useful error messages for known problems 
      //and display them in a messagebox. 
     } 
     // if anything went wrong scraping the exception text for formatting, show the raw value. 
     catch 
     { 
      MessageBox.Show(e.Message); 
      return; 
     } 
     // after showing the MessageBox, close out the app. 
     finally 
     { 
      System.Environment.Exit(1); 
     } 
    } 
} 

class MyStaticClass 
{ 
    static MyStaticClass() 
    { 
     myThread = new Thread(new ThreadStart(SomeMethod)); 

     //if this exception is thrown everything works normally 
     //Throw new Exception("KABOOM"); 

     myThread.Start(); 

     //if this exception is thrown a windows error reporting dialog appears 
     //along with the messagebox from program.FatalExcetion handlder    
     //Throw new Exception("KABOOM"); 
    } 


    public void KillThreads() 
    { 
     //clean up the worker threads 
    } 
} 

回答

4

靜態構造函數在應用程序啓動期間的特定時間沒有被調用。特別是,如果您從未從另一個類引用MyStaticClass,則可能永遠不會初始化它。既然你不能以任何理智的方式推理,你應該爲靜態構造函數中的非平凡代碼類型提供一個StaticInitialize()方法(或類似的方法),以及靜態初始化代碼確實需要運行的情況。將代碼從靜態構造函數移動到靜態初始化方法。

+0

我認爲構造函數總是被調用,最遲在它的成員/方法/屬性被訪問時調用。 – 2009-09-21 18:36:35

+0

這是正確的,但是訪問成員的「if和when」時,它仍然沒有解決a)構造函數運行於哪個線程上,b)運行時相對於應用程序生存期。下面是我剛剛制定的一個經驗法則,可以幫助您:如果靜態構造函數中的代碼無法在不更改程序行爲的情況下連續運行兩次,請將代碼移至靜態初始化方法。 – 2009-09-21 18:44:57

+0

如果我將所有代碼從靜態構造函數移動到初始化方法,是否有理由保持構造函數? – 2009-09-21 19:50:18

1

Application.ThreadException僅針對UI線程未處理的異常(因爲是Application類的一部分)而引發的。工作線程未處理的異常事件是AppDomain.UnhandledException。當一個工作線程發生未處理的異常時,會引發此事件,然後顯示系統崩潰對話框。 AppDomain.UnhandledException僅用於記錄目的,並且沒有記錄的方法來防止顯示系統崩潰錯誤對話框。

+0

在這兩種情況下,該異常都是在同一個方法中調用的,並且應該來自同一個線程,因此我不明白AppDomain.UnhandledException如何涉及。 – 2009-09-21 18:53:12

+0

另外,有沒有辦法我可以附加一個覆蓋異常捕獲器在我的工作線程,以防止任何東西去AppDomain.UnhandledException? – 2009-09-21 19:29:40

+0

我認爲你扔的兩個地方之間的差異行爲可能會導致時間差異。在一種情況下,靜態構造函數在UI線程中運行,因此由應用程序傘處理程序運行,另一種情況下,由於構造函數實際上由工作線程運行的時間不同,所以它轉到appdomain非ui情況。不幸的是,非UI用戶線程沒有全球性的嘗試。 – 2009-09-21 19:33:39

相關問題