Question

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!

Was it helpful?

Solution

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();
        }
    });
}

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top