I try to implement a ConcurrentDictionary
by wrapping it in a BlockingCollection
but did not seem to be successful.
I understand that one variable declarations work with BlockingCollection
such as ConcurrentBag<T>
, ConcurrentQueue<T>
, etc.
So, to create a ConcurrentBag
wrapped in a BlockingCollection
I would declare and instantiate like this:
BlockingCollection<int> bag = new BlockingCollection<int>(new ConcurrentBag<int>());
But how to do it for ConcurrentDictionary
? I need the blocking functionality of the BlockingCollection
on both the producer and consumer side.
Maybe you need a concurrent dictionary of 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();
By this way, a consumer which is expecting something in the mailbox 5, will wait until the productor puts a letter in the mailbox 5.
You'll need to write your own adapter class - something like:
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With