I have multiple producers and a single consumer. However if there is something in the queue that is not yet consumed a producer should not queue it again. (unique no duplica
In addition to the caveat Brian Gideon mentioned after Update, his solution suffers from these performance issues:
queue.Contains(item)
) have a severe impact on performance as the queue growsThe following code improves on Brian's solution by
System.Collections.Concurrent
namespaceN.B. As there is no ConcurrentHashSet
, I'm using a ConcurrentDictionary
, ignoring the values.
In this rare case it is luckily possible to simply compose a more complex concurrent data structure out of multiple simpler ones, without adding locks. The order of operations on the 2 concurrent data structures is important here.
public class NoDuplicatesConcurrentQueue : IProducerConsumerCollection
{
private readonly ConcurrentDictionary existingElements = new ConcurrentDictionary();
private readonly ConcurrentQueue queue = new ConcurrentQueue();
public bool TryAdd(T item)
{
if (existingElements.TryAdd(item, false))
{
queue.Enqueue(item);
return true;
}
return false;
}
public bool TryTake(out T item)
{
if (queue.TryDequeue(out item))
{
bool _;
existingElements.TryRemove(item, out _);
return true;
}
return false;
}
...
}
N.B. Another way at looking at this problem: You want a set that preserves the insertion order.