【问题标题】:HttpContext Class and its Thread SafetyHttpContext 类及其线程安全
【发布时间】:2011-09-27 13:02:41
【问题描述】:

我在应用程序中有一个 Singleton 对象,它具有以下属性:

private AllocationActionsCollection AllocationActions
{
    get
    {
        return HttpContext.Current.Session["AllocationOptions.AllocationActions"] as AllocationActionsCollection;
    }
    set
    {
        HttpContext.Current.Session["AllocationOptions.AllocationActions"] = value;
    }
}

我正在处理一个错误(HttpContext.Current.Session["AllocationOptions.AllocationActions"] 为空,即使我认为它总是设置为有效实例...)。我刚刚在 MSDN 中读到 HttpContext 实例成员不能保证是线程安全的!我想知道这是否可能是问题所在。应用程序中的某处可能存在资源竞争,而 HttpContext.Current.Session["AllocationOptions.AllocationActions"] 为 null 的时刻就是使用此语句使用 AllocationActions 设置器的时刻:

AllocationActions = new AllocationActionsCollection(Instance.CacheId);

我的问题是:

a) 我很震惊 HttpContext.Current.Session 不是线程安全的。那么如何安全地使用该属性呢? b) 你有什么想法为什么 Session 变量可以为空(即使我很确定我在第一次使用它之前就设置了它)?

谢谢,帕维尔

编辑 1:

a) 初始化会话变量的行每 2 分钟使用以下语句设置一次(在 Page_Load 中执行)

AllocationActions = new AllocationActionsCollection(Instance.CacheId);

b) 在事件处理程序中调用 getter 的代码(如 Button_Click)

c) 应用程序中没有自定义线程。唯一常见的 HTTP Handler

【问题讨论】:

  • 好的,那么这段代码是什么?这是一个显式线程情况(调用 Thread.Start)还是通过线程这是一个 Web 服务或 HTTP 处理程序,还是什么?
  • 什么时候执行返回空会话的代码?在页面构造函数中 Session IS null;在 Page_Init 或 Page_Load 会话中不为空
  • 你需要展示更多的源代码——尤其是。在哪里设置并澄清线程情况...例如,如果您在 IIS 中访问 HttpContext.Current 之外的 IIS 线程(即在您单独启动的线程中),这将产生“有趣”的结果...跨度>
  • 文档的意思是,一个特定的 HttpContext 实例一次只能从一个线程安全地使用。这是所需的行为,因为它与正在处理页面请求的线程绑定。

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


【解决方案1】:

singleton 对象是通过将类的实例化限制为一个对象来实现的。

HttpContext.Current.Session 是一个专用于单个用户的区域;存储在 Session 中的任何对象将仅对创建它的用户/会话可用。

存储在Application 中的任何对象将仅对每个用户/会话可用。

任何静态对象也将仅对每个用户/会话可用。 Suggested implementations 总是使用静态对象.. 你为什么不呢?

【讨论】:

  • 谢谢,我当时很困惑。当然事实证明,应用程序中存在一个未设置 Session 变量的错误......
【解决方案2】:

HttpContext.Current 不是实例成员,它是静态成员。所以它是线程安全的。它返回一个HttpContext 实例,但它为每个请求返回一个单独的实例——可以有多个线程处理请求,但每个请求都会得到一个单独的HttpContext 实例。所以任何给定的实例都没有被多个线程使用,线程安全不是问题。

因此,除非您为单个请求手动启动多个自己的线程,否则您线程安全的。

【讨论】:

  • 这不是真的。当达到某些负载时,IIS 将启动新线程,并且如果您将配置信息或其他内容存储在静态变量中,则无法从新线程访问该数据。
  • @DonRolling,有引用吗?我从来没有听说过 IIS 会为同一个请求启动多个线程,我也不确定这意味着什么。
  • 我没有引用,但我遇到了这个问题。它不会在单个请求期间发生。如果您将数据库配置值之类的内容存储在静态变量中,就会发生这种情况。如果 IIS 由于流量而开始一个新线程,那么这些配置值对新线程不可用。
  • @DonRolling,您将线程与应用程序域混淆了。静态数据在 appdomain 内的所有线程之间共享,因此这些值可用于新线程。只有当它启动一个新的 appdomain 时,您才会获得静态变量的新副本。即便如此,您的初始化代码仍应运行并初始化变量,就像它在第一个 appdomain 中所做的那样。
  • 在此处进一步讨论 ASP.NET 如何在线程之间迁移 HttpContext:stackoverflow.com/questions/8109526
【解决方案3】:

HttpContext 类的线程安全对于 .NET 来说是相当标准的。基本的经验法则(除非明确指定)是静态成员是线程安全的,而实例成员不是。

在任何情况下,如果不深入研究设置/重置它的代码,就很难判断为什么您的会话变量为空。或者您可能是从与您设置的会话不同的会话中调用您的 get_AllocationActions 方法。同样,更多代码会有所帮助。

【讨论】:

    【解决方案4】:

    要安全地访问会话属性,您只需将访问包装在一个锁定语句中并使用会话类的 SyncRoot 对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-10
      • 2012-06-19
      • 1970-01-01
      相关资源
      最近更新 更多