如何抑制thread.abort()错误C#?
我的程序加载时,我在后台线程上显示启动画面。 一旦加载我就会中止线程,因为它的唯一目的是显示一个正在加载的启动表单。
我的问题是,当中止一个Thread时,它会抛出一个ThreadAbortException
,用户只需单击Continue on。
我该如何处理? 我试图压制它 – >
try { Program.splashThread.Abort(); } catch(Exception ex) { }
但我有一种感觉,这会让我在这里大吼大叫,它无论如何都行不通。
谢谢!
您无需取消该主题。 我将用代码举例说明。
在启动画面中:
public void CloseSplash() { Invoke((MethodInvoker)delegate { this.Close(); }); }
在Program.cs文件中:
private static Splash _splash = null; public static void CloseSplash() { if (_splash!= null) { _splash.CloseSplash(); } }
现在,当您的Main方法启动时,在线程中显示启动:
Thread t = new Thread(new ThreadStart(delegate { _splash = new Splash(); _splash.ShowDialog(); })); t.Start();
…当你想要它关闭时,只需关闭它:
Program.CloseSplash();
然后你不必担心中止线程; 它会优雅地退出。
请参阅以下链接获取Google搜索(返回的第一个结果):
http://msdn.microsoft.com/en-us/library/5b50fdsz.aspx
特别注意这部分:
在线程上调用此方法时,系统会在线程中抛出ThreadAbortException以中止它。 ThreadAbortException是一个特殊的exception,可以被应用程序代码捕获,但是在catch块的末尾重新抛出,除非调用ResetAbort 。 ResetAbort取消中止请求,并阻止ThreadAbortException终止线程。 在线程中止之前执行未执行的finally块。
不建议使用Threadabort。 这是邪恶的。 为什么不使用像(自动/手动)ResetEvent这样的其他机制? 使用启动画面启动线程,等待事件。 如果其他代码已完成加载内容,请设置事件以允许启动屏幕以正常(好)方式关闭自身。
一些观点。 ThreadAbortexception是线程中止的原因。 这不是你打电话中止的副作用。 在线程上调用abort时,运行时会强制将threadabortexception传播到线程。 可以捕获此exception,因为它允许用户在线程中止之前执行一些清理。
然后自动重新抛出该exception以确保线程被中止。 如果exception被捕获并且如果没有重新抛出,则线程永远不会中止。
实际上真的很聪明。
所以抓住那个例外真的没问题。 实际上你应该。 但只抓住那个特定的例外,而不是一般的例外。 (如下所示)
catch(ThreadAbortException ex) { //This is an expected exception. The thread is being aborted }
将exception类型更改为ThreadAbortException并添加对ResetAbort()的调用
try { Program.splashThread.Abort(); } catch(ThreadAbortException ex) { Thread.ResetAbort(); }
一般来说,中止线程被认为是非常糟糕的做法,并且可能导致各种难以追踪的错误。 您是否考虑过设置一种方法来关闭启动窗口或使用某种轮询来在设置标志时停止线程?
为什么要这么做? 只需设置一个线程轮询的标志,然后最终当线程选中它时它将自行关闭。
试试这个代码。 它对我来说很好。
void splash() { try { SplashScreen.SplashForm frm = new SplashScreen.SplashForm(); frm.AppName = "HR"; Application.Run(frm); } catch (ThreadAbortException ex) { Thread.ResetAbort(); } }
我使用了FredrikMörk建议的解决方案。 它非常清晰优雅。 否则,如果我们在启动真实应用程序(application.run(mainform …))之前实例化splash表单,我发现了一个问题:
它引发了一个由form-handle引起的invalidOprationException仍然不存在于调用线程中。 要直接在线程t中创建句柄(并跳过此exception!),请尝试以这种方式启动splash表单:
Thread t = new Thread(new ThreadStart(delegate { _splash = new Splash(); Application.Run(_splash); })); t.Start();
并且,如果您计划在程序的更多分支中调用closeSplash方法,请在第一次调用后强制使用null值:
private static Splash _splash = null; public static void CloseSplash() { if (_splash!= null) { _splash.CloseSplash(); _splash=null; } }