开发者

System.Linq.Dynamic .Select("new ...") does not appear to be thread safe

I grabbed System.Linq.Dynamic.DynamicQueryable from here: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query开发者_JAVA技巧-library.aspx

The issue that I am running into is in code that looks like this:

var results = dataContext.GetTable<MyClass>.Select("new (MyClassID, Name, Description)").Take(5);

It appears that if that line of code is executed by multiple threads near simultaneously, Microsoft's dynamic Linq code crashes in their ClassFactory.GetDynamicClass() method, which looks like this:

    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();
        }
    }

The crash is a simple dictionary error: "An item with the same key has already been added."

In Ms code, The rwLock variable is a ReadWriterLock class, but it does nothing to block multiple threads from getting inside classes.TryGetValue() if statement, so clearly, the Add will fail.

I can replicate this error pretty easily in any code that creates a two or more threads that try to execute the Select("new") statement.

Anyways, I'm wondering if anyone else has run into this issue, and if there are fixes or workarounds I can implement.

Thanks.


I did the following (requires .NET 4 or later to use System.Collections.Concurrent):

  • changed the classes field to a ConcurrentDictionary<Signature, Type> ,
  • removed all the ReaderWriterLock rwLock field and all the code referring to it,
  • updated GetDynamicClass to:

    public Type GetDynamicClass(IEnumerable<DynamicProperty> properties) {
        var signature = new Signature(properties);
        return classes.GetOrAdd(signature, sig => CreateDynamicClass(sig.properties));
    }
    
  • removed the classCount field and updated CreateDynamicClass to use classes.Count instead:

    Type CreateDynamicClass(DynamicProperty[] properties) {
        string typeName = "DynamicClass" + Guid.NewGuid().ToString("N");
    ...
    
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜