【问题标题】:C# Thread Termination and Thread.Abort()C# 线程终止和 Thread.Abort()
【发布时间】:2011-01-16 03:43:44
【问题描述】:

在 MSDN 中,Thread.Abort() 方法的描述说:“调用此方法通常会终止线程。”

为什么不总是?

在哪些情况下它不会终止线程?

还有其他可能终止线程吗?

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    FileStream.Read() 到当前未接收任何内容的命名管道(在等待传入数据时读取调用块)将不会响应 Thread.Abort()。它保留在 Read() 调用中。

    【讨论】:

      【解决方案2】:

      我似乎无法中止陷入循环的线程:

      //immortal
      Thread th1 = new Thread(() => { while (true) {}});
      

      如果在循环期间休眠,我可以中止线程:

      //mortal
      Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});
      

      【讨论】:

      • 这似乎不是真的,我运行了一个测试程序:`{var th = new Thread(() => { int i = 0; try { while (true) { i++; } } catch(Exception e) { Console.WriteLine("aborting@ {0}", i); } }); th.Start();线程.睡眠(1000); th.Abort(); th.Join(); }
      【解决方案3】:

      在哪些情况下它不会终止线程?

      这个问题是重复的。

      What's wrong with using Thread.Abort()

      还有其他终止线程的可能性吗?

      是的。你的问题是你不应该启动一个你不能礼貌地停止的线程,它会及时停止。如果您必须启动一个线程,该线程可能 (1) 难以停止,(2) 有错误,或者最糟糕的是 (3) 对用户怀有敌意,那么正确的做法是让一个新进程,在新进程中启动线程,然后终止进程,当您希望线程停止运行时。唯一能保证不合作线程安全终止的是操作系统取消其整个进程。

      有关详细信息,请参阅我对这个问题的过长回答:

      Using lock statement within a loop in C#

      相关的部分是最后我讨论的关于在中止线程之前应该等待线程杀死自己多长时间的注意事项。

      【讨论】:

      • Eric,如果线程正在等待同步对象,我应该如何礼貌地告诉线程停止,例如EventWaitHandle.WaitOne();?
      • @Corvin:描述一个线程如何与另一个线程通信的两个线程之间的契约取决于在这些线程上运行的代码的作者。如果您的要求是(1)线程 X 必须永远等待一个对象,并且(2)线程 Y 必须能够在有限的时间内干净地关闭线程 X,那么我认为您的要求是矛盾的;决定哪一方获胜。如果是前者,那么线程 Y 将不得​​不等待。如果是后者,那么线程 X 不应该永远等待,它应该等待一小段时间。
      • 感谢您的回答。考虑以下架构:我有一个应用程序,当某个系统范围的事件发生时,它必须将自身最小化。我在该应用程序中有一个线程等待全局命名事件并在设置该事件时执行其工作。另一方面,我的应用程序可能必须在事件发生之前退出,不得不关闭那个等待线程。编写这种东西的武士方式是什么?
      • @Corvin:你可以有一个循环等待事件(有一个短暂的超时),然后检查它是否应该停止尝试等待(这样它就可以正常退出)。这样,您可以向您的线程发出它应该停止的信号,并且您只需等待超时即可停止。
      • @Corvin,如果你让那个等待线程成为后台线程,那么你不应该在应用程序退出之前关闭它。
      【解决方案4】:

      因为您可以在处理程序中捕获 ThreadAbortException 并调用 Thread.ResetAbort。

      【讨论】:

        【解决方案5】:

        Thread.Abort() 在线程上注入 ThreadAbortException。线程可以通过调用Thread.ResetAbort() 来取消请求。此外,还有某些代码部分,例如 finally 块,将在处理异常之前执行。如果由于某种原因线程卡在这样的块中,则永远不会在线程上引发异常。

        由于调用者在调用Abort() 时对线程的状态几乎没有控制权,因此一般不建议这样做。而是将消息传递给请求终止的线程。

        【讨论】:

        • 什么样的消息?你的意思是方法调用吗?
        • 这取决于您如何在线程之间传递数据。例如。如果您的线程是带有任务队列的工作线程,您可以将 PleaseTerminate 消息排队并让线程优雅地处理它。
        • 我的线程有一个大问题需要解决,就是没有任务队列。
        • 正如我所说,这取决于你的线程代码是如何设计的。也许你可以通过一个成员变量发出信号。如果没有可用的实际代码,很难更具体。
        【解决方案6】:

        如果线程持有锁并被中止/终止怎么办?资源仍然卡住

        当线程调用时它工作正常 中止自身,但不被其他线程中止。 中止,强行终止 受影响的线程,即使它没有 完成了任务并且没有提供 清理的机会 资源

        参考MSDN


        见:Managed Threading Best Practices

        【讨论】:

          【解决方案7】:

          ThreadAborts 不会发生在 finally 块内或 BeginCriticalRegion 和 EndCriticalRegion 之间

          【讨论】:

            【解决方案8】:

            OT:有关并发性的全面、与语言无关、有问题且非常有趣的观点,请参阅Verity Stob!

            【讨论】:

              【解决方案9】:

              我遇到过线程太忙而无法听到 Abort() 调用的情况,这通常会导致 ThreadAbortingException 被抛出到我的代码中。

              【讨论】:

                【解决方案10】:

                为什么不总是? 在哪些情况下它不会终止线程?

                对于初学者,线程可能会捕获ThreadAbortException 并取消它自己的终止。或者它可以执行一个计算,当你试图中止它时,它会永远持续下去。正因为如此,运行时不能保证线程在你要求它之后总是会终止。

                ThreadAbortException还有更多:

                当调用 Abort 方法来销毁线程时,公共语言运行时会引发 ThreadAbortException。 ThreadAbortException 是一个可以被捕获的特殊异常,但它会在 catch 块结束时再次自动引发。当引发此异常时,运行时会在结束线程之前执行所有 finally 块。 由于线程可以在 finally 块中进行无限计算,或调用 Thread.ResetAbort() 取消中止,因此无法保证线程永远结束。

                您不需要手动Abort() 一个线程。如果您简单地让线程中的方法返回,CLR 将为您完成所有繁琐的工作;这将正常结束线程。

                【讨论】:

                • 我确实需要 Abort() 它,因为在该线程 (Dispatcher.Run();) 上启动了一个消息循环。如果我理解正确的话,我需要在线程中调用一个调用 return 的方法来完成它吗?
                猜你喜欢
                • 1970-01-01
                • 2023-03-26
                • 2015-11-22
                • 1970-01-01
                • 2021-12-17
                • 1970-01-01
                • 1970-01-01
                • 2011-05-20
                相关资源
                最近更新 更多