.net 表单关闭时调用thread.Abort()可以吗?如果不是,那么全球旗帜是否足够好?

.net 表单关闭时调用thread.Abort()可以吗?如果不是,那么全球旗帜是否足够好?,.net,multithreading,threadabortexception,thread-abort,.net,Multithreading,Threadabortexception,Thread Abort,首先,Thread.Abort()是邪恶的-明白了!现在让我解释一下我的情况 情况: 我有一个只向用户显示当前运行状态的仪表板。它对Sql Server DB执行各种select查询,并执行一些计算,最终在仪表板上显示给用户。用户可以同时打开多个仪表板。我有一个计时器线程,每隔几秒钟刷新一次仪表板。该计时器线程生成另一个线程(实际上是对线程池中的工作进行排队)以执行长时间运行的计算/查询 问题: 当用户单击X关闭仪表板窗口时,它需要立即关闭(比如在一秒钟内,我认为2秒钟太长)。所以我使用这个代码

首先,Thread.Abort()是邪恶的-明白了!现在让我解释一下我的情况

情况:

我有一个只向用户显示当前运行状态的仪表板。它对Sql Server DB执行各种select查询,并执行一些计算,最终在仪表板上显示给用户。用户可以同时打开多个仪表板。我有一个计时器线程,每隔几秒钟刷新一次仪表板。该计时器线程生成另一个线程(实际上是对线程池中的工作进行排队)以执行长时间运行的计算/查询

问题:

当用户单击X关闭仪表板窗口时,它需要立即关闭(比如在一秒钟内,我认为2秒钟太长)。所以我使用这个代码:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        _timerThread.Abort();
    }

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // we're on the timer thread now

        try
        {
            RefreshUi();
        }
        catch (ThreadAbortException)
        {
            System.Threading.Thread.ResetAbort();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
问题是有时捕获到ThreadAbortException,有时则没有。我发现,在执行查询的过程中,这几乎是不起作用的。

[更新]我最近发现,如果检查innerexception,我可以捕获ThreadAbortException

问题:

  • 在这种情况下可以使用Thread.Abort()吗?如果是这样,我如何始终捕获ThreadAbortException,以便用户在关闭表单时看不到它?(据我所知,我认为这是不可能的)
  • 如果使用Thread.Abort()不合适(我想你们中的大多数人都会回答这个问题),那么下面是关于使用“全局布尔标志”来告诉线程何时关闭的其他问题。
    • 我担心线程不会在1秒的时间限制内自行停止。(例如,我可能有一些查询需要1-2秒才能运行)
    • 我将不得不用:if(shouldShutdown)语句来混乱我的代码
    • 我是否应该将shouldShutdown标志设置为静态,以便我的所有类都可以使用它?如果用户可以同时打开多个仪表板,这会造成问题吗?(我担心静态变量会在所有仪表板上共享。这是我绝对不想要的。)
    • 当工作线程看到它们必须关闭时,它们应该抛出异常还是返回?如果它们只是返回,那么我必须添加更多的If(shouldShutdown)检查,因为有些函数返回false是可以的。如果抛出异常是可以的,那么您建议使用哪种异常?定制的

  • 谢谢

    正确的方法是

  • 使对SQL server的所有请求都是异步的
  • 在后台线程中处理
    ManualResetEvent
    并在关闭时从主线程触发
  • 中断
    AutoResetEvent
    处理程序中的sql请求并正常退出线程
  • 使GUI在退出线程的同时关闭窗口,这样它们就不会相互依赖
  • 如果关闭仪表板意味着退出进程,那么最好在关闭窗口时等待所有线程退出
    您的捕获代码错误。您正在中止工作线程,而不是UI线程。我看不出立即关闭(关闭仪表板)如何连接到后台线程?在窗口关闭后,让他们使用
    AutoResetEvent
    优雅地结束。@Anri说得对。我假设由于表单创建了线程,它们必须先完成,然后才能关闭。但我猜你是说他们不必。1)你是说使用BeginInvoke()?我已经在做了。2) ManualResetEvents不适合暂停线程而不是终止线程吗?3) 你是怎么做到的?4) 你是说因为我已经在使用线程了,所以表单可以关闭而不用先终止线程吗?5) 如果仪表板关闭,进程/应用程序不会终止。1。我的意思是
    SqlCommand.BeginExecuteReader
    或您用来获取数据的任何东西。2.执行异步sql查询时线程在做什么?右-正在等待,但仍在侦听来自控制线程的消息,该线程应停止等待并开始中止sql请求。对于其他情况(不是sql),它可以用于检查事件(设置/未设置)的状态,而无需等待。4.我是说FormClosing事件处理程序应该触发线程关闭过程,而不是等待它们完成。