2009-09-21 80 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