我是否必须锁定对实例成员的访问权限?
例子:
public class HttpModule : IHttpModule
{
//...
Dictionary<int, int> foo;
void UseFoo(int a, int b)
{
foo[a] = b;
}
}
我是否必须锁定对实例成员的访问权限?
例子:
public class HttpModule : IHttpModule
{
//...
Dictionary<int, int> foo;
void UseFoo(int a, int b)
{
foo[a] = b;
}
}
到目前为止,我对 MSDN 文档还不是很清楚,但是我发现了一个论坛帖子,来自一个声称知道答案的人。听起来您不应该期望您的实现会发生坏事,但是您应该知道,foo
' 状态不一定会在所有结果中共享,因为您将在IIS 选择保留在其池中HttpModule
时创建一次。HttpApplication
我想在这里提供我在 IIS6 中观察到的与此问题相关的发现:
我一直在 IIS6 中广泛处理这个问题,并发现了一些有趣的结果,利用 log4net 和反射来捕获执行历史。我发现在幕后进行了大量的“线程管理”。似乎有一个“主要”系列线程对应于 1:1 到HttpApplication
. 然而,这些线程并不专门为您的请求处理管道。各种不同的子线程可以在访问这些实例时调用。您的应用程序使用的后续新请求和资源请求似乎共享一些与您的原始请求相关的持久信息,但从未完全由初始线程处理,表明某种类型的关系。我无法辨别任何具体模式(除了我之前描述的)关于哪些元素被划分到其他线程,因为它似乎是随机的。我对这个证据的结论是存在一些分层池的概念?发生在某些未知的引用元素子集通过父引用在子线程中继承的情况下。
因此,作为答案,我会说这HttpModules
是线程之间共享的。就锁定实例值而言,如果这些值适用于所有使用该模块并且必须保持某种状态的请求,则这将适用。如果尝试维护昂贵的有状态实例值以便在后续请求中重用它们,我可以看到这很有用。
这个问题困扰了我一段时间,希望这些信息对某人有所帮助。
我最近发现了一篇稍微涉及到这个问题的文章:http: //www.dominicpettifer.co.uk/Blog/41/ihttpmodule-gotchas---the-init---method-can-get-called-multiple-次
它没有提到线程,而只是说工作进程将
实例化它认为需要的尽可能多的 HttpApplication 对象,然后出于性能原因将它们池化,在新请求进入之前重用实例,然后将它们发送回池中。
按照链接中的代码,您可以确保您的 init 代码以线程安全的方式执行一次:
private static bool HasAppStarted = false;
private readonly static object _syncObject = new object();
public void Init(HttpApplication context)
{
if (!HasAppStarted)
{
lock (_syncObject)
{
if (!HasAppStarted)
{
// Run application StartUp code here
HasAppStarted = true;
}
}
}
}
我一直想设置一个测试应用程序来运行它并测试它,只是为了看看它是否属实,但我没有时间。
Jim 发表的文章很有趣,但正如 Jim 所说,它没有提到任何关于线程安全的内容。
我想如果您正在初始化静态成员或执行“仅一次”初始化(即初始化静态资源),您将只需要锁定机制。
我无法从 MSDN 和 Jim 提到的文章中得出结论,我们在初始化非静态类变量时需要锁定机制。