码迷,mamicode.com
首页 > 其他好文 > 详细

Lock

时间:2017-12-12 00:14:20      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:锁定   csharp   9.png   没有   为什么   nbsp   操作   mon   并发   

一、线程同步,先来看一下一段代码:

 Thread t1 = new Thread(new ThreadStart(() =>
            {
                //1.递增
                for (int i = 0; i < 10000000; i++)
                {
                    _count++;
                    //_count = _count + 1;//分为3个步骤,取到_count的值,把_count的值加1,把计算好的值重新赋值给_count
                }
            }));
            t1.Start();
            Console.WriteLine("t1线程已经启动,开始对_count变量++");
            Console.WriteLine("主线程继续执行.....");
            //2.递减
            for (int i = 0; i < 10000000; i++)
            {
                _count--;
            }

            //到这里的时候要保证主线程的--操作与t1线程的++操作都执行完毕
            //等待t1执行完毕
            t1.Join();
            Console.WriteLine("_count结果是:{0}", _count);
            Console.ReadKey();

结果是:

技术分享图片

这个结果是不是很惊讶?因为_count++或者_count--分为上述三个步骤! 线程什么时候执行或者暂停是由cpu决定的,我们可能在准备++的时候拿到的_count的值是1000,

但是线程暂停了,去执行_count--,它那边拿到的值也是1000,线程可能又转去执行++完之后是1001,赋给_count,但是之后执行--是999,再次赋给_count,结果就不对了。

二、解决并发访问变量问题

  static readonly object objSync = new object();
 Thread t1 = new Thread(new ThreadStart(() =>
            {
                //1.递增
                for (int i = 0; i < max; i++)
                {
                    lock (objSync)//向系统申请可不可以 锁定objSync对象 如果objSync对象没有被锁定,那么可以 如果objSync对象呗锁定了,那么这个语句会暂停,直到申请到mobjSync
//对象 { //在lock块中的代码同时只能有一个线程来访问。 _count++; }//释放第objSync的锁定 } })); t1.Start(); Console.WriteLine("t1线程已经启动,开始对_count变量++"); Console.WriteLine("主线程继续执行....."); //2.递减 //加锁后执行变慢!! for (int i = 0; i < max; i++) { lock (objSync) { _count--; } } //到这里的时候要保证主线程的--操作与t1线程的++操作都执行完毕 //等待t1执行完毕 t1.Join(); Console.WriteLine("_count结果是:{0}", _count); Console.ReadKey();

锁的本质是什么呢?我们反编译一下代码:

技术分享图片

可以看到就是  Monitor.Enter与  Monitor.Exit,我们改造一下上面的代码:

  Thread t1 = new Thread(new ThreadStart(() =>
            {
                //1.递增
                for (int i = 0; i < max; i++)
                {
                    //lock (objSync)
                    //{
                    //    //在lock块中的代码同时只能有一个线程来访问。
                    //    _count++;
                    //}
                    //标记当前是否已经上锁
                    bool isLockOk = false;
                    //上锁
                    Monitor.Enter(objSync, ref isLockOk);
                    try
                    {
                        _count++;
                    }
                    finally
                    {
                        if (isLockOk)
                        {
                            Monitor.Exit(objSync);
                        }
                    }

                }
            }));
            t1.Start();
            Console.WriteLine("t1线程已经启动,开始对_count变量++");
            Console.WriteLine("主线程继续执行.....");
            //2.递减
            //加锁后执行变慢!!
            for (int i = 0; i < max; i++)
            {
                lock (objSync)
                {
                    _count--;
                }

            }
            t1.Join();
            Console.WriteLine("_count结果是:{0}", _count);
            Console.ReadKey();

锁住的对象为什么不能是值类型呢?

Monitor.Enter或者Monitor.Exit的参数是object类型,如果传进来一个值类型,就会装箱,产生一个新的对象!那么这两次操作的对象都不是同一个对象,不是同一个地址,

所以只能用引用类型来当做所变量。

 

 

Lock

标签:锁定   csharp   9.png   没有   为什么   nbsp   操作   mon   并发   

原文地址:http://www.cnblogs.com/entclark/p/8025506.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!