2

为未来的读者更新:如果您发现此文本太长:这是由于静态变量而导致的竞争条件。您在下面阅读的内容表明,对于正在调试它并忽略static关键字的人来说,这会变得多么令人困惑。如果您遇到类似的行为,请务必先检查static

我正在调试此应用程序,但在代码中找不到错误。我的母版页类有一个名为Greeting. 直到同一服务器上的两个用户大约同时(不到一秒)注销时,此属性才会引起问题。然后,一个用户会收到为其他用户准备的问候语(例如,如果 John 和 Jane 正在测试,他们都会看到“Dear Misses Jane!”)。因此,出于调试目的,我为此属性实现了一个 getter 和一个 setter。两者都通过 将读取或写入到 trace.axd 的值写入HttpContext.Current.Trace.Write()。我看到设置了正确的值。但最后get会读取相应其他用户的值。有两次连续调用 getter 返回不同的值。中间没有调用 setter。该属性是私有的,并且代码分析显示,它没有从其他任何地方引用。我还将堆栈跟踪写入带有Environment.StackTrace. 代码按预期运行。这与 .NET 本身的错误有何不同?

    private static string _Greeting = String.Empty;
    private static string Greeting
    {
        get
        {
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__get(): " + _Greeting);
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__get() STACKTRACE: " + Environment.StackTrace);
            return _Greeting;
        }
        set
        {
            _Greeting = value;
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__set(): " + _Greeting);
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__set() STACKTRACE: " + Environment.StackTrace);
        }
    }

踪迹摘录(化名):

 Debug  myMasterPage.Greeting__get(): Dear Misses Jane  
 Debug  myMasterPage.Greeting__get(): Dear Mister John
4

4 回答 4

7

问题是这个变量是这样的static,因此当一个用户登录并设置值时,另一个用户登录并更改它。所以您知道,静态变量是在所有线程(请求)之间共享的变量,并且您希望在 Web 应用程序上声明静态变量的情况很少。

于 2013-08-16T14:45:21.880 回答
1

你有所谓的竞争条件

    private static string Greeting
    {
        get
        {
            /*1.*/ Trace.Write("Debug", "myMasterPage.Greeting__get(): " + _Greeting);
            /*2.*/ return _Greeting;
        }
        set
        {
            /*3.*/ _Greeting = value;
            /*4.*/ Trace.Write("Debug", "myMasterPage.Greeting__set(): " + _Greeting);
        }
    }

我已经对相关行进行了编号,以显示当两个线程(A 和 B)运行相同的代码时如何实现结果 - 沿着以下行:

 StaticClass.Greeting = "Hi "+username;
 //some other code
 Display(ShowStaticClass.Greeting);
  1. 程序启动,_Greeting == string.Empty.
  2. 线程 A 开始执行,到达相关代码。执行第 3 行。_Greeting == "A"
  3. 线程 A 执行第 4 行。写出"_Greeting saved as A"
  4. 线程 A 执行第 1 行。写出"_Greeting read as A"
  5. 线程 B 开始执行,到达相关代码。执行第 3 行。_Greeting == "B"
  6. 线程 B 执行第 4 行。写出"_Greeting saved as B"
  7. 线程 A 执行第 2 行。返回 _Greeting == "B"
  8. 线程 B 执行第 4 行。写出"_Greeting saved as B"
  9. 线程 B 执行第 1 行。写出"_Greeting read as B"
  10. 线程 B 执行第 2 行。返回 _Greeting == "B"

这将导致以下日志:

"_Greeting saved as A"
"_Greeting read as A"
"_Greeting saved as B"
"_Greeting read as B"

同时返回"Hi B"两个线程的值。

第 3 行和第 6 行不会一个接一个地执行,但是可以(并且将会)有代码在一个之后和另一个之前执行。那样的话,你的调试日志基本上是骗你的,而只告诉你真相。

于 2013-08-16T15:02:32.280 回答
0

如果你想在服务器端保存数据,你应该在 asp.net 页面中使用 Session ,或者你可以把它放在 ViewState 中(在客户端)

于 2013-08-16T14:44:21.710 回答
0

这是一篇关于静态变量的好帖子,它应该可以解释你的问题。 C#中静态变量有什么用?什么时候使用它?为什么我不能在方法中声明静态变量?

于 2013-08-16T14:48:27.130 回答