临界区:当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竞态条件发生的代码区称作临界区。
临界区线程同步适用范围:它只能同步一个进程中的线程,不能跨进程同步。一般用它来做单个进程内的代码快同步,效率比较高。
在.Net中有Monitor、Lock等方式是以临界区的方式来实现线程同步的,我们看一下两者的具体示例。
1、Lock Lock关键字将代码块标记为临界区,方法是获取指定对象的互斥锁,执行语句,然后释放锁,这样其它线程就可以接着获取锁来进入临界区。
Lock关键字保证了临界资源在同一时刻只能有唯一一个线程访问,一旦有线程获取互斥锁,进入临界区,其它线程访问时就会被挂起,直到当前线程释放锁。
private static object lockObj = new object(); lock(lockObj) { //操作公共资源 }
对于任何一个引用对象都存在一个索引,该索引指向CLR中SyncBlock Cache中的SyncBlock。当执行lock(object)时,如果object索引值为负数,就从SyncBlock Cache
中取出一个SyncBlock,存入object索引值,这样object索引值就变成了正数。当有其它线程再进入时lock(object)时发现object索引值不为负,责挂起等待,直到object索引
值变为负数。
使用lock应注意
1)lock不能锁定null值
2)lock不能锁定string类型的值,虽然它是引用类型,旦字符串类型被CLR暂留
3)lock锁定的必须是引用类型,不能是值类型
4)lock避免锁定public对象,因为公开的对象可能被其它类进行修改,很可能导致死锁。如lock(this)时,当前对象的公开属性值被修改后,会造成线程安全问题
2、Monitor的用法
Monitor类使用Enter(object)和Exit(object)来标示临界区,事实上lock使用的原理就是Monitor。当lock开始是调用就是monitor.Enter(object),当lock结束时
则调用monitor.Exit(object)释放object锁。