保持线程空闲或杀死它们/重新启动它们?

时间:2009-11-07 22:03:54

标签: c# multithreading

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

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

  1. 第一次调用Start()时,使用IsBackground = true初始化并启动线程。 使用一个简单的bool标志来指示每个循环是否应该实际执行任何工作,或只是睡眠。初始初始化后,让Stop()和Start()简单地控制bool标志。当应用程序退出时,IsBackground = true,线程将被运行时停止并清理。
  2. 强制中止/加入/中断/停止上的任何内容,并在Start()上重新创建线程,而不是让线程处于此处。
  3. ......或者更好/更清洁的方式吗?

6 个答案:

答案 0 :(得分:9)

既不!使用Thread Pool!

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

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

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

请参阅:

答案 4 :(得分:1)

您还可以使用bool标志来指示线程是否应该停止。它为您提供中断和停止代码。因此,如果有工作,则有两个用于停止循环。

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

答案 5 :(得分:1)

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

while (true)
{
  if (shouldSleep)
 {
   Thread.Sleep(interval);
   continue;
 }

  doSomeWork();

 if (shouldCancel)
 {
   CleanUpResources();
   break;
 }
}

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

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