【问题标题】:ASP.NET Threading - Double checked lockingASP.NET 线程 - 双重检查锁定
【发布时间】:2009-01-26 18:06:20
【问题描述】:

我在 HttpApplicationState 对象上有一个扩展方法,用于将我的 IoC 容器从应用程序中取出。如果容器不存在,同样的代码也会创建容器。

我有两个问题:

  1. 我的代码是否真的像我预期的那样是线程安全的
  2. 这是否被认为是处理应用程序状态的最佳实践

代码如下:

private const string GlobalContainerKey = "UnityContainerKey";

public static IUnityContainer GetContainer(this HttpApplicationState application)
{
    var container = application[GlobalContainerKey] as IUnityContainer;

    if (container == null)
    {
        try
        {
            application.Lock();
            container = application[GlobalContainerKey] as IUnityContainer;

            if (container == null)
            {
                container = new UnityContainer();
                application[GlobalContainerKey] = container;
            }
        }
        finally
        {
            application.UnLock();
        }
    }

    return container;
}

【问题讨论】:

  • 顺便说一句,自从我从 Unity 迁移到 StructureMap 并且 SM 将自己暴露为静态类,所以我永远不必担心它不存在。

标签: c# asp.net multithreading


【解决方案1】:

你需要放

var container = application[GlobalContainerKey] as IUnityContainer;

在锁中也是如此,否则许多线程可能会依次创建一个新容器。

private const string GlobalContainerKey = "UnityContainerKey";
private const object lockObject = new object();

public static IUnityContainer GetContainer(this HttpApplicationState application)
{
    var IUnityContainer container = null;

    lock (lockObject)
    {
        container = application[GlobalContainerKey] as IUnityContainer;
        if (container == null)
        {
            container = new UnityContainer();
            application[GlobalContainerKey] = container;
        }
    }

    return container;
}

【讨论】:

  • 你说得对,我的意思是在第二个 if 语句之前将它放在里面。
  • 如果第一个 if 语句在锁中,则不需要第二个 if 语句。此外,如果使用 lock(),则不需要 try/finally(lock() 是 try/finally 的语法糖。
  • 对,但我不希望它在每个页面请求上锁定应用程序,这就是为什么我有外部 if。您能否详细说明 .Lock 的用法,无需尝试/最终以及为什么它是安全的?我什至需要调用 .Unlock 吗?
  • 如果您不想锁定应用程序以锁定每个调用,则使用容器的静态 get 属性(并使底层文件只读)。然后在应用程序类的静态 ctor 中设置它。
  • 静态 ctor 保证在访问任何实例或静态方法或字段之前运行。不过,您正在失去“懒惰”的初始化。
【解决方案2】:

从技术上讲,鉴于 EMCA 规范,这不起作用。 Jon Skeet 在他的 C# FAQ 中对此进行了介绍:

http://www.yoda.arachsys.com/csharp/singleton.html

具体见“第三版”部分

我会进一步阅读并使用他关于如何实现单例的建议来了解如何实现您正在尝试做的事情。

【讨论】:

  • 不同之处在于我已经在使用单例而不是尝试创建新的单例。阅读他反对 DCL 的理由中的第 2 点是唯一合理的观点,但是没有详细说明为什么它不起作用或“显式内存屏障调用”将是什么来确保它。
【解决方案3】:

为什么你第一次检查“container == null”?我认为您应该先锁定,然后检查容器是否为空。在第一个 if 和其他线程中的 return 之间可能会发生各种狡猾的事情。

【讨论】:

  • 我不想在容器存在后每次都锁定应用程序,因为每次页面请求都会调用它。它只需要为初始插入锁定。然而,我确实意味着有第二个“container = application[GlobalContainerKey] as IUnityContainer;”锁定后
【解决方案4】:

在 .NET Framework 的代码中使用带锁的双重检查,用于单例(例如,参见 System.Web.Profile.ProfileManager)。

所以我认为你的实现还可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多