2012-05-24 49 views
6

我嘗試通過將它包裝在BlockingCollection中來實現ConcurrentDictionary,但似乎沒有成功。如何在BlockingCollection中包裝ConcurrentDictionary?

我明白,一個變量聲明BlockingCollection如ConcurrentBag<T>ConcurrentQueue<T>工作等

因此,創建裹在BlockingCollection一個ConcurrentBag我想聲明和實例是這樣的:

BlockingCollection<int> bag = new BlockingCollection<int>(new ConcurrentBag<int>()); 

但如何爲ConcurrentDictionary做到這一點?我需要生產者和消費者兩方面的BlockingCollection的阻塞功能。

+0

詞典(和併發詞典)也不會保留項目的順序。你能描述你的生產者 - 消費者情景嗎? – Dennis

+0

@丹尼斯,我知道這一點。生產者在concurrentDictionary中存儲KeyValuePairs,並且消費者任務增加一個int值,並且如果int與相應的密鑰匹配,則刪除KeyValuePair。我這樣做是因爲工作任務使用值填充concurrentDictionary,但以任意順序,使用者任務確保接收到的值以正確的順序傳遞/處理。一個ConcurrentDictionary是否可以封裝在BlockingCollection中? –

+0

你提出了什麼解決方案?我試圖找到一個很好的解決方案來解決類似的問題,即生產者不按消費者所需的順序生產物品。 (舊帖子我知道,但值得一試) – Kim

回答

1

你需要編寫自己的適配器類 - 是這樣的:

public class ConcurrentDictionaryWrapper<TKey,TValue> : IProducerConsumerCollection<KeyValuePair<TKey,TValue>> 
{ 
    private ConcurrentDictionary<TKey, TValue> dictionary; 

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
    { 
     return dictionary.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public void CopyTo(Array array, int index) 
    { 
     throw new NotImplementedException(); 
    } 

    public int Count 
    { 
     get { return dictionary.Count; } 
    } 

    public object SyncRoot 
    { 
     get { return this; } 
    } 

    public bool IsSynchronized 
    { 
     get { return true; } 
    } 

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index) 
    { 
     throw new NotImplementedException(); 
    } 

    public bool TryAdd(KeyValuePair<TKey, TValue> item) 
    { 
     return dictionary.TryAdd(item.Key, item.Value); 
    } 

    public bool TryTake(out KeyValuePair<TKey, TValue> item) 
    { 
     item = dictionary.FirstOrDefault(); 
     TValue value; 
     return dictionary.TryRemove(item.Key, out value); 
    } 

    public KeyValuePair<TKey, TValue>[] ToArray() 
    { 
     throw new NotImplementedException(); 
    } 
} 
+1

感謝代碼建議。但是我使用BlockingCollection的主要目的是將集合標記爲「添加完成」並檢查其狀態以及是否添加完整和空白的功能,類似於BlockingCollection提供的功能。我知道我可以輕鬆地添加這樣的功能,但我正在尋找一個建議,如何直接通過BlockingCollection來完成。到目前爲止,我沒有看到它無法直接通過Blocking集合的原因。也許它只需要IProducerConsumerCollection ? –

4

也許你需要blockingCollection

 ConcurrentDictionary<int, BlockingCollection<string>> mailBoxes = new ConcurrentDictionary<int, BlockingCollection<string>>(); 
     int maxBoxes = 5; 

     CancellationTokenSource cancelationTokenSource = new CancellationTokenSource(); 
     CancellationToken cancelationToken = cancelationTokenSource.Token; 

     Random rnd = new Random(); 
     // Producer 
     Task.Factory.StartNew(() => 
     { 
      while (true) 
      { 
       int index = rnd.Next(0, maxBoxes); 
       // put the letter in the mailbox 'index' 
       var box = mailBoxes.GetOrAdd(index, new BlockingCollection<string>()); 
       box.Add("some message " + index, cancelationToken); 
       Console.WriteLine("Produced a letter to put in box " + index); 

       // Wait simulating a heavy production item. 
       Thread.Sleep(1000); 
      } 
     }); 

     // Consumer 1 
     Task.Factory.StartNew(() => 
     { 
      while (true) 
      { 
       int index = rnd.Next(0, maxBoxes); 
       // get the letter in the mailbox 'index' 
       var box = mailBoxes.GetOrAdd(index, new BlockingCollection<string>()); 
       var message = box.Take(cancelationToken); 
       Console.WriteLine("Consumed 1: " + message); 

       // consume a item cost less than produce it: 
       Thread.Sleep(50); 
      } 
     }); 

     // Consumer 2 
     Task.Factory.StartNew(() => 
     { 
      while (true) 
      { 
       int index = rnd.Next(0, maxBoxes); 
       // get the letter in the mailbox 'index' 
       var box = mailBoxes.GetOrAdd(index, new BlockingCollection<string>()); 
       var message = box.Take(cancelationToken); 
       Console.WriteLine("Consumed 2: " + message); 

       // consume a item cost less than produce it: 
       Thread.Sleep(50); 
      } 
     }); 

     Console.ReadLine(); 
     cancelationTokenSource.Cancel(); 

的併發字典通過這種方式,消費者這是期待着什麼在郵箱5中,將等到產品員在郵箱5中放入一個字母。