Multithreading System.Linq.Dynamic.Select(“新建…”)似乎不是线程安全的

Multithreading System.Linq.Dynamic.Select(“新建…”)似乎不是线程安全的,multithreading,linq-to-sql,Multithreading,Linq To Sql,我从这里获取System.Linq.Dynamic.DynamicQueryable: 我遇到的问题在代码中看起来是这样的: var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5); public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)

我从这里获取System.Linq.Dynamic.DynamicQueryable:

我遇到的问题在代码中看起来是这样的:

var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);
    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();
        }
    }
var results=dataContext.GetTable.Select(“new(MyClassID,Name,Description)”).Take(5);
如果该行代码几乎同时由多个线程执行,则Microsoft的动态Linq代码会在其ClassFactory.GetDynamicClass()方法中崩溃,如下所示:

var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);
    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();
        }
    }
公共类型GetDynamicClass(IEnumerable属性)
{
rBlock.AcquisitionerReaderLock(Timeout.Infinite);
尝试
{
签名=新签名(属性);
类型;
if(!classes.TryGetValue(签名,输出类型))
{
type=CreateDynamicClass(signature.properties);
class.Add(签名,类型);//我做了以下操作(需要.NET 4或更高版本才能使用
System.Collections.Concurrent
):

  • classes
    字段更改为
    ConcurrentDictionary
  • 删除了所有的
    ReaderWriterLock rwLock
    字段和所有引用该字段的代码
  • GetDynamicClass
    更新为:

    public Type GetDynamicClass(IEnumerable<DynamicProperty> properties) {
        var signature = new Signature(properties);
        return classes.GetOrAdd(signature, sig => CreateDynamicClass(sig.properties));
    }
    

既然您有了源代码,您就可以通过将
字典
ConcurrentDictionary
交换来有效地修复此问题-这将相当快(大多数操作都是无锁实现的),并解决线程问题(因为它是线程安全的),这显然是一个bug。幸好您可以修复它,请使用UpgradeToWriterLock()在调用Add.Simply upgrading to write lock之前,仅升级到write lock是不够的,您需要在获得X锁后再次检查(尝试获取)该值。我“认为”我通过更改rwLock.AcquireReaderLock()对rwLock.AcquireWriterLock()的调用修复了它,以及随后的发布电话。我可能会支付一个小的性能点击,但我猜它太小了,不值得注意。我猜我希望有人遇到了这件事,并且有一个更“正式的”如果修复了其他错误,我应该进行修复。这里仍然存在潜在的竞争条件,因为您读取类。无锁计数。您可能会创建两个具有相同数字后缀的类。更安全的方法是使用“DynamicClass”+Guid.NewGuid()。