我正在使用一个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
但我尽量避免这种性能影响。
如何在没有任何例外的情况下添加项目?如果添加已完成,丢失物品会很好。