BlockingCollection <t> .GetConsumingEnumerable()在附加条件下阻塞</t>

时间:2013-10-01 08:19:46

标签: c# .net task-parallel-library ienumerable blockingcollection

是否可以在BlockingCollection<T>流和其他一些条件上执行JobQueue(我的示例中为GetConsumingEnumerable())块执行?

我有条件availableSlots > 0,它只允许在有空位时使用项目。问题是当集合中有项目但条件为假时,foreach会无限循环。

我是否也无法在availableSlots > 0上阻止该集合?

foreach (var job in JobQueue.GetConsumingEnumerable())
{
    if(availableSlots > 0)
    {
        JobHandler jobHandler = job;

        Task.Factory.StartNew(() =>
        {
            ExecuteJob(jobHandler);
        });
    }
}

也许我错误地使用了这个集合。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:2)

如果要在值为0时阻止,则需要进行额外的同步。我认为适合您的解决方案是SemaphoreSlim,因为它完全符合您的需求:等待其值为0.

有了这个,代码看起来像:

SemaphoreSlim slotsSemaphore = new SemaphoreSlim(…);

…

foreach (var job in JobQueue.GetConsumingEnumerable())
{
    slotsSemaphore.Wait();

    JobHandler jobHandler = job;

    Task.Factory.StartNew(() =>
    {
        try
        {
            ExecuteJob(jobHandler);
        }
        finally
        {
            slotsSemaphore.Release();
        }
    });
}

答案 1 :(得分:0)

不确定这是最好的方法,但要推进我的选择。

为什么不等到它是真的?

while (availableSlots <= 0)
{
    Thread.Sleep(1);//arbitary sleep
}

JobHandler jobHandler = job;
...

或使用SpinWait

SpinWait.SpinUntil(() => availableSlots > 0);

JobHandler jobHandler = job;
...

第三个选项是使用ManualResetEventAutoResetEvent

signal.Waitone();

JobHandler jobHandler = job;
...

更改signal的值时设置availableSlots