静态信号量作为成员传递给Thread类instance = bug?

时间:2009-10-27 17:45:18

标签: c# multithreading windows-services garbage-collection

我们的代码库中有一些Windows服务项目遵循此模型,我只是想确保它不是错误。

在此模型中,至少有一个静态“计时器”类,由System.Timers.Timer管理,它从数据库中检索要处理的批量数据。 Semaphore初始化为静态成员。检索一批工作后,会生成一个新的工作线程实例来处理每个行或列表项,并且线程由父计时器类的静态信号量管理。

internal class BatchTimer
{
  private static Semaphore m_sem = new Semaphore(Settings.Default.ThreadCount, 
     Settings.Default.ThreadCount);
  private static System.Timers.Timer m_timer = new System.Timers.Timer();

  internal static void DoWork(object source, ElapstedEventArgs e)
  { 
    List<WorkRow> work = Work.GetBatch(Settings.Default.ObjectsPerIteration);
    foreach (WorkRow row in work)
    {
      WorkerThread worker = new WorkerThread
      {
        Semaphore = m_sem,
        Work = row
      };    
      Thread thread = new Thread(worker.Run);
      // Release() is called in finally block of WorkerThread.Run.
      m_sem.WaitOne(); 
      thread.Start();
    }
  }
}

来自timer类的静态Semaphore被传递给工作线程类的成员,而不是让工作线程在父计时器类的信号量上调用Release()。我认为它可以工作,因为它是一个参考类型。但我的问题是,这不会阻止垃圾收集吗?

1 个答案:

答案 0 :(得分:1)

基本上,只要您调用worker.Run的线程正在运行,您就有了GCRoot给worker。当Run方法结束时,worker是垃圾收集的候选者(因为它不再在主线程中引用,也不在任何工作线程中引用)。

工作者获取对互斥锁的引用,但是如果它是反过来的话(只有一个静态变量持有对工作者的引用),你只会遇到问题。

所以,基本上,GC会照顾你的工作人员。

如果您的某个工作人员阻止,您可能会遇到麻烦。你最终会有一个车队,或者更糟糕的是,如果你的所有工人都被困住了,根本就没有工作。我会在worker中实现一个超时,以确保它不会阻止整个过程。