2012-08-02 67 views
2

我有这个生产者/消费者代码:Monitor.Pulse丢失信号?

MAIN:

static void Main() 
{ 
    using(PCQueue q = new PCQueue(2)) 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      int itemNumber = i; // To avoid the captured variable trap 
      q.EnqueueItem(() = > { 
       Thread.Sleep(1000); // Simulate time-consuming work 
       Console.Write(" Task" + itemNumber); 
      }); 
     } 
     Console.WriteLine("Enqueued 10 items"); 
     Console.WriteLine("Waiting for items to complete..."); 
    } 

} 

类:

public class PCQueue: IDisposable 
    { 
     readonly object _locker = new object(); 
     Thread[] _workers; 
     Queue <Action> _itemQ = new Queue <Action>(); 
     public PCQueue(int workerCount) 
     { 
      _workers = new Thread[workerCount]; 
      // Create and start a separate thread for each worker 
      for(int i = 0; i < workerCount; i++) 
      (_workers[i] = new Thread(Consume)).Start(); 
     } 
     public void Dispose() 
     { 
      // Enqueue one null item per worker to make each exit. 
      foreach(Thread worker in _workers) EnqueueItem(null); 
     } 
     public void EnqueueItem(Action item) 
     { 
      lock(_locker) 
      { 
       _itemQ.Enqueue(item); // We must pulse because we're 
       Monitor.Pulse(_locker); // changing a blocking condition. 
      } 
     } 
     void Consume() 
     { 
      while(true) // Keep consuming until 
      { // told otherwise. 
       Action item; 
       lock(_locker) 
       { 
        while(_itemQ.Count == 0) Monitor.Wait(_locker); 
        item = _itemQ.Dequeue(); 
       } 
       if(item == null) return; // This signals our exit. 
       item(); // Execute item. 
      } 
     } 
    } 

问:

比方说执行的item();需要很长的时间。

1) we enqueue a new work and pulse. (1 consumer is busy now) 
2) we enqueue a new work and pulse. (second consumer is busy now) 
3) we enqueue a new work and pulse. 

现在呢?两个线程都很忙!

know,脉冲会丢失(或不?)

是唯一的解决办法是将其更改为AutoResetEvent

+0

System.Collections.Concurrent.BlockingCollection有什么问题?如果你想DIY,你可以使用System.Threading.Semaphore和一个锁。对于生产者 - 消费者队列来说,事件并不是一个合适的解决方案 - 我不知道为什么如此之多的开发者被欺骗使用它们来达到这个目的。 – 2012-08-02 13:48:02

+0

@MartinJames没有错。我只想知道如何增强代码,并检查我的假设是否正确。 – 2012-08-02 13:49:07

+0

@MartinJames我猜你必须问Joe Albahari关于你的问题.http://books.google.co.il/books?id = VENrFSQFco8C&pg = PA846&lpg = PA846&dq =%22 + To + avoid + the + captured + variable +阱%22&源= BL&OTS = 3uV-ribX9Q&SIG = gjsMPGyZD6H-DgcwjR_vuv5V8aI&HL = EN&SA = X&EI = noUaUJKpLcem0QXHsYC4Cw&redir_esc = Y#v = onepage&q =%22%20To%20avoid%第二十条%20captured%20variable%20trap%22&F =假 – 2012-08-02 13:51:09

回答

3

现在呢?两个线程都很忙!
我知道脉冲会丢失(或不?)

是,当(全部)你的线程都忙于执行的项目()调用,脉冲会丢失。

但是这并不是一个问题,你在每个Enqueue()之后都是Pulsing,基本上只有当queue.Count从0变为1时才需要Pulse。你需要更多的脉冲。

但是,当您尝试优化脉冲数时,您可能会遇到麻烦。 等待/脉冲无状态的事实意味着你应该小心使用它。

+0

亨克,我不理解。 (抱歉)。 _基本上一个脉冲只有当队列_...确定即时排队,但脉冲丢失时需要....它可能导致一个工作项目没有得到治疗的情况。对? – 2012-08-02 13:59:48

+0

当没有人在等待,然后一个脉冲将会丢失,但它不需要反正...... – 2012-08-02 14:02:11

+0

愚蠢的我,我没看看while循环。它扫描直到它将为0,所以基本上我可以推动1000个项目只有2个脉冲,队列将被消化直到0.(对吧?) – 2012-08-02 14:20:42