【问题标题】:Is this code thread safe in ASP.NET MVC 4?此代码线程在 ASP.NET MVC 4 中是否安全?
【发布时间】:2015-02-20 07:22:52
【问题描述】:

根据我目前的理解,我认为这段代码不是线程安全的,但想确认一下。换句话说,我认为,尽管极不可能,但表示不同 HTTP 请求的多个线程可能会混淆_userName 属性的值。

public class SomeClass
{
    private static string _userName;

    public static string UserName
    {
        get
        {
            if (string.IsNullOrEmpty(_userName))
            {
                _userName = HttpContext.Current.User.Identity.Name;
            }

            return _userName; 
        }
    }
}

它是线程安全的吗?如果不是,是否会删除 null 检查,并且始终直接(在静态属性中)访问 HttpContext.Current.User.Identity.Name 是线程安全的?

public class SomeClass
{
    public static string UserName
    {
        get
        {
            return HttpContext.Current.User.Identity.Name; 
        }
    }
}

【问题讨论】:

  • 正确,您的第一个示例不是线程安全的,因为静态成员在线程之间共享(除非您使用线程本地存储,但您不是),并且 HttpContext.Current 属性 被存储在线程本地存储中。
  • 另外,还有第二个线程安全问题:你的线程可能在if= 语句之间被抢占,所以你想要一个lock,而不是他的代码很好首先是想法。
  • “虽然可能性极小” 这可能比你想象的要大得多。

标签: c# asp.net asp.net-mvc multithreading thread-safety


【解决方案1】:

你的两个例子非常不同。你是对的,你的第一个例子不是线程安全的,但更重要的问题是 它不是会话安全的。访问UserName 的第一个会话将设置用户名,所有其他会话将使用相同的名称UserName 在应用程序池被回收之前不会更改。 技术上 second 会话设置用户名是否重要,如果它在第一个会话之后稍稍发出请求?

如果要缓存每个会话的用户名,请使用 Session 属性:

Session["UserName"] = HttpContext.Current.User.Identity.Name;

第二个块线程安全的,但是每次调用它都会返回当前用户名。所以不用担心数据会跨线程交叉,更不用说会话了。

【讨论】:

  • "在应用程序池被回收之前,用户名不会改变。"你对这部分有多大把握?这似乎不是它的行为方式,但我会更多地研究它。我认为它会归结为何时为类调用隐式静态构造函数——静态构造函数不会在每次调用时清除 _userName 吗?它在整个过程的生命周期中只调用一次吗?
  • @SeanThoman 静态属性对于整个应用程序池都是静态的。第一次尝试读取 UserName 属性时,当前会话的用户被提取并设置了静态字段 - 除非您有其他代码更改该字段,否则它将保持相同的值,直到进程终止。
【解决方案2】:

您的第二个解决方案可以正常工作。第一个是根本不是线程安全的。在静态变量中缓存一个值会将其暴露给所有线程,如果您有两个或多个同时请求,它们很可能会读取其他请求的值。你认为它极不可能,嗯...它不是,恰恰相反。

另外,如果你真的想在多个线程之间共享一个值,你应该使用一些同步机制来确保正确性。在您的第一个示例中,您访问 _userName 3 次(2 次读取和 1 次写入)。您可能会遇到此变量以不同值结尾的情况,因此您应该将所有内容都包含在 lock 中。只有当您明确希望在线程之间共享此信息时。

第二种方法有效,因为HttpContext.Current 的值是从当前execution context 检索的(因此它依赖于当前线程)。

还有一件事:在 ASP.NET 应用程序中,由于thread agility,您不应该依赖线程本地存储,因此如果您需要缓存值,请改用HttpContext。您有一个 Items 属性,它允许您仅在当前请求期间存储值。但在您的特定示例中,您不必缓存此值,因为它已经从 HTTP 上下文中检索到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-13
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多