bitfan(数字世界一凡人)的专栏

在新浪博客的新家:http://blog.sina.com.cn/bitfan

用户操作
[即时聊天] [发私信] [加为好友]
bitfan(数字世界一凡人)ID:bitfan
377052次访问,排名142好友0人,关注者67
=========
几本小书:
《网站建设教程》:高等教育出版社(2005)
《编程的奥秘——.NET软件技术学习与实践》:电子工业出版社(2006)
《.NET 2.0面向对象编程揭秘》:电子工业出版社(2007)。
《ASP.NET程序设计教程》高等教育出版社(2009)。

几堂小课:
在ITCAST(http://www.itcast.net)讲授.NET系列在线视频课程,想将课堂开到互联网上,目标不大,要帮助更多的年轻人学好技术找到好工作。野心不小,已录制了5个系列30节课,打算一路跟踪微软最新技术,打造国内自成体系、独特风格的微软技术系列课程。
bitfan的文章
原创 88 篇
翻译 0 篇
转载 0 篇
评论 2216 篇
最近评论
holon:不错,支持一下。

------------------------------
www.arraylist.cn cn域名免费送
IT人的酒吧式交流平台
-----------------------------
jxgzcxf:有金老师在前面带路,我们学习起这些技术来也相对轻松了些,不至于太迷惘。敬重金老师!
vxbb_free:楼上的说的吓人了
vxbb_free:楼上的说的吓人了
wjfmail:可以学,但估计要比别人多很多的努力.毕竟开发不是一种天赋就可以拥有的才能.你碰的钉子会比别人多得多.不过,还是从现在开始努力吧.
文章分类
收藏
    相册
    .NET技术学习与实践
    5.2 使用.NET开发数据库应用程序
    数据绑定原理
    杂类
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 ASP.NET应用程序中要小心使用放在App_Code文件夹类中的静态成员收藏

    新一篇: 使用泛型在VB.NET中实现VB6.0中的控件数组 | 旧一篇: 微软邹欣关于“清华-微软 软件科学实验班”的补充说明

    小心使用放在App_Code中类的静态成员

    每个ASP.NET应用程序都可以添加一个App_Code文件夹。放置在这一文件夹下的类可以被此ASP.NET应用程序中的所有页面所使用,可将这些类称为“全局类”,用起来很方便。 

    然而,如果这些类中定义了静态成员,则访问这些成员必须小心陷井。

    请看以下示例:

        public class SharedClass

        {

             public static int counter=0;

        }

     

    上述类放在App_Code中。网页访问代码如下:

     

    protected void Page_Load(object sender, EventArgs e)

        {

            SharedClass.counter++;

            Response.Write(SharedClass.counter.ToString());

        }

     

    上述代码好象没有什么问题,而且实验运行好象每次都正常。

    然而,由于Web应用程序是多线程的,而App_Code中的类具有全局性,因此,上述代码会带来一个多线程数据存取冲突的问题。

    我们可以修改SharedClass类来使这个问题突出出来:

     private static int _counter = 0;

     

        public static int Counter

        {

            get {

                return SharedClass._counter;

            }

            set {

                Thread.Sleep((new Random()).Next(5000, 10000));

                SharedClass._counter = value;

            }

        }

     上述代码通过随机延迟时间来以模拟互联网下的程序并发运行环境。

    页面访问共享资源的代码不变。

    现在请打开多个浏览器窗口,访问同一个页面(或多次刷新),注意访问间隔小于5秒,会发现多个页面得到相同的数字。事实上,这一数字并没有真实地反映出共享资源被访问的次数。

    为了解决这个问题,可以将页面代码修改如下:

        protected void Page_Load(object sender, EventArgs e)

        {

            lock (typeof(SharedClass))

            {

                 SharedClass.Counter++;

                 Response.Write("共享资源被访问次数:" + SharedClass.Counter.ToString());

            }

        }

     

    使用C#提供的lock关键字锁定资源现在,问题解决了。

    另一个有趣的问题是,如果由共享资源本身实现存取控制,是否访问者就不需要再写存取控制代码了?

    为此再次修改共享资源类:

    public class SharedClass

    {

        private static int _counter = 0;

     

        public static int Counter

        {

            get

            {

                lock (typeof(SharedClass))

                {

                     return SharedClass._counter;

                }

            }

            set

            {

                lock (typeof(SharedClass))

                {

                     //随机睡眠一段时间(5~10秒)

                Thread.Sleep((new Random()).Next(5000, 10000));

                SharedClass._counter = value;

                }

            }

        }

     

    但维持原有的页面访问代码不变:

     

    protected void Page_Load(object sender, EventArgs e)

        {

            SharedClass.counter++;

            Response.Write(SharedClass.counter.ToString());

        }

     

     情况会怎样?请感兴趣的朋友试一试,并思索一下出现这种现象的原因。

     

     

     

     

     

    发表于 @ 2008年01月07日 13:04:00|评论(loading...)|编辑

    新一篇: 使用泛型在VB.NET中实现VB6.0中的控件数组 | 旧一篇: 微软邹欣关于“清华-微软 软件科学实验班”的补充说明

    评论

    #eparg 发表于2008-01-07 21:42:00  IP: 58.41.84.*
    SharedClass.counter++;
    在现在的CPU上,已经是一个原子操作了。
    mov eax,addr
    inc eax
    mov addr,eax

    会被CPU在一个脉冲内做完。真的是做int++操作,不需要用锁。

    另外,你最后的代码,read操作,其实也不需要锁的。你要真的在read/write上都放锁,contention会会在data corruption发生前就弄死程序了。
    #zuilong1208 发表于2008-01-08 09:14:58  IP: 222.88.77.*
    其实你这样写,加快了你的程序的死亡!
    #gccr 发表于2008-01-08 09:39:26  IP: 59.151.58.*
    好像读不用加锁。
    #bitfan 发表于2008-01-08 09:47:24  IP: 222.131.59.*
    to eparg :
    SharedClass.counter++;是否真的原子操作?.NET生成的程序是托管的,编译之后所包含的是独立于CPU的IL指令,没有确切的证据表明CLR对类似于这样的代码都用原子操作完成。因为CPU不止一种,内部指令与体系结构也可能相差很大。
    事实上,对于int类自增的操作,.NET提供了Interlocked类来实现原子操作,MSDN中是这样描述的:
    在现代处理器中,Interlocked 类的方法经常可以由单个指令来实现。
    即使是Interlocked类,也不保证在所有CPU上一定以单指令实现。

    至于读和写操作是否要锁,这要看具体情况。在许多实际开发场景中,读和写操作都可能包含不止一句代码。我写这篇文章只不过是想说明对于多页面访问共享资源,如果不小心可能会带来一些非常难以重现的BUG。
    而且补充一下,如果不同的网页都需要存取共享资源,那么所有访问共享资源的代码都必须考虑线程同步,至于采用具体哪种同步手段,.NET提供了多种选择方式,不止使用锁这一种机制。

    因此,除非必要,尽量避免在Bin或App_code文件夹中放置公有静态成员作为共享资源。
    #007pro 发表于2008-01-08 12:48:35  IP: 125.34.196.*

    lock (typeof(SharedClass))

    {

    //随机睡眠一段时间(5秒~10秒)

    Thread.Sleep((new Random()).Next(5000, 10000));

    SharedClass._counter = value;

    }

    老大,你这么干活,大家就不用干了,你一跑,大家死一片。
    虽然你是教计算机得老师,但是要加深自己得业务学习啊,比如并发
    #ukyo1 发表于2008-01-08 13:28:20  IP: 61.141.93.*
    楼上的,人家加上Sleep只是仿真一下实际环境好不好?
    #hand741 发表于2008-01-14 18:30:37  IP: 61.144.230.*
    IIS已经自己解决了这种迸发的问题了
    public class SharedClass

    {

    public static int counter=0;

    }
    你就这么用就行了.

    Thread.Sleep((new Random()).Next(5000, 10000)); 你这么仿真是不对的....
    至于IIS,是不是自己LOCK静态对像来达到目的,小弟还不敢确定......
    但你今天这个"重大发现"纯属脱裤子放屁,多此一举
    #yawer 发表于2008-01-16 09:39:36  IP: 220.231.1.*
    其实提供了一种思路而已,只是让大家注意到这个问题。我想所有的多线程程序都应该注意到同步这种问题。这是一个最基本的知识。
    #aasheaa212 发表于2008-05-11 12:04:17  IP: 61.144.144.*
    老师是列举这样的现象,就是想在实际应用当中给我们借鉴,学习。我们得感谢老师的良苦用心啊。
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © bitfan(数字世界一凡人)