架构师_程序员_码农网

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 20407|回复: 0

[资料] c# lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然...

[复制链接]
发表于 2015-12-31 17:51:01 | 显示全部楼层 |阅读模式
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。

lock语句根本使用的就是Monitor.Enter和Monitor.Exit,也就是说lock(this)时执行Monitor.Enter(this),大括号结束时执行Monitor.Exit(this).他的意义在于什么呢,对于任何一个对象来说,他在内存中的第一部分放置的是所有方法的地址,第二部分放着一个索引,他指向CLR中的SyncBlock Cache区域中的一个SyncBlock.什么意思呢?就是说,当你执行Monitor.Enter(Object)时,如果object的索引值为负数,就从SyncBlock Cache中选区一个SyncBlock,将其地址放在object的索引中。这样就完成了以object为标志的锁定,其他的线程想再次进行Monitor.Enter(object)操作,将获得object为正数的索引,然后就等待。直到索引变为负数,即线程使用Monitor.Exit(object)将索引变为负数。

使用lock需要注意的地方:
1.lock不能锁定空值某一对象可以指向Null,但Null是不需要被释放的。(请参考:认识全面的null)
2.lock不能锁定string类型,虽然它也是引用类型的。因为字符串类型被CLR“暂留”
这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。因此,最好锁定不会被暂留的私有或受保护成员。
3.lock锁定的对象是一个程序块的内存边界
4.值类型不能被lock,因为前文标红字的“对象被释放”,值类型不是引用类型的
5.lock就避免锁定public 类型或不受程序控制的对象。
例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。
使用lock(this)的时候,类的成员变量的值可能会被不在临界区的方法改值了

应用场景:经常会应用于防止多线程操作导致公用变量值出现不确定的异常,用于确保操作的安全性

  1. // statements_lock2.cs
  2. using System;
  3. using System.Threading;

  4. class Account
  5. {
  6.     private Object thisLock = new Object();
  7.     int balance;

  8.     Random r = new Random();

  9.     public Account(int initial)
  10.     {
  11.         balance = initial;
  12.     }

  13.     int Withdraw(int amount)
  14.     {

  15.         // This condition will never be true unless the lock statement
  16.         // is commented out:
  17.         if (balance < 0)
  18.         {
  19.             throw new Exception("Negative Balance");
  20.         }

  21.         // Comment out the next line to see the effect of leaving out
  22.         // the lock keyword:
  23.         lock(thisLock)
  24.         {
  25.             if (balance >= amount)
  26.             {
  27.                 Console.WriteLine("Balance before Withdrawal :  " + balance);
  28.                 Console.WriteLine("Amount to Withdraw        : -" + amount);
  29.                 balance = balance - amount;
  30.                 Console.WriteLine("Balance after Withdrawal  :  " + balance);
  31.                 return amount;
  32.             }
  33.             else
  34.             {
  35.                 return 0; // transaction rejected
  36.             }
  37.         }
  38.     }

  39.     public void DoTransactions()
  40.     {
  41.         for (int i = 0; i < 100; i++)
  42.         {
  43.             Withdraw(r.Next(1, 100));
  44.         }
  45.     }
  46. }

  47. class Test
  48. {
  49.     static void Main()
  50.     {
  51.         Thread[] threads = new Thread[10];
  52.         Account acc = new Account(1000);
  53.         for (int i = 0; i < 10; i++)
  54.         {
  55.             Thread t = new Thread(new ThreadStart(acc.DoTransactions));
  56.             threads[i] = t;
  57.         }
  58.         for (int i = 0; i < 10; i++)
  59.         {
  60.             threads[i].Start();
  61.         }
  62.     }
  63. }
复制代码








上一篇:win8启动sql server2012服务
下一篇:[飞速]IP段开放端口扫描器,扫描速度很快!!!
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:help@itsvse.com

QQ|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2026-1-2 23:28

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表