如何抑制thread.abort()错误C#?

时间:2009-06-04 14:48:50

标签: c# .net multithreading error-suppression thread-abort

我在程序加载时在后台线程上显示启动画面。加载后我将中止线程,因为它的唯一目的是显示一个正在加载的初始形式。

我的问题是,在中止线程时,它会抛出一个ThreadAbortException,用户只需点击继续。

我该如何处理?我试图像这样压制它 - >

            try
        {
            Program.splashThread.Abort();
        }
        catch(Exception ex)
        {

        }

但是我有一种感觉会让我在这里大吼大叫而且无论如何都没有用。

谢谢!

8 个答案:

答案 0 :(得分:20)

您无需取消该帖子。我将用代码举例说明。

在初始屏幕中:

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();

然后你不必担心中止线程;它会优雅地退出。

答案 1 :(得分:9)

请参阅Google搜索获得的以下链接(返回的第一个结果):

http://msdn.microsoft.com/en-us/library/5b50fdsz.aspx

特别注意这一部分:

在线程上调用此方法时,系统会在线程中抛出 ThreadAbortException 以中止它。 ThreadAbortException 是一个特殊的异常,可以被应用程序代码捕获,但会在catch块的末尾重新抛出,除非调用 ResetAbort ResetAbort 取消中止请求,并阻止 ThreadAbortException 终止该线程。在线程中止之前执行未执行的finally块。

答案 2 :(得分:7)

不建议使用Threadabort。这是邪恶的。为什么不使用像(自动/手动)ResetEvent这样的其他机制? 使用启动画面启动线程,等待事件。如果其他代码已完成加载,请设置事件,允许启动画面以正常(漂亮)的方式关闭。

答案 3 :(得分:4)

有些观点。 ThreadAbort异常是线程中止的原因。这不是你打电话中止的副作用。 在线程上调用abort时,运行时会强制将threadabort异常传播到线程。可以捕获此异常,因为它允许用户在线程中止之前执行一些清理。

然后自动重新抛出异常以确保线程被中止。如果异常被捕获并且如果没有被重新抛出,那么线程永远不会中止。

实际上是真正的智能设计。

所以抓住那个例外真的很好。实际上你应该。但只抓住那个特定的例外而不是一般的例外。 (如下图所示)

catch(ThreadAbortException ex)
{
   //This is an expected exception. The thread is being aborted
}

答案 4 :(得分:3)

将例外类型更改为 ThreadAbortException 并添加对 ResetAbort()的调用

    try
    {
        Program.splashThread.Abort();
    }
    catch(ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }

一般来说,中止线程被认为是非常糟糕的做法,并且可能导致各种难以追踪的错误。您是否考虑过设置一种方法来关闭启动窗口或使用某种轮询来在设置标志时停止线程?

答案 5 :(得分:1)

你为什么这样做?只需设置一个线程轮询的标志,然后最终当线程选中它时它将自行关闭。

答案 6 :(得分:1)

试试这段代码。它对我来说很好。

void splash()
{
    try {
        SplashScreen.SplashForm frm = new SplashScreen.SplashForm();
        frm.AppName = "HR";

        Application.Run(frm);
    }
    catch (ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }
}

答案 7 :(得分:0)

我使用了FredrikMörk建议的解决方案。它非常清晰优雅。 否则,如果我们在启动真实应用程序之前实例化splash表单(application.run(mainform ...)),我发现了一个问题:

它引发了一个由form-handle引起的invalidOprationException,它仍然不存在于调用线程中。 要直接在线程t中创建句柄(并跳过此异常!),请尝试以这种方式启动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;
        }
}