2010-07-11 52 views
0

我注意到了一些我正在编写的代码中的一个常见模式,所以我决定将它提取到一个类中。然而,自从开始使用这个类以来,我一直在遇到一个问题,即每隔一段时间程序就会无限期地挂起,从调试中我可以看出,这个类似乎是原因。有时能告诉我我做错了什么?感谢您的时间。在线程池周围实现一个包装器

更新代码:

class ParallelTaskWaiter 
{ 
    int numTasksRunning; 
    private readonly object completeLock = new object(); 

    public void WaitFor(ThreadStart action) 
    { 
     Interlocked.Increment(ref numTasksRunning); 
     ThreadPool.QueueUserWorkItem(delegate 
     { 
      try { action(); } 
      finally 
      { 
       if (Interlocked.Decrement(ref numTasksRunning) == 0) 
       { 
        lock (completeLock) 
        { 
         Monitor.PulseAll(completeLock); 
        } 
       } 
      } 
     }); 
    } 

    public void Wait() 
    { 
     lock (completeLock) 
     { 
      if (Interlocked.CompareExchange(ref numTasksRunning, 0, 0) == 0) return; 
      Thread.SpinWait(1); 
      Monitor.Wait(completeLock, Timeout.Infinite); 
     } 
    } 
} 

回答

0

WAG这里...更改

if (Interlocked.Decrement(ref numTasksToComplete) == 0) 

if (Interlocked.Decrement(ref numTasksToComplete) <= 0) 

其更安全的赌注,不管是什么。

另外,当您将增量联锁时,您仍在递增排队工作项目。增量和排队应该是原子的。我也使用lock而不是互锁增量。

+0

这样做肯定会意味着其他地方有同步错误... – 2010-07-11 05:01:53

+0

@mitch WAG =野驴猜测。当然,很难从样本中调试多线程代码。但是,仍然在寻找东西。 – Will 2010-07-11 05:05:06

+0

感谢您的回复Will。对于你的答案的'lock'部分,你的意思是将一个私有对象成员添加到该类中,并在增量和QueueUserWorkItem上锁定该成员? – George 2010-07-11 05:10:05

1

难道不应该是:

private int numTasksToComplete = 0; 

没有开始与任务。

+0

没有,我认为这将是可能的一个线程完成,并发现Interlocked.Decrement(ref numTasksToComplete)== 0是真实的,即使还有更多的任务尚未添加。 – George 2010-07-11 05:05:34

+0

如果完全明显的答案是正确的,那将是非常可怕的。 – Will 2010-07-11 05:06:14

+0

@george更多地锁定而不是使用互锁递增/递减的原因。 – Will 2010-07-11 05:07:05