我有一个包装ConcurrentDictionaryWrapper并实现ConcurrentDictionary<K,V>接口的IProducerConsumerCollection类,因此我可以将其与BlockingCollection一起使用。生产者将使用键将值添加到BlockingCollection中。想法是,如果键存在,我们将替换基础字典中的值。我的ConcurrentDictionaryWrapper.TryAdd()方法如下:public bool TryAdd(KeyValuePair<TKey, TValue> item){ _wrapped[item.Key] = item.Value return true;}我看到的问题是,如果替换了该值,则BlockingCollection会将其视为添加项。var wrapper = new ConcurrentDictionaryWrapper<string, object>();var bc = new BlockingCollection<KeyValuePair<string, object>>(wrapper);bc.TryAdd(new KeyValuePair<string, object>("key", new object()));bc.TryAdd(new KeyValuePair<string, object>("key", new object()));wrapper.Count; # returns 1bc.Count; # returns 2我不能在上面的TryAdd()中返回false,因为BlockingCollection将引发InvalidOperationException。有没有办法实现我想要的行为?我希望这尽可能简单,但是似乎没有办法通过实现IProducerConsumerCollection来使BlockingCollection具有这种“ AddOrUpdate”行为。我想避免在BlockingCollection上调用TryTake()之前不必TryAdd() -我可能只在Dictionary周围使用标准锁,并将生产者/消费者与AutoResetEvent同步。 最佳答案 这里有很大的摩擦,BlockingCollection 保持其自己的计数,并且不使用您的IProducerConsumerCollection.Count实现。因此,由于您没有使TryAdd()失败,因此BlockingCollection现在确信集合中有两项。即使您只能检索其中之一。因此,您当然不能按原样保留它,您的代码将始终死锁。您需要的是一个BlockingCollection方法,如果该项目已经存在,则该方法返回false或静默失败。但是它没有一个,InvalidOperationException是不可避免的。您可以抓住它,但是那很难看。替代方法是一个Contains()方法,如果该方法返回true,则可以使用该方法避免调用TryAdd()。但是现在该集合不再是线程安全的。这就是为什么BlockingCollection没有该方法的原因。这是一个坎and而艰辛的地方,您无法使其按预期工作。您必须自己旋转。最好窃取线程主控器的代码,this magazine article中的有界缓冲区应该是一个正确的锁设计的好开始。关于c# - C#如何更新BlockingCollection <T>中的元素?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20658271/
10-08 22:26