【问题标题】:Keep threads idle or kill them / restart them?保持线程空闲或杀死它们/重新启动它们?
【发布时间】:2009-11-07 22:03:54
【问题描述】:

伪情况:有一个类(比如说BackgroundMagic),它有Start() 和Stop() 方法。这个类中的工作是由一个线程完成的,并且只是每 X 毫秒一个短循环。

就管理停止/启动而言,这些选项中哪个更好?无法决定走哪条路。

  1. 第一次调用 Start() 时,使用IsBackground = true 初始化并启动线程。 在每个循环中使用一个简单的 bool 标志来指示它是否应该实际执行任何工作,或者只是休眠。 初始初始化后,让 Stop() 和 Start() 简单地控制 bool 标志。线程只会被运行时停止和清理,因为当应用退出时IsBackground = true。
  2. 在 Stop 时强制中止/加入/中断/任何操作,并在 Start() 上重新创建线程,而不是让线程闲置。

...或任何更好/更清洁的方法?

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    没有!使用Thread Pool!

    【讨论】:

      【解决方案2】:

      线程创建相当昂贵,因此标准的“工业强度”方法是使用标志控制线程。对于相同想法的更大规模变体,请考虑线程池,例如Apache 用于管理数千个线程,而无需大量显式状态或痛苦的性能损失。

      所以在摘要中,我会投票给你的选项#1。但是,如果性能不是问题,并且选项 #2 的代码更容易推理,那就去吧。

      【讨论】:

        【解决方案3】:

        互斥锁或信号量比简单的布尔标志更好,因为它不需要反复检查标志的状态。只需阻塞 mutex/semaphore,当您希望线程运行时,释放 mutex/semaphore,线程将运行一次。

        【讨论】:

          【解决方案4】:

          线程池不适合长时间运行的任务。线程池非常适合短任务,其中线程创建的开销会大大增加操作的开销。 .NET 4 框架中的 TPL(任务并行库)也是如此。

          使用专门的线程来完成这项工作可能是个好主意,但如何管理它可能很重要。如果您只是在检查工作之间执行Thread.Sleep,那么效率会降低,因为现在您没有充分的理由让线程旋转。这被称为自旋锁(一种),只有当您知道您正在等待的资源将很快释放锁时才有效。使用AutoResetEvent 会更好。这样线程只会被唤醒,因为生产者线程表示有工作要做。这样做的好处是在无事可做时不会浪费 CPU 资源来调度线程,并且可以减少生产者和消费者之间的延迟。

          要直接回答您的问题,是的,您可以使用某种bool 来优雅地关闭线程(不过我会将其标记为volatile)。这比中止线程要好得多!

          见:

          【讨论】:

            【解决方案5】:

            您还可以使用 bool 标志来指示线程是否应该停止。这为您提供了中断和停止代码。所以两个布尔值,一个用于是否有工作,一个用于停止循环。

            您可以考虑的另一件事是使用 Dispose 模式并在释放对象时清理线程。

            【讨论】:

              【解决方案6】:

              我会使用 bool 标志,但您需要确保它被正确锁定或仅从一个线程设置。你的循环应该是这样的

              while (true)
              {
                if (shouldSleep)
               {
                 Thread.Sleep(interval);
                 continue;
               }
              
                doSomeWork();
              
               if (shouldCancel)
               {
                 CleanUpResources();
                 break;
               }
              }
              

              这确保您可以将线程发送到睡眠状态,但也可以正确终止它。如果您可以避免它,那么杀死线程绝不是一个好主意,因为线程没有机会清理使用的任何资源。不过,您需要决定适当的睡眠间隔。它将确定您的线程需要启动的延迟时间。

              第二个选项比较昂贵,线程创建涉及一些操作系统资源,启动时间也相当长。如果线程重新创建不会经常发生并且执行的工作量足够大,这将是合理的。您可以避免循环方法中涉及的复杂性。

              【讨论】:

                猜你喜欢
                • 2013-10-14
                • 1970-01-01
                • 2016-01-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-10-22
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多