none
有关asp.net Application、Dictionary及线程安全,有点难度,盼线程安全高手 RRS feed

  • 问题

  • 在Application_Start中加入了下面的代码

    protected void Application_Start(object sender, EventArgs e)
    {
    Dictionary<string, int> vals = new Dictionary<string, int>();
    vals.Add("1",0);
    vals.Add("2",0);
    Application["server"] = vals
    }

    有一个server.ashx用来接收浏览器发送的数据,代码大概是这样

    public void ProcessRequest(HttpContext context)
    {


    Dictionary<string, int> vals = context.Application["server"] as Dictionary<string, int>;

    vals[context.Request.QueryString.Get("key")] =Convert.ToInt32(context.Request.QueryString.Get("value"));

    context.Application.Lock();
    context.Application["server"] = vals;
    context.Application.UnLock();

    }

    现在问题来了:
    我觉得上面代码是有问题的,在
    Dictionary<string, int> vals = context.Application["server"] as Dictionary<string, int>;
    中,取出vals后,对于当前执行这段代码的线程来说,是一个vals的变量,然后线程修改该Dictionary中的数据

    假设此时发生线程切换,前一个线程被挂起,另一个浏览器也请求server.ashx,并且将完整的ProcessRequest方法执行完成。
    它可能也在修改Dictionary中的数据。

    最后,刚挂起的线程现在恢复,并且在当前的vals保存到Application["server"]中,但是没有考虑到其它线程已经修改了Dictionary
    中的值。

    Lock和UnLock只是用来保证对 Application的操作是原子性完成的。
    当使用 context.Application["server"] as Dictionary<string, int>取出时,脱离Lock和UnLock的范围时,已经不是线程安全了。

    所以认为这里应该使用   System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>

    大家认为我的说法正确吗?
    2012年5月5日 3:55

全部回复

  • 在Application_Start中加入了下面的代码

    protected void Application_Start(object sender, EventArgs e)
    {
    Dictionary<string, int> vals = new Dictionary<string, int>();
    vals.Add("1",0);
    vals.Add("2",0);
    Application["server"] = vals
    }

    有一个server.ashx用来接收浏览器发送的数据,代码大概是这样

    public void ProcessRequest(HttpContext context)
    {


    Dictionary<string, int> vals = context.Application["server"] as Dictionary<string, int>;

    vals[context.Request.QueryString.Get("key")] =Convert.ToInt32(context.Request.QueryString.Get("value"));

    context.Application.Lock();
    context.Application["server"] = vals;
    context.Application.UnLock();

    }

    现在问题来了:
    我觉得上面代码是有问题的,在
    Dictionary<string, int> vals = context.Application["server"] as Dictionary<string, int>;
    中,取出vals后,对于当前执行这段代码的线程来说,是一个vals的变量,然后线程修改该Dictionary中的数据

    假设此时发生线程切换,前一个线程被挂起,另一个浏览器也请求server.ashx,并且将完整的ProcessRequest方法执行完成。
    它可能也在修改Dictionary中的数据。

    最后,刚挂起的线程现在恢复,并且在当前的vals保存到Application["server"]中,但是没有考虑到其它线程已经修改了Dictionary
    中的值。

    Lock和UnLock只是用来保证对 Application的操作是原子性完成的。
    当使用 context.Application["server"] as Dictionary<string, int>取出时,脱离Lock和UnLock的范围时,已经不是线程安全了。

    所以认为这里应该使用   System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>

    大家认为我的说法正确吗?
    2012年5月5日 3:54
  • public void ProcessRequest(HttpContext context)
    {
    context.Application.Lock();
    Dictionary<string, int> vals = context.Application["server"] as Dictionary<string, int>;
    vals[context.Request.QueryString.Get("key")] =Convert.ToInt32(context.Request.QueryString.Get("value"));
    context.Application["server"] = vals;
    context.Application.UnLock();
    }

    调整位置即可。试试看。
    2012年5月5日 6:10
  • 感谢您的回复。

    你没有考虑到如果Lock与UnLock中间的代码比较复杂的情况,执行时间长,该线程阻塞后,会有很多的线程在排队。这样吞吐量急剧下降。

    2012年5月6日 9:15
  • 尽量不要在Lock与UnLock中间放过于复杂的代码..

    2012年5月8日 8:32
    版主
  • Hi heywap,

    欢迎来到C#论坛。

    根据你的描述,我将把该帖移到ASP.NET论坛以获得更好的回应。谢谢你的理解!


    Bob Shen [MSFT]
    MSDN Community Support | Feedback to us

    2012年5月8日 8:42
  • 你好 heywap

    欢迎来到Asp.net论坛。

    由于你2个帖子相同,所以我帮你合并了下,谢谢你的理解!

    2012年5月8日 8:59
    版主