我正在使用一个BlockingCollection{T}仅由一个线程填充并仅由一个线程消耗的线程。生产和消费物品工作正常。问题出在此操作结束时。任务阻塞(如预期)在GetConsumingEnumerable。调用CompleteAdding任务后将处理BlockingCollection并完成,没有任何异常。到目前为止,一切都很好。
现在我有一个线程可以将项目添加到BlockingCollection. 该线程必须进行测试IsAddingCompleted,然后必须添加该项目。IsAddingCompleted但是在请求和添加项目之间存在竞争条件。有一个TryAdd- 方法,但如果添加已经完成,也会引发异常。
如何在没有附加锁的情况下添加已完成的项目或测试?为什么会TryAdd抛出任何异常?false如果添加已经完成,返回就可以了。
非常简化的代码如下所示:
private BlockingCollection<string> _items = new BlockingCollection<string>();
public void Start()
{
Task.Factory.StartNew(
() =>
{
foreach (var item in this._items.GetConsumingEnumerable())
{
}
this._items.Dispose();
});
Thread.Sleep(50); // Wait for Task
this._items.CompleteAdding(); // Complete adding
}
public void ConsumeItem(string item)
{
if (!this._items.IsAddingCompleted)
{
this._items.Add(item);
}
}
是的,我知道这段代码没有意义,因为几乎没有机会添加任何项目并且 foreach-loop 没有注意到。消费任务对我的问题无关紧要。
问题显示在ConsumeItem-method 中。我可以添加一个额外的锁(信号量)arroundConsumeItem和CompleteAdding+Dispose但我尽量避免这种性能影响。
如何在没有任何例外的情况下添加项目?如果添加已完成,丢失物品会很好。