質問

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!

役に立ちましたか?

解決

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

他のヒント

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top