2012-08-02 85 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