I have two BlockingCollection<T>
objects, collection1
and collection2
. I want to consume items from these collections giving priority to items in collection1
. That is, if both collections have items, I want to take items from collection1
first. If none of them have items, I want to wait for an item to be available.
I have the following code:
public static T Take<T>(
BlockingCollection<T> collection1,
BlockingCollection<T> collection2) where T:class
{
if (collection1.TryTake(out var item1))
{
return item1;
}
T item2;
try
{
BlockingCollection<T>.TakeFromAny(
new[] { collection1, collection2 },
out item2);
}
catch (ArgumentException)
{
return null;
}
return item2;
}
This code is expected to return null
when CompleteAdding
is called on both collections and they both are empty.
My main issue with this code is that the documentation for the TakeFromAny
method specifies that TakeFromAny
will throw an ArgumentException
if CompleteAdding
was called on "the collection":
ArgumentException
The collections argument is a 0-length array or contains a null element or CompleteAdding() has been called on the collection.
Does it throw if CompleteAdding
was called on any collection? or both collections?
What if CompleteAdding
was called and the collection still has some items, does it throw?
I need a reliable way to do this.
In this code I am trying to get from collection1
first because the documentation of TakeFromAny
does not give any guarantees about the collection order from which to take the item if the two collections have items.
This also means that if both collections are empty, and then they receive items at the same time later, then I might get an item from collection2
first, which is fine.
EDIT:
The reason I add items to two collections (and not simply a single collection) is that the first collection does not have an upper-bound, and the second collection does.
More details for those who are interested why I need this:
I am using this in an open source project called ProceduralDataflow. See here for more details https://github.com/ymassad/ProceduralDataflow
Each processing node in the dataflow system has two collections, one collection will contain items coming for the first time (so I need to slow down the producer if needed), and another collection will contain items coming for the second (or third,..) times (as a result of a loop in the data flow).
The reason why one collection does not have an upper-bound is that I don't want to have deadlocks as a result of loops in the dataflow.