单身人士和比赛条件 [英] Singletons and race conditions

查看:63
本文介绍了单身人士和比赛条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关此问题:

网络api调用中的空引用

但是我将其单独产生,因为我认为这可能与Ninject确实有关,并且如果我错了,我不想混淆原始问题.

But I'm spawning this off separately because it I think it might really be an issue with Ninject and I don't want to confuse the original question in case I'm wrong about this.

我的问题是我有一个Web api项目,该项目使用Ninject来管理依赖项注入,并且在大多数情况下都能正常工作.问题是,如果您在启动应用程序后立即快速启动多个请求,有时它们会以NullReferenceExceptions的某种真正怪异的方式失败,而对于似乎不为null的对象,它们根本不应该存在,我想知道如果这是Ninject使用InSingletonScope的问题,并没有真正给我一个单身人士,而是有时给了我一些尚未完成初始化的东西(但也许是在调试器中看到它时就已经初始化了).那可能吗?还是我完全把树弄错了?

My problem is that I have a web api project that uses Ninject to manage dependency injection and most of the time it works fine. The problem is if you fire off multiple request very quickly right after starting the application, sometimes they fail in some really weird way with NullReferenceExceptions that simply shouldn't exist for objects that don't appear to be null and I'm wondering if it's an issue with Ninject using InSingletonScope and not really giving me a singleton but sometimes giving me something that hasn't finished initializing (but perhaps is initialized by the time I look at it in the debugger). Is that possible? Or am I completely barking up the wrong tree?

我使用Nuget软件包和一些Web资源设置了Ninject(对不起,我似乎没有确切链接到哪个资源的链接),我认为我做得对.我的项目中有对NinjectNinject.Web.Common的引用.在NinjectWebCommon.cs中,我这样做是为了注册一堆服务(我已经排除了其中的大多数服务,以隔离那些给我带来麻烦的服务):

I have Ninject set up using Nuget packages and some web resources (sorry I don't seem to have the link to exactly which ones) and I thought I was doing it right. I have references in my project to Ninject and Ninject.Web.Common. In NinjectWebCommon.cs I have this for registering a bunch of services (I've excluded most of them, to isolate just the one that is giving me trouble):

    private static void RegisterServices(IKernel kernel)
    {
        System.Diagnostics.Debug.WriteLine("Registering Services...");
        kernel.Bind<Services.IUserService>().To<Services.UserService>().InSingletonScope();                                 

        kernel.Bind<Services.IMyFinderService>().To<Services.MyFinderService>().InSingletonScope();
        //kernel.SingletonBind<Services.IMyFinderService>().To<Services.MyFinderService>();
        //kernel.Bind<Services.IMyFinderService>().ToConstant<Services.MyFinderService>(new Services.MyFinderService(kernel.Get<Services.IUserService>()));
    }  

MyFinderService是给我带来麻烦的一个,请注意,它的构造函数使用了一个在其之前注册的IUserService(这也可能是造成问题的原因):

The MyFinderService is the one giving me trouble and note that it's constructor take an IUserService which was registered before it (and may also be the cause of the problem):

    public MyFinderService(IUserService service)
    {
        cache = new Dictionary<Guid, MyClassBase>();
        userService = service;
    }

我尝试了几种不同的方法来绑定它(在回答这个问题时提出了第二种方法:

I tried a couple of different approaches for how to bind it (the second one was suggested in an answer to this question: Ninject InSingletonScope with Web Api RC) but it still seems something isn't right when my API controller calls this method on MyFinderService:

public MyClassBase GetThing(Guid id)
{
    if (cache.ContainsKey(id))
    {
        return cache[id];
    }
    else
    {
        var type = typeof(MyClassBase).Assembly.GetTypes().FirstOrDefault
        (
            t => t.IsClass &&
                t.Namespace == typeof(MyClassBase).Namespace + ".Foo" &&
                t.IsSubclassOf(typeof(MyClassBase)) &&
                (t.GetCustomAttribute<MyIdAttribute>()).GUID == id
        );
        if (type != null)
        {
            System.Diagnostics.Debug.WriteLine(string.Format("Cache null: {0}",cache == null));
            var param = (MyClassBase)Activator.CreateInstance(type, userService);
            cache[id] = param;
            return param;
        }
        return null;
    }
}

有时我会在这行上得到一个NullReferenceException:

I sometimes get a NullReferenceException on this line:

cache[id] = param;

即使在调试器cache中,idparam似乎都具有值.

Even though in the debugger cache, id and param all appear to have values.

我的假设是,当我将某物注册为单例时,Ninject将处理确保它确实为单例并在延迟初始化期间锁定访问以确保它不会创建单独的单例的所有详细信息,但是也许我错了吗?

It was my assumption that when I registered something as a singleton that Ninject would handle all the details of making sure it really is a singleton and locking access during lazy initialization to ensure that it doesn't create a separate one, but maybe I'm wrong about that?

因此,如何在Web api项目的上下文中安全地创建和注册我的类的单个实例,该实例可能会收到来自不同线程的多个请求.

So how can I safely create and register a single instance of my class in the context of a web api project that might get multiple request coming from different threads.

推荐答案

如果您使用的是Ninject.Web.WebApi.WebHost,则InSingletonScope将以线程安全的方式为您提供单个实例.

Incase you are using Ninject.Web.WebApi.WebHost then InSingletonScope will give you a single instance in a threadsafe manner.

但是不幸的是,有许多博客文章和stackoverflow答案显示了使用ActivationBlock错误实现的DependencyResolver实现,即使将它们注册为单例,它也会在请求范围内为您提供对象.

But unfortunately there are many blog posts and stackoverflow answers that show incorrectly implemented DependencyResolver implementations using an ActivationBlock that will give you an object in request scope even though they are registered as singletons.

Ninject不做的是确保返回的对象本身是线程安全的.您的情况似乎就是这种情况. Dictionary的内部结构不是线程安全的.只允许一个线程同时修改字典.您应该切换到ConcurrentDictionary.

What Ninject doesn't do is to ensure that the returned objects are thread safe themselves. It seems this is that case in your case. The internal structure of a Dictionary is not thread safe. Just one thread is allowed to modify a dictionary at the same time. You should switch to a ConcurrentDictionary.

这篇关于单身人士和比赛条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆