5

我正在使用一个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 中。我可以添加一个额外的锁(信号量)arroundConsumeItemCompleteAdding+Dispose但我尽量避免这种性能影响。

如何在没有任何例外的情况下添加项目?如果添加已完成,丢失物品会很好。

4

0 回答 0