我在這裏要求任何ConcurentSet/ConcurentQueue執行how to create no-duplicates ConcurrentQueue?,但沒有人提出任何建議。爲什麼我的ConcurentSet不起作用?
所以我決定自己寫了,稍微修改了MSDN例子。 我創建了ConcurentSet
類。我插入相同的元素兩次,並期望它只能插入一次,因爲Set
用於內部:
numbers.Add(i);
Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
numbers.Add(i);
Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
然而,根據兩次插入輸出要素:
Add:0 Count=0
Add:0 Count=1
Add:1 Count=2
Add:1 Count=3
Add:2 Count=4
Take:0
Add:2 Count=5
Add:3 Count=6
Add:3 Count=7
Add:4 Count=7
Add:4 Count=8
Take:3
Add:5 Count=9
Add:5 Count=10
Add:6 Count=11
Add:6 Count=12
的問題是 - 爲什麼我的ConcurentSet實現不按預期工作? 我希望這樣的輸出:
Add:0 Count=0
Add:0 Count=0
Add:1 Count=1
Add:1 Count=1
Add:2 Count=2
Take:0
Add:2 Count=1
Add:3 Count=2
Add:3 Count=2
Add:4 Count=3
Add:4 Count=3
Take:3
Add:5 Count=3
Add:5 Count=3
.....
完整清單如下:
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace BCBlockingAccess
{
using System;
using System.Collections.Concurrent;
public class ConcurentSet
: IProducerConsumerCollection<int>
{
private readonly object m_lockObject = new object();
private readonly HashSet<int> m_set = new HashSet<int>();
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public int Count { get { return m_set.Count; } }
public object SyncRoot { get { return m_lockObject; } }
public bool IsSynchronized { get { return true; } }
public void CopyTo(int[] array, int index)
{
throw new NotImplementedException();
}
public bool TryAdd(int item)
{
lock (m_lockObject)
{
m_set.Add(item);
}
return true;
}
public bool TryTake(out int item)
{
lock (m_lockObject)
{
foreach (var i in m_set)
{
if (m_set.Remove(i))
{
item = i;
return true;
}
}
item = -1;
return false;
}
}
public int[] ToArray()
{
throw new NotImplementedException();
}
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Program
{
static void Main(string[] args)
{
// Increase or decrease this value as desired.
int itemsToAdd = 50;
// Preserve all the display output for Adds and Takes
Console.SetBufferSize(80, (itemsToAdd * 5) + 3);
// A bounded collection. Increase, decrease, or remove the
// maximum capacity argument to see how it impacts behavior.
BlockingCollection<int> numbers = new BlockingCollection<int>(new ConcurentSet());
// A simple blocking consumer with no cancellation.
Task.Factory.StartNew(() =>
{
int i = -1;
while (!numbers.IsCompleted)
{
try
{
i = numbers.Take();
}
catch (InvalidOperationException)
{
Console.WriteLine("Adding was compeleted!");
break;
}
Console.WriteLine("Take:{0} ", i);
// Simulate a slow consumer. This will cause
// collection to fill up fast and thus Adds wil block.
Thread.SpinWait(100000);
}
Console.WriteLine("\r\nNo more items to take. Press the Enter key to exit.");
});
// A simple blocking producer with no cancellation.
Task.Factory.StartNew(() =>
{
for (int i = 0; i < itemsToAdd; i++)
{
numbers.Add(i);
Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
numbers.Add(i);
Console.WriteLine("Add:{0} Count={1}", i, numbers.Count);
}
// See documentation for this method.
numbers.CompleteAdding();
});
// Keep the console display open in debug mode.
Console.ReadLine();
}
}
}
Eiter某些東西非常壞或者你的測試代碼和輸出不匹配:在第一個Add()之後計數== 0? – 2011-05-01 11:56:00
@亨克,他使用'BlockingCollection',他將這個集合作爲構造函數的參數。所以當他調用Add()時,BlockingCollection 調用他的類的TryAdd()。 –
svick
2011-05-01 14:23:55
@svick,好的,謝謝,我錯過了。 – 2011-05-01 15:23:23