首页  ·  知识 ·  编程语言
异常处理之ThreadException、unhandledException及多线程异常处
luminji  其它 http://www.cnblogs.com/luminji/  .NET  编辑:DEZAI   图片来源:网络
div align=leftb一:/bbThreadException/bb和/bbunhandledExcept
一:ThreadExceptionunhandledException的区别
处理未捕获的异常是每个应用程序起码有的功能,C#在AppDomain提供了UnhandledException 事件来接收未捕获到的异常的通知。常见的应用如下:   
代码
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        }

       
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception error = (Exception)e.ExceptionObject;
            Console.WriteLine(
"MyHandler caught : " + error.Message);
        }
未捕获的异常,通常就是运行时期的BUG,于是我们可以在UnhandledException 的注册事件方法CurrentDomain_UnhandledException中将未捕获异常的信息记录在日志中。值得注意的是,UnhandledException提供的机制并不能阻止应用程序终止,也就是说,CurrentDomain_UnhandledException方法执行后,应用程序就会被终止。
上面我们举的例子来自于控制台程序,UnhandledException可以在任何应用程序域中使用,在某些应用程序模型,如windows窗体程序,还存在ThreadException来处理 Windows 窗体线程中所发生的其未经处理的异常。即,在windows窗体程序中,使用 ThreadException 事件来处理 UI 线程异常,使用 UnhandledException 事件来处理非 UI 线程异常。ThreadException可以阻止应用程序终止。具体使用方法如下:  
代码
        [STAThread]
       
static void Main()
        {
            Application.ThreadException +=
new ThreadExceptionEventHandler(UIThreadException);
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            AppDomain.CurrentDomain.UnhandledException +=
               
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
            Application.Run(new ErrorHandlerForm());
        }

       
private static void UIThreadException(object sender, ThreadExceptionEventArgs t)
        {
           
try
            {
               
string errorMsg = "Windows窗体线程异常 : \n\n";
                MessageBox.Show(errorMsg + t.Exception.Message + Environment.NewLine + t.Exception.StackTrace);
            }
           
catch
            {
                    MessageBox.Show(
"不可恢复的Windows窗体异常,应用程序将退出!");
            }
        }

       
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
           
try
            {
                Exception ex = (Exception)e.ExceptionObject;
               
string errorMsg = "非窗体线程异常 : \n\n";
                MessageBox.Show(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
            }
           
catch
            {
                    MessageBox.Show(
"不可恢复的非Windows窗体线程异常,应用程序将退出!");
            }
        }
 除了Windows窗体程序,再来说一下WPF程序。WPF的UI线程和Windows的UI线程有点不一样。WPF的UI线程是交给一个叫做调度器的类:Dispatcher。代码如下:   
代码
public App()
        {
           
this.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        }

       
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
           
try
            {
                Exception ex = e.ExceptionObject
as Exception;
                string errorMsg = "非WPF窗体线程异常 : \n\n";
                MessageBox.Show(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
            }
           
catch
            {
                    MessageBox.Show(
"不可恢复的WPF窗体线程异常,应用程序将退出!");
            }
        }

       
private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
           
try
            {
                Exception ex = e.Exception;
                
string errorMsg = "WPF窗体线程异常 : \n\n";
                MessageBox.Show(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
            }
           
catch
            {
                    MessageBox.Show(
"不可恢复的WPF窗体线程异常,应用程序将退出!");
            }
        }
无论是Windows窗体程序还是WPF程序,我们都看到捕获的异常当中分为"窗体线程异常"和"非窗体线程异常"。如在Windows窗体程序中,如果在窗体线程中,       
throw new Exception("窗体线程异常");
将会触发ThreadException事件。  
            Thread t = new Thread((ThreadStart)delegate
            {
               
throw new Exception("非窗体线程异常");
            });
            t.Start();
 将会触发UnhandledException事件,然后整个应用程序会被终止。
 
二:多线程异常处理
 
多线程的异常处理,要采用特殊的做法。以下的处理方式会存在问题:   
代码
            try
            {
                Thread t =
new Thread((ThreadStart)delegate
                {
                   
throw new Exception("多线程异常");
                });
                t.Start();
            }
           
catch (Exception error)
           {
                MessageBox.Show(error.Message + Environment.NewLine + error.StackTrace);
            }
 应用程序并不会在这里捕获线程t中的异常,而是会直接退出。从.NET2.0开始,任何线程上未处理的异常,都会导致应用程序的退出(先会触发AppDomain的UnhandledException)。上面代码中的try-catch实际上捕获的还是当前线程的异常,而t是属于新起的异常,所以,正确的做法应该是:  
代码
            Thread t = new Thread((ThreadStart)delegate
            {
                
try
                {
                   
throw new Exception("多线程异常");
                }
               
catch (Exception error)
                {
                    MessageBox.Show(
"工作线程异常:" + error.Message + Environment.NewLine + error.StackTrace);
                }
            });
            t.Start();
 也就是说,新起的线程中异常的捕获,可以将线程内部代码全部try起来。原则上来说,每个线程自己的异常应该在自己的内部处理完毕,不过仍旧有一个办法,可以将线程内部的异常传递到主线程。
在Windows窗体程序中,可以使用窗体的BeginInvoke方法来将异常传递给主窗体线程:  
代码
            Thread t = new Thread((ThreadStart)delegate
            {
               
try
                {
                   
throw new Exception("非窗体线程异常");
                }
               
catch (Exception ex)
               {
                   
this.BeginInvoke((EventHandler)delegate
                    {
                       
throw ex;
                    });
                }
            });
            t.Start();
上文的代码将最终引发主线程的Application.ThreadException。最终的结果看起来有点像:  
 
本文作者:luminji 来源:其它 http://www.cnblogs.com/luminji/
CIO之家 www.ciozj.com 微信公众号:imciow
    >>频道首页  >>网站首页   纠错  >>投诉
版权声明:CIO之家尊重行业规范,每篇文章都注明有明确的作者和来源;CIO之家的原创文章,请转载时务必注明文章作者和来源;
延伸阅读