1

我正在尝试在我的WPF应用程序中实现加载器。在一些繁重的操作中,UI 线程被冻结,所以我不得不使用线程来实现加载器。每次加载程序加载时,都会创建一个新线程,并且当加载程序启动时,该线程会(手动)中止。我面临的问题是,有时应用程序会崩溃并给出ThreadAbortException.

这是启动加载程序的代码:

try
        {
            //if(newWindowThread !=null && !newWindowThread.IsAlive) { }
            newWindowThread = new Thread(new ThreadStart(() =>
            {
                try
                {
                    // Create and show the Window
                    awq = new BusyIndicatorDisguise(BusyMessage);
                    awq.Show(); // <== POINT WHERE THE EXCEPTION IS THROWN
                    //Start the Dispatcher Processing
                    if (!isDispatcherStarted)
                    {
                        var a = Thread.CurrentThread;
                        var b = Dispatcher.CurrentDispatcher;
                        //isDispatcherStarted = true;
                        Dispatcher.Run();
                    }

                }
                catch (ThreadAbortException thEx)
                {

                }
                catch (Exception ex)
                {

                }
            }
            ));
            // Set the apartment state
            newWindowThread.SetApartmentState(ApartmentState.STA);
            // Make the thread a background thread
            newWindowThread.IsBackground = true;
            // Start the thread
            newWindowThread.Start();
        }
        catch (Exception ex)
        {

        }

此代码用于停止加载程序:

if (newWindowThread != null && newWindowThread.IsAlive)
        {          
            newWindowThread.Abort();              
        }

我无法在我的 catch 块中捕获此异常。也许是因为它在不同的线程上。我想知道如何避免 ThreadAbortException

4

2 回答 2

1

您应该在可能引发异常的线程中添加一个 try catch 块,并根据您的需要对其进行管理。

无论如何,正如@Josh 在其他类似帖子中所说

有很多更好的方法可以在不使用 Thread.Abort 的情况下中止线程,这不仅会在不可预知的点混乱地中断您的代码,而且也不能保证工作,因为如果您的线程当前正在调用一些非托管代码,线程将不会中止直到控制权返回到托管代码。

最好使用某种类型的同步原语(例如 aManualResetEvent)作为一个标志,告诉您的线程何时退出。您甚至可以为此目的使用一个布尔字段,这就是 BackgroundWorker 所做的。

于 2016-04-22T05:22:02.007 回答
1

如果您为自己抛出异常,请忘记Thread.Abort. 这就是为什么:

  • 抛出异常是一项极其昂贵的操作。它保存了整个调用堆栈和其他有用的数据以供调试。在这种情况下,您只需要设置一个简单的标志。
  • ThreadAbortException是一个棘手的问题。Thread.ResetAbort除非您在块中调用,否则它会在异常处理程序块的末尾自动重新抛出catch。但不要那样
  • AThreadAbortException是一个异步异常,这意味着它可能发生在代码的任何位置,这可能会导致不可预知的结果。它是一个蛮力工具,例如End task任务管理器中的按钮。仅当您无法重写执行的代码(第 3 方组件)并且您确定可以卸载不稳定执行环境的剩余部分(它在 中执行AppDomain)时才使用它。

相反,向您的加载程序发送取消请求(可以是简单的bool),您应该在加载操作期间定期轮询。是一个示例,您可以如何使用 aBackgroundWorker和 volatile 字段来做到这一点。

于 2016-04-22T06:08:53.137 回答