1

我有两个后台线程和一个线程来处理在我的 WinForms 应用程序上运行的最小化。当程序关闭时,我使用这种方法。

private void MyForm_Closing(object sender, FormClosingEventArgs e)
    {
        if(labelsUpdaterThread.IsAlive == true)
            labelsUpdaterThread.Abort();
        if(printNotifyThread.IsAlive == true)
            printNotifyThread.Abort();
        if(minimizeThread.IsAlive == true)
            minimizeThread.Abort();
    }

labelsUpdaterThread 和 printNotifyThread 一直在运行。正如您可能猜到的那样,MinimizeThread 仅在父窗体最小化时运行。这是我的问题:

当我在上面的方法中调用 thread.abort 方法时,我的 MdiParent 表单右上角的“X”不做任何事情。点击它没有效果。

When the thread.abort methods are NOT called in my above method, closing the MdiParent will sometimes throw exceptions because the Threads are still trying to access resources on the MdiParent that are no longer available, even though they are background threads!

I'm unsure as to why this is happening, doesn't make much sense to me. Thanks in advance for any help!

4

3 回答 3

4

我同意Paul Alexander 的回答,因为您永远不应该调用Thread.Abort,这是一种处理同步的可怕方式。

此外,您在这里有一个可怕的关注点分离。线程不应直接访问表单中的资源。两者之间应该有某种抽象/共享状态,双方(线程和表单,因此请确保使实例线程安全)对其进行修改和读取。

也就是说,如果您无法在 Close 方法中进行这些更改,请Thread.Abort在另一个线程中调用这些方法,并在每个方法周围使用 try/catch 语句。至少在某处记录错误。

在另一个线程上执行调用时Thread.Abort,不要阻塞 UI 线程,因为Thread.Abort不能保证调用是即时的,阻塞 UI 线程会导致 X 变灰,而 UI 线程无法处理 Windows 消息(它还有助于指导您更好地分离关注点)。

但是,您应该抽象出表单和线程之间共享的资源,并提供适当的取消机制。

如果您将资源抽象到共享状态的类中,那么您的表单不必在关闭时执行任何操作,线程调用堆栈具有对具有状态的对象的引用,然后您可以在这些线程上调用 abort不用担心表单和线程共享任何东西。

然后,您可以从那里引入适当的合作取消机制(合作取消,Task 在 .NET 4.0 中支持,如果您可以使用的话)。

于 2011-01-04T21:48:25.307 回答
0

首先,删除对 .Abort() 的调用,不再使用它们。线程不应该通过调用 Abort 来终止。它基本上使您的线程崩溃,并且没有机会正确释放任何资源或释放任何系统句柄。而是创建一个ManualResetEvent并在您的线程中检查它。设置事件后,它们应该终止。

线程1

while( ! _stopEvent.WaitOne(0) )
{
  ...do my thready work

}

然后在关闭

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
  _stopEvent.Set();
  labelsUpdaterThread.Join();
  ...
}

如果您不关心线程是否在应用程序存在时正确终止,只需设置IsBackground = true,它们将在应用程序退出时自动终止。

于 2011-01-04T21:21:56.960 回答
0

Abort 调用可能会引发异常。在调用 abort 之前,确保指针有效并且线程仍然有效(未释放)。

并且,在 Visual Studio 中,打开 Debug\Exceptions... 并在“抛出”列中设置检查所有异常,以便您查看何时出现问题。

于 2011-01-04T21:18:08.127 回答