這是一個有趣的問題。這是我第一次見到有人要求阻止重複的阻止隊列。奇怪的是,我找不到你想要的東西在BCL中已經存在。我說這是奇怪,因爲BlockingCollection
可以接受IProducerConsumerCollection
因爲它具有TryAdd
方法被公佈爲能夠檢測到重複時失敗底層集合。問題是,我沒有看到IProducerConsumerCollection
的具體實現,防止重複。至少我們可以寫我們自己的。現在
public class NoDuplicatesConcurrentQueue<T> : IProducerConsumerCollection<T>
{
// TODO: You will need to fully implement IProducerConsumerCollection.
private Queue<T> queue = new Queue<T>();
public bool TryAdd(T item)
{
lock (queue)
{
if (!queue.Contains(item))
{
queue.Enqueue(item);
return true;
}
return false;
}
}
public bool TryTake(out T item)
{
lock (queue)
{
item = null;
if (queue.Count > 0)
{
item = queue.Dequeue();
}
return item != null;
}
}
}
,我們有我們IProducerConsumerCollection
不接受重複利用它我們可以這樣:
public class Example
{
private BlockingCollection<object> queue = new BlockingCollection<object>(new NoDuplicatesConcurrentQueue<object>());
public Example()
{
new Thread(Consume).Start();
}
public void Produce(object item)
{
bool unique = queue.TryAdd(item);
}
private void Consume()
{
while (true)
{
object item = queue.Take();
}
}
}
你可以不喜歡我實施NoDuplicatesConcurrentQueue
。如果您認爲您需要TPL收藏提供的低鎖性能,您當然可以自由使用ConcurrentQueue
或其他任何方式實施自己的產品。
更新:
我能夠今天早上來測試代碼。有一些好消息和壞消息。好消息是,這將在技術上起作用。壞消息是,你可能不希望這樣做,因爲BlockingCollection.TryAdd
攔截來自底層IProducerConsumerCollection.TryAdd
方法的返回值,當檢測false
拋出異常。是的,那是對的。它不會像您所期望的那樣返回false
,而是會生成一個異常。我必須說實話,這是令人驚訝和可笑的。 TryXXX方法的重點在於它們不應該拋出異常。我深感失望。
如果有這樣的方法,那麼它將不得不是一個單一的原子方法。它永遠不會被執行,因爲你的兩個摘錄是因爲anothe線程可能會在TryPeek和Add之間添加。我認爲你運氣不好。無論如何,你爲什麼需要這樣的能力? –
在我的情況下,如果另一個線程在trypeek和add之間添加,則可以。我主要是這樣做的,作爲安全檢查,調度程序在多個線程(因此有多個生產者)觸發報告生成觸發器。如果無論出於何種原因調度程序出現故障並且在短時間內多次觸發相同的觸發器,我只想處理。明白我可以解決並以某種方式處理它。看起來好像沒有優雅的處理方式。謝謝 – Gullu