2010-04-22 18 views
2

是否有相當於Monitor.PulseMonitor.Wait,我可以結合使用ReaderWriterLockSlimReaderWriterLockSlim和脈衝/等待

我有一個類,我已經封裝了對底層隊列的多線程訪問。爲了排隊,我獲得了一個保護底層隊列的鎖(以及一些其他對象),然後添加該項並鎖定對象以表示某些內容已添加到隊列中。

public void Enqueue(ITask task) 
{ 
    lock (mutex) 
    { 
     underlying.Enqueue(task); 
     Monitor.Pulse(mutex); 
    } 
}

在隊列的另一端,我有一個後臺線程,當它們到達隊列時不斷處理消息。當隊列中沒有項目時使用Monitor.Wait,以避免不必要的輪詢。 (我認爲這是很好的設計,但(在合理範圍內)任何火焰的歡迎,如果他們幫助我,否則學習。)

private void DequeueForProcessing(object state) 
{ 
    while (true) 
    { 
     ITask task; 
     lock (mutex) 
     { 
      while (underlying.Count == 0) 
      { 
       Monitor.Wait(mutex); 
      } 
      task = underlying.Dequeue(); 
     } 
     Process(task); 
    } 
}

隨着越來越多的業務都加入到這一類(需要只讀訪問鎖受保護的基礎),有人建議使用ReaderWriterLockSlim。我以前從未使用過這個課程,並且假設它可以提供一些性能優勢,但我並不反對它,但前提是我可以保留Pulse/Wait設計。

+1

對於反饋...我不會認爲從'Wait'喚醒意味着「有數據」;我會打'繼續;'並再次檢查。這種方法使得稍後添加停止/排放設施更容易。如果您添加到以前爲空的隊列,您也可能只想要「脈衝」;否則,什麼都沒有在等待。 – 2010-04-22 15:55:35

+0

我喜歡在將單個項目添加到隊列後執行脈衝的想法。然而,我還有一些關於我的代碼的疑問(以及我應該,它是多線程的)以及計數隊列中項目的效率並將該值與0進行比較(我希望它不會走路一個鏈接列表來做計數)。我想我應該真的調用PulseAll以防萬一它是另一個接收單脈衝的寫線程。 – Jono 2010-04-22 21:14:01

+0

我同意'PulseAll'。請參閱「計數」,請參閱文檔:http://msdn.microsoft.com/en-us/library/fy0wwyz4.aspx「檢索此屬性的值是O(1)操作。」;含義:不,它不這樣做 - 它分開知道「Count」。 – 2010-04-22 21:32:27

回答

0

張望了一下打後(並接受馬的攻擊後(我同意,我的變化是不完全的基礎)),我想出了這個組合:

ReaderWriterLockSlim rwls; 
AutoResetEvent are;
public void Enqueue(ITask task) { 
    rwls.EnterWriteLock(); 
    try { 
     underlying.Enqueue(task); 
     if (underlying.Count == 1) { 
      are.Set(); 
     } 
    } finally { 
     rwls.ExitWriteLock(); 
    } 
}
private void DequeueForProcessing(object state) { 
    while (true) { 
     ITask task; 
     rwls.EnterWriteLock(); 
     try { 
      while (underlying.Count == 0) { 
       rwls.ExitWriteLock(); 
       are.WaitOne(); 
       rwls.EnterWriteLock(); 
      } 
      task = underlying.Dequeue(); 
     } finally { 
      rwls.ExitWriteLock(); 
     } 
     Process(task); 
    } 
}

要我未經訓練的眼睛,它似乎符合法案(雖然它有點醜陋,可以肯定),它與原始版本沒有太大差別。

1

不,基本上。它被優化以提供一些特定/常見的場景。如果你超出這些場景,它將無法工作。如果您需要Pulse等,請改爲使用Monitor

+0

是否有任何其他內置.NET機制可以將當前線程放回等待隊列中的鎖,或者是什麼監視器? – Jono 2010-04-22 22:20:07

+0

@Jono - 'Monitor.Wait' – 2010-04-22 22:53:30