我抓住System.Linq.Dynamic.DynamicQueryable從這裏: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspxSystem.Linq.Dynamic。選擇(「新的......」)似乎沒有線程安全
是我遇到的問題在代碼看起來像這樣:
var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);
看來,如果該行代碼由多個線程執行的幾乎同時,在他們的ClassFactory.GetDynamicClass()方法,它看起來像這樣微軟的動態Linq的代碼崩潰:
public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
{
rwLock.AcquireReaderLock(Timeout.Infinite);
try
{
Signature signature = new Signature(properties);
Type type;
if (!classes.TryGetValue(signature, out type))
{
type = CreateDynamicClass(signature.properties);
classes.Add(signature, type); // <-- crashes over here!
}
return type;
}
finally
{
rwLock.ReleaseReaderLock();
}
}
崩潰是一個簡單的字典錯誤:「具有相同密鑰的項目已被添加。」
在Ms代碼中,rwLock變量是一個ReadWriterLock類,但它沒有阻止多個線程進入classes.TryGetValue()if語句,很明顯,Add會失敗。
我可以很容易地在創建兩個或更多線程的代碼中複製這個錯誤,這些線程嘗試執行Select(「new」)語句。
無論如何,我想知道是否有其他人遇到過這個問題,以及是否有修復或可以實施的解決方法。
謝謝。
因爲你有,你可以有效地使用'ConcurrentDictionary'交換'Dictionary'解決這個問題的來源 - 這將是相當快(大多數操作都是無鎖的)並解決線程問題(因爲它是線程安全的) – Yahia
這顯然是一個錯誤。好東西,你可以修復它,在調用Add之前使用UpgradeToWriterLock()。 –
只需升級到寫入鎖定是不夠的,您需要在獲得X鎖定後再次檢查(嘗試獲取)值*。 –