我正在嘗試構建自我更新集合。集合中的每個項目都有一個位置(x,y)。當職位更改時,會觸發一個事件,集合將重新定位該項目。自我更新集合併發問題
集合內部使用「鋸齒狀字典」。外部字典使用x座標一個鍵,而嵌套字典使用y座標一個鍵。嵌套字典然後將項目列表作爲值。
集合還維護一個字典,用於存儲存儲在嵌套字典中的項目位置 - 項目到存儲的位置查找。
我在收集線程安全,我真的需要一些麻煩。對於集合
的源代碼:
public class PositionCollection<TItem, TCoordinate> : ICollection<TItem>
where TItem : IPositionable<TCoordinate>
where TCoordinate : struct, IConvertible
{
private readonly object itemsLock = new object();
private readonly Dictionary<TCoordinate, Dictionary<TCoordinate, List<TItem>>> items;
private readonly Dictionary<TItem, Vector<TCoordinate>> storedPositionLookup;
public PositionCollection()
{
this.items = new Dictionary<TCoordinate, Dictionary<TCoordinate, List<TItem>>>();
this.storedPositionLookup = new Dictionary<TItem, Vector<TCoordinate>>();
}
public void Add(TItem item)
{
if (item.Position == null)
{
throw new ArgumentException("Item must have a valid position.");
}
lock (this.itemsLock)
{
if (!this.items.ContainsKey(item.Position.X))
{
this.items.Add(item.Position.X, new Dictionary<TCoordinate, List<TItem>>());
}
Dictionary<TCoordinate, List<TItem>> xRow = this.items[item.Position.X];
if (!xRow.ContainsKey(item.Position.Y))
{
xRow.Add(item.Position.Y, new List<TItem>());
}
xRow[item.Position.Y].Add(item);
if (this.storedPositionLookup.ContainsKey(item))
{
this.storedPositionLookup[item] = new Vector<TCoordinate>(item.Position);
}
else
{
this.storedPositionLookup.Add(item, new Vector<TCoordinate>(item.Position)); // Store a copy of the original position
}
item.Position.PropertyChanged += (object sender, PropertyChangedEventArgs eventArgs) => this.UpdatePosition(item, eventArgs.PropertyName);
}
}
private void UpdatePosition(TItem item, string propertyName)
{
lock (this.itemsLock)
{
Vector<TCoordinate> storedPosition = this.storedPositionLookup[item];
this.RemoveAt(storedPosition, item);
this.storedPositionLookup.Remove(item);
}
this.Add(item);
}
}
我寫了一個簡單的單元測試,以檢查併發問題:
[TestMethod]
public void TestThreadedPositionChange()
{
PositionCollection<Crate, int> collection = new PositionCollection<Crate, int>();
Crate crate = new Crate(new Vector<int>(5, 5));
collection.Add(crate);
Parallel.For(0, 100, new Action<int>((i) => crate.Position.X += 1));
Crate same = collection[105, 5].First();
Assert.AreEqual(crate, same);
}
實際存儲的位置變化我每次運行測試時間。我很感激你可能有的任何反饋。
似乎並沒有多個線程訪問過PositionCollection類。你的問題必須在其他地方。 – 2010-05-18 01:30:07
@BrianGideon UnitTest正在使用Parallel.For,它將更新多個線程中的項目位置。 – DEHAAS 2010-05-18 20:05:24