ASP.NETにおいて、static変数は「リクエスト単位」のグローバル変数『ではない』

http://kapijie.blog115.fc2.com/blog-entry-8.html

ASP.NETでstatic変数を扱う場合、変数のスコープをしっかり確認しておく必要があります。
ASP.NETの場合、static変数はASPという大きなプロセスの中に1つしか存在しません。
フォームアプリケーションと同じ感覚で使っていると、複数のユーザーから同時にアクセスがあった時に、大変なことになります。

ASP.NET で static変数 はサーバで動作している「プログラム全体」で共有する。
ASP.NETにおいて、static変数は「リクエスト単位」のグローバル変数『ではない』。
以下のようなページがあるとき、_staticNumはサーバ全体で1つの値を保持しており、表示される数値はアクセスされるごとに毎回カウントアップされていく。
これは別のリクエストだろうが、別ブラウザからのアクセスだろうが、別マシンからのアクセスだろうが関係なく、カウントアップされていく。

Public Class SamplePage
    Inherits System.Web.UI.Page

    Public Shared _staticNum As Integer = 0

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        _staticNum += 1
        Me.Response.Write(_staticNum)
    End Sub

End Class

対策

以下の対策を行うことで、static変数はリクエスト単位のグローバル変数であるかのように振る舞う。
static変数にThreadStatic属性を付けて宣言する。
さらにPage_Loadイベントでstatic変数の初期化を行う。



ThreadStatic属性をつけることで、あるリクエスト中に、別のリクエストがstatic変数を上書きしてしまうことを防止できる。別のリクエストは別スレッドで処理されるため。
スレッドは使い回される可能性があるため、リクエストごとに初期化をしないと前回の値が残ったままになる。
ごく稀に1つのリクエストが最初はスレッド1で処理されており、Loadイベント発生前に処理がスレッドBに引き継がれるということが起きるらしい。そのため、Page_Loadより前にThreadStatic属性static変数に格納された値はスレッドが切り替わって破棄される可能性がある。
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=http%3A%2F%2Fpiers7.blogspot.com%2F2005%2F11%2Fthreadstatic-callcontext-and_02.html