5

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

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

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

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

        }

但我有一种感觉,这会让我在这里大喊大叫,但它没有任何作用。

谢谢!

4

8 回答 8

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

那么你就不用担心中止线程了;它会优雅地退出。

于 2009-06-04T14:59:36.193 回答
9

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

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

这部分要特别注意:

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

于 2009-06-04T14:52:17.443 回答
7

不推荐使用 Threadabort。这是邪恶的。为什么不使用另一种机制,例如(自动/手动)ResetEvent?使用初始屏幕启动线程,等待事件。如果其他代码已完成加载内容,请设置事件以允许启动屏幕以正常(好的)方式自行关闭。

于 2009-06-04T14:53:01.870 回答
4

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

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

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

于 2009-06-04T14:50:35.510 回答
4

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

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

真正的智能设计实际上。

所以捕捉那个异常真的没问题。事实上你应该。但是只捕获那个特定的异常,而不是一般的异常。(如下所示)

catch(ThreadAbortException ex)
{
   //This is an expected exception. The thread is being aborted
}
于 2009-06-04T18:10:54.410 回答
1

为什么要这么做?只需设置一个线程轮询的标志,然后最终当线程捡起它时它会自行关闭。

于 2009-06-04T14:52:59.907 回答
1

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

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

        Application.Run(frm);
    }
    catch (ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }
}
于 2017-07-09T18:02:55.243 回答
0

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

它引发了由调用线程中仍然不存在表单句柄引起的 invalidOperationException 。要直接在线程 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;
        }
}
于 2009-07-23T14:11:06.963 回答