【发布时间】:2012-04-14 23:53:17
【问题描述】:
我需要为每个 Web 请求实例化一个单例对象,以便数据处理一次并且在整个请求期间有效,我在 HTTP 请求期间使用 HttpContext.Current.Items 共享数据,一切都很好,直到我们需要 单例对象实例 跨多个线程,我想出的第一件事就是将 HttpContext 实例传递给新线程:
HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
{
HttpContext.Current = context;
// blah blah
});
我认为这不是 noted here 那样的线程安全方法。
使用 Reflector 我发现 HttpContext.Current.Items 实际上使用 CallContext 将对象存储在每个逻辑线程中。所以我把单例界面改成这样:
public static SingletonType SingletonInstance
{
get { return CallContext.GetData(key) as SingletonType; }
set { CallContext.SetData(key, value); }
}
在启动任何新线程时只需覆盖SingletonInstance!代码工作正常,但似乎不知何故在重负载下,CallContext.GetData(key) 返回 null 并且应用程序因 null 引用异常而崩溃!
我在想,如果CallContext.GetData 是原子的?但这似乎不对,CallContext 是线程特定的数据存储,并且必须是原子的,否则我错过了重点!
我的另一个猜测是设置 SingletonInstance (CallContext.SetData) 发生在一个线程中,而 CallContext.GetData 在另一个线程中以noted here 执行,但我不知道如何/为什么?
更新:
我们将每个在线用户的实例保存在服务器上的一个数组中。单例对象实际上是对代表当前用户的对象的引用。当前用户必须是唯一的,并且在每个线程中都可以用于数据库查询、日志记录、错误处理等,这就是它的完成方式:
public static ApplicationUser CurrentUser
{
get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
set { CallContext.SetData("ApplicationUser", value); }
}
【问题讨论】:
-
一个 HttpContext 指的是单个 Http 请求。在线程中的某个地方排队会导致一些问题(正如您显然已经发现的那样)。也许如果您描述一下您正在尝试做什么,我们可以想出一个更好的解决方案?
-
问题很简单,我需要在我的应用程序中使用任何请求(可能是应用程序开始请求)实例化的单个对象引用,并且在整个请求中保持活动状态,和任何可能之后开始的线程
标签: c# asp.net multithreading thread-safety singleton