使用TryGetValue进行反射的并发问题

时间:2018-08-14 20:44:39

标签: c# .net concurrency hang

我们有一个旧版CMS系统,该问题似乎更经常发生(可能是由于.NET v4升级并以64位运行)。

(由于机密性,我不得不删除对CMS名称的所有引用)

以下是我们实时服务器中转储文件的摘要。

./src/index.js

这最终也导致我们使用Utils.GetMethodsWithAttribute(DetectServicePage使用的)

背景:如果所请求的页面是“服务页面”而不是常规内容页面,则调用DetectServicePage方法以解决此问题

System.Collections.Generic.Dictionary`2[[InternalCMSNameRedacted.Core.Utils+MethodWithAttributeKey, InternalCMSNameRedacted.Core],[System.__Canon, mscorlib]].FindEntry(MethodWithAttributeKey)+f5 
System.Collections.Generic.Dictionary`2[[InternalCMSNameRedacted.Core.Utils+MethodWithAttributeKey, InternalCMSNameRedacted.Core],[System.__Canon, mscorlib]].TryGetValue(MethodWithAttributeKey, System.__Canon ByRef)+14 
InternalCMSNameRedacted.Core.ConcurrentMap`2[[InternalCMSNameRedacted.Core.Utils+MethodWithAttributeKey, InternalCMSNameRedacted.Core],[System.__Canon, mscorlib]].TryGetValue(    MethodWithAttributeKey, System.__Canon ByRef)+8d 
InternalCMSNameRedacted.Core.Utils.GetMethodsWithAttribute[[System.__Canon, mscorlib],[System.__Canon, mscorlib]]()+1f9 
InternalCMSNameRedacted.Core.InternalCMSNameRedactedHandler.DetectServicePage(InternalCMSNameRedacted.Core.ServicePageData)+39c 

这将调用Utils.GetMethodsWithAttribute,我认为这是问题所在(基于转储文件)。以下是此方法的代码:

   foreach (MethodInfo mi in Utils.GetMethodsWithAttribute<ServicePageHandlerAttribute, ServicePageHandlerContainerAttribute>())
    {
        foreach (ServicePageHandlerAttribute spha in mi.GetCustomAttributes<ServicePageHandlerAttribute>())
        {
            if (urlParts[0] == spha.ServicePage)
            {
                if (data.IsPasswordProtection)
                {
                    if (mi.ReturnType == typeof(ServicePageData))
                    {
                        return mi.Invoke(null, new object[] { data }) as ServicePageData;
                    }
                    else
                    {
                        continue;
                    }
                }
                else
                {
                    if (mi.ReturnType == typeof(ServicePageData))
                    {
                        return mi.Invoke(null, new object[] { data }) as ServicePageData;
                    }
                    else
                    {
                        mi.Invoke(null, new object[] { });
                    }
                }
                if (spha.EndResponse)
                {
                    Oracle.Response.End();
                }
            }
        }
    }

这使用了CMS特定的数据存储ConcurrentMap:

  private readonly static ConcurrentMap<MethodWithAttributeKey, ICollection<MethodInfo>> _MethodsWithAttributeCache = new ConcurrentMap<MethodWithAttributeKey, ICollection<MethodInfo>>();

    private readonly static ConcurrentMap<MethodWithAttributeKey, ICollection<string>> _ClassesWithAttributeStringCache = new ConcurrentMap<MethodWithAttributeKey, ICollection<string>>();

    public static ICollection<MethodInfo> GetMethodsWithAttribute<AttributeType, ContainerAttributeType>()
        where AttributeType : Attribute
        where ContainerAttributeType : Attribute
    {
        List<Type> validTypes = null;
        List<MethodInfo> l = new List<MethodInfo>();

        var key = new MethodWithAttributeKey {
            AttributeType = typeof(AttributeType),
            ContainerAttributeType = typeof(ContainerAttributeType)
        };

        ICollection<MethodInfo> methods;
        if (_MethodsWithAttributeCache.TryGetValue(key, out methods)) {
            // If the methods are in the cache and none have disappeared
            if (methods != null && methods.None(m => m == null)) {
                return methods;
            }

            // At least one of the methods we cached last time do not appear to exist now
            // so we need to regenerate from the classesWithAttributeStringCache if possible
            if (_ClassesWithAttributeStringCache.ContainsKey(key))
            {
                validTypes = new List<Type>();

                foreach (var ts in _ClassesWithAttributeStringCache[key])
                {
                    Type type = BuildManager.GetType(ts, false, true);

                    if (type != null) {
                        validTypes.Add(type);
                    }
                }
            }
        }

        if (validTypes == null) {
            validTypes = new List<Type>();

            foreach (Assembly assembly in Thread.GetDomain().GetAssemblies().Where(a => !a.FullName.StartsWith("System."))) {
                Type[] assemblyTypes = null;
                try {
                    assemblyTypes = assembly.GetTypes();
                }
                catch (ReflectionTypeLoadException refEx) {
                    EventLog.Add(refEx);
                    refEx.LoaderExceptions.ToList().ForEach(e => EventLog.Add(e));
                    //throw refEx;
                    continue;
                }
                catch (Exception ex)
                {
                    EventLog.Add(ex);
                    continue;
                }
                if (assemblyTypes != null)
                {
                    foreach (var t in assemblyTypes)
                    {
                        if (t.GetCustomAttributes<ContainerAttributeType>().Count > 0)
                        {
                            validTypes.Add(t);
                        }
                    }
                }
            }

            List<string> typeStrings = new List<string>();
            validTypes.ToList().ForEach(t => typeStrings.Add(t.AssemblyQualifiedName));
            _ClassesWithAttributeStringCache[key] = typeStrings;
        }

        foreach (Type currentType in validTypes) {
            foreach (var m in currentType.GetMethods()) {
                if (m.GetCustomAttributes<AttributeType>().Count > 0) {
                    l.Add(m);
                }
            }
        }

        // Add into 
        _MethodsWithAttributeCache[key] = l;
        return l;
    }

我感觉这是自定义实现-并发映射,可能有一个我们可以使用的本机实现,因为它是在.net v2中构建的

0 个答案:

没有答案