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

Posted

技术标签:

【中文标题】如何抑制 thread.abort() 错误 C#?【英文标题】:How do I suppress a thread.abort() error C#? 【发布时间】:2010-10-31 08:47:45 【问题描述】:

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

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

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

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

        

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

谢谢!

【问题讨论】:

我最近刚刚写了一篇关于创建启动画面的博客。看看这是否可以帮助你:crazorsharp.blogspot.com/2009/06/… 如果你需要使用 Thread.Abort 你做错了什么(通常)。尝试寻找一种不同的、更安全的方式。下面有很多好的建议。 @BFree:如果可以的话,我会给你分享答案!感谢您的建设性反馈。我已经从你的帖子中学到了很多东西!虽然另一个答案让我当前的解决方案能够正常工作,但我希望我会根据您博客中的信息创建一个更强大的 Splash。谢谢! 【参考方案1】:

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

void splash()

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

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

【讨论】:

【参考方案2】:

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

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

实际上是非常智能的设计。

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

catch(ThreadAbortException ex)

   //This is an expected exception. The thread is being aborted

【讨论】:

【参考方案3】:

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

它引发了由调用线程中仍然不存在表单句柄引起的 invalidOprationException。 要直接在线程 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;
        

【讨论】:

【参考方案4】:

您不需要取消线程。我会用代码来举例说明。

在闪屏表单中:

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

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

【讨论】:

感谢您向我展示了一种更好的方法。非常感谢建设性的反馈!【参考方案5】:

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

【讨论】:

从我嘴里说出来的话 ;-) 我什至打算写 Thread.Abort() 是邪恶的,哈哈。【参考方案6】:

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

【讨论】:

【参考方案7】:

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

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

这部分要特别注意:

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

【讨论】:

我正要发布这个。也就是说,他想做的事,很可能是不可能的。【参考方案8】:

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

的调用
    try
    
        Program.splashThread.Abort();
    
    catch(ThreadAbortException ex)
    
        Thread.ResetAbort();
    

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

【讨论】:

如果我关闭 Splash Form 并且这就是线程所做的所有事情,那会处理我的线程吗?

以上是关于如何抑制 thread.abort() 错误 C#?的主要内容,如果未能解决你的问题,请参考以下文章

C# - 线程中止异常(Thread Abort Exception)重新抛出自身

c# .net 一条线程 abort 之后,怎么重启启动。

如何在 C# 中立即杀死一个线程?

C#:有啥方法可以抑制编译器错误,类似于抑制警告消息?

Thread.Abort()方法冻结

Thread.Abort() 并在 finally 之后延迟