Reputation: 40022
Is it possible to have a BlockingCollection<T>
(JobQueue
in my example) block execution on both the GetConsumingEnumerable()
stream AND on some other criteria?
I have the condition availableSlots > 0
which only allows items to be consumed when there are available slots. The problem is that the foreach indefinitely loops when there are items in the collection but the condition is false.
Can I not get the collection to block on availableSlots > 0
as well?
foreach (var job in JobQueue.GetConsumingEnumerable())
{
if(availableSlots > 0)
{
JobHandler jobHandler = job;
Task.Factory.StartNew(() =>
{
ExecuteJob(jobHandler);
});
}
}
Perhaps I am using this collection incorrectly. Any help appreciated!
Upvotes: 0
Views: 1140
Reputation: 244797
If you want to block while the value is 0, you will need additional synchronization for this. I think the right solution for you is SemaphoreSlim
, because it does exactly what you need: waiting while its value is 0.
With that, the code would look something like:
SemaphoreSlim slotsSemaphore = new SemaphoreSlim(…);
…
foreach (var job in JobQueue.GetConsumingEnumerable())
{
slotsSemaphore.Wait();
JobHandler jobHandler = job;
Task.Factory.StartNew(() =>
{
try
{
ExecuteJob(jobHandler);
}
finally
{
slotsSemaphore.Release();
}
});
}
Upvotes: 2
Reputation: 73472
Not sure this is the best way, but putting my option forward.
Why not just wait until it is true?
while (availableSlots <= 0)
{
Thread.Sleep(1);//arbitary sleep
}
JobHandler jobHandler = job;
...
or use SpinWait
SpinWait.SpinUntil(() => availableSlots > 0);
JobHandler jobHandler = job;
...
Third option is to use ManualResetEvent
or AutoResetEvent
signal.Waitone();
JobHandler jobHandler = job;
...
And set the signal
when you change the value of availableSlots
.
Upvotes: 0