如何抑制thread.abort()错误c#?
-
11-09-2019 - |
题
我的程序加载时,我在背景线程上显示一个飞溅屏幕。一旦加载,我将中止该线程,因为它的唯一目的是显示现已加载的飞溅形式。
我的问题是,当中止线程时,它会抛出 ThreadAbortException
用户只需单击“继续”。
我该如何处理?我试图像这样抑制它 - >
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();
}
}
现在,当您的主要方法启动时,在线程中显示飞溅:
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 是可以通过应用程序代码捕获的特殊例外 重置 叫做。 重置 取消中止请求,并防止 threadabortexception 从终止线程。未执行的最终块在线程中止之前被执行。
不建议使用ThreadAbort。这是邪恶的。为什么不使用(自动/手动)RESETEVENT等其他机制?使用飞溅屏幕启动线程,等待活动。如果其他代码已完成加载内容,请设置事件EN允许飞溅屏幕以正常(不错的)方式关闭自身。
一些要点。线程非例外是线程中止的原因。这不是您打电话堕胎的副作用。当您在线程上调用流产时,运行时会迫使线程型异常传播到线程。可以捕获此例外,因为它允许用户在线程中止之前进行一些清理。
然后将自动重新自动重新启动,以确保螺纹流产。如果抓住了例外,如果没有再生,则线程将永远不会流产。
实际上,真正聪明的设计。
因此,捕获该异常确实可以。实际上你应该。但是只捕获该特定例外,而不是一般例外。 (如下所示)
catch(ThreadAbortException ex)
{
//This is an expected exception. The thread is being aborted
}
将异常类型更改为 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 ...))之前实例化飞溅表格,我会发现问题。
它提出了由台阶引起的无效验证,在呼叫线程中仍然不存在。要直接在线程t中创建句柄(并跳过此例外!)尝试以这种方式启动飞溅表:
Thread t = new Thread(new ThreadStart(delegate
{
_splash = new Splash();
Application.Run(_splash);
}));
t.Start();
而且,如果您打算在程序的更多分支中调用Closesplash方法,请在第一个调用后强制零值:
private static Splash _splash = null;
public static void CloseSplash()
{
if (_splash!= null)
{
_splash.CloseSplash();
_splash=null;
}
}