2013-04-10 270 views
3

我知道使用ConcurrentQueue的BlockingCollection的有限容量爲100.BlockingCollection最大尺寸

但是我不確定這是什麼意思。

我試圖實現一個併發緩存,如果隊列大小過大(即緩存溢出時出現鬆散消息),那麼可以在一個操作中進行dequeue,deque/enque操作。有沒有一種方法來使用boundedcapacity,或者是手動執行此操作還是創建新的集合更好?

基本上我有一個閱讀線程和幾個寫線程。如果隊列中的數據是所有編寫者的「最新」,我希望它。

+0

可能您需要提供有關最新數據的回饋事件嗎? – 2013-04-10 14:31:09

回答

1

N的有界容量意味着如果隊列中已經包含N個項目,則嘗試添加其他項目的任何線程都會阻塞,直到其他線程移除項目爲止。

你似乎想要的是一個不同的概念 - 你希望最近添加的項目成爲消費線程出列的第一個項目。

您可以通過使用ConcurrentStack而不是底層存儲的ConcurrentQueue來實現。您可以使用this constructor並通過ConcurrentStack

例如:

var blockingCollection = new BlockingCollection<int>(new ConcurrentStack<int>()); 

使用ConcurrentStack,可以確保每個項目的消費線程將出列在當時的隊列最新鮮的項目。

另請注意,如果您爲阻止集合指定了上限,則可以使用BlockingCollection.TryAdd(),如果該集合在您調用它時已滿,將返回false

+0

根據我的最新陳述是真實的。但是我仍然希望隊列按照它們入隊的順序進行分派。如果(q.count> x) {q.take(); // donothing} q.add(newitem) 在每次添加之前保留大小,似乎最好做一個 ,但如果另一個線程需要計算長度,然後最終消除不必要的消息 – maxfridbe 2013-04-10 15:17:37

+0

嗯,我不認爲我真的理解你的需求......但是,如果你指定阻塞集合的上限,你可以使用['BlockingCollection。 TryAdd()'](http://msdn.microsoft.com/en-us/library/dd267245.aspx),如果隊列已滿,它將返回false - 你能使用它嗎? – 2013-04-10 15:26:42

2

這聽起來像你正在嘗試構建像MRU(最近使用)緩存的東西。 BlockingCollection不是最好的方式來做到這一點。我會建議你改用LinkedList。它不是線程安全的,所以你必須提供自己的同步,但這並不難。您的排隊方法是這樣的:

LinkedList<MyType> TheQueue = new LinkedList<MyType>(); 
object listLock = new object(); 

void Enqueue(MyType item) 
{ 
    lock (listLock) 
    { 
     TheQueue.AddFirst(item); 
     while (TheQueue.Count > MaxQueueSize) 
     { 
      // Queue overflow. Reduce to max size. 
      TheQueue.RemoveLast(); 
     } 
    } 
} 

和出隊就更簡單了:

MyType Dequeue() 
{ 
    lock (listLock) 
    { 
     return (TheQueue.Count > 0) ? TheQueue.RemoveLast() : null; 
    } 
} 

,如果你想消費者做隊列非忙等待這是一個涉及多一點。你可以使用Monitor.WaitMonitor.Pulse。有關示例,請參閱Monitor.Pulse頁面上的示例。

更新:

它發生,我認爲你可以做同樣的事情用一個循環緩衝器(陣列)。只需保持頭部和尾部指針。你插入head並刪除tail。如果你去插入,並head == tail,那麼你需要增加tail,這有效地刪除了以前的tail項目。