如何在没有竞争条件和异常的情况下检测BlockingCollection的AddingCompleted?

Seb*_*ann 6 c# multithreading race-condition blockingcollection

我使用的BlockingCollection{T}是仅由一个线程填充且仅由一个线程消耗的线程。生产和消费物品运行良好。问题出在这个操作的最后。任务在 处阻塞(如预期)GetConsumingEnumerableCompleteAdding调用任务后将处理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);
    }
}
Run Code Online (Sandbox Code Playgroud)

是的,我知道这段代码没有意义,因为几乎没有机会添加任何项目,并且 foreach 循环没有注意到。消耗任务对我的问题来说并不重要。

问题如ConsumeItem-method 所示。我可以添加一个额外的锁(信号量)ConsumeItemCompleteAdding+ Dispose,但我试图避免这种性能影响。

如何添加项目而不出现任何异常?如果添加完成,丢失物品也没关系。