我正在使用仅从一个线程填充并仅由一个线程使用的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
- 方法中。我可以添加一个额外的锁(信号量)arround ConsumeItem
和CompleteAdding
+ Dispose
,但我尽量避免这种性能影响。
如何添加项目,没有任何例外?如果添加完成,丢失的项目将会很好。