我抓住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锁定后再次检查(尝试获取)值*。 –