代码2执行到lock(this)后b被锁定

时间:2021-09-18 09:10:51

在c#中有个关键字lock,它的感化是锁定某一代码块,让同一时间只有一个线程访谒该代码块,本文就来谈谈lock关键字的道理和此中应注意的几个问题:


lock的使用原型是:

lock(X) { //需要锁定的代码.... }

首先要大白为什么上面这段话能够锁定代码,此中的玄妙就是X这个东西,事实上X是任意一种引用类型,它在这儿起的感化就是任何线程执行到lock(X)时候,X需要独享才华运行下面的代码,若假定此刻有3个线程A,B,C都执行到了lock(X)而ABC因为此时都占有X,这时ABC就要停下来排个队,一个一个使用X,从而起到不才面的代码块内只有一个线程在运行(因为此时只有一个线程独享X,其余两个在排队),所以这个X必需是所有要执行临界区域代码进程必需共有的一个资源,从而起到按捺线程的感化。

下面再来谈谈lock使用中会遇到和注意的问题,lock最需要注意的一个问题就是线程死锁!

在MSDN上列出了3个范例问题:

凡是,应制止锁定 public 类型,否则实例将超过代码的控制范畴。常见的布局 lock (this)、lock (typeof (MyType)) 和 lock (“myLock”) 违反此准则:


如果实例可以被大众访谒,将呈现 lock (this) 问题。


如果 MyType 可以被大众访谒,将呈现 lock (typeof (MyType)) 问题。


由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以呈现 lock(“myLock”) 问题。


最佳做法是界说 private 东西来锁定, 或 private shared 东西变量来掩护所有实例所共有的数据。


(1)lock (this) 问题:

假定有两个类:

class A{} class B{}

有两个大众东西:

A a=new A(); B b=new B();

首先在A中若有一函数内的代码需要锁定:

代码1:

lock(this)//this在这里就是a { //.... lock(b) { //...... } }

然而此时B中某函数也有如下代码需要锁定:

代码2:

lock(this)//this在这里就是b { //.... lock(a) { //...... } }

设想一下上面两段代码在两个线程下同时执行会有什么后果?

功效就是,代码1执行到lock(this)后a被锁定,代码2执行到lock(this)后b被锁定,然儿女码1需求b,代码2需求a,此时两个需求都被彼此占有呈现僵持状态,措施死锁了。


(2)lock(typeof (MyType))问题:

假定有两个大众变量:

int a;float b;

下面看如下代码

代码3:

lock(typeof(a))//typeof(a)就是System.type.Int类型 { //.... lock(typeof(b)) { //...... } }

又有如下代码:

代码4:

lock(typeof(b))//typeof(b)就是System.type.Float类型 { //.... lock(typeof(a)) { //...... } }

若有两个进程分袂同时进入上面两个代码外层的lock,就分袂锁定了System.type.Int和System.type.Float,而顿时它们又需求System.type.Float和System.type.Int,相互彼此占有,相互僵持,措施进入死锁状态!


(3)字符串问题 :

在论述这个问题之前,有一个常识大家必需知道:C#中字符串被大众语言运行库 (CLR)“暂留”。这意味着整个措施中任何给定字符串都只有一个实例,就是这同一个东西暗示了所有运行的应用措施域的所有线程中的该文本。因此,只要在应用措施进程中的任何位置处具有不异内容的字符串上安排了锁,就将锁定应用措施中该字符串的所有实例。

言下之意就是假定有两个类分袂有两个字符串:

class A { string a="abc"; string b="def"; } class c { string c="abc"; string d="def"; }

事实上a和c引用的是同一个字符串”abc”,b和d引用的是同一个字符串”def”

此刻如果在两个类中有如下代码

在类A中有代码5:

lock(b)//b是"def" { //.... lock(a)//a是"abc" { //...... } }

在类B中有代码6:

lock(c)//c是"abc" { //.... lock(d)//d是"def" { //...... } }

那么代码5和代码6同时有两个线程执行功效可想而知:在两个线程执行到外层lock代码时”def”和”abc”被锁定。接着他们在内部lock处同时需求”abc”和”def”,而此时两个字符串被两个进程相互占有,,措施又死锁了!所以MSDN说:锁定字符串尤其危险!最好不要使用!

MSDN最后说了:最佳做法是界说 private 东西来锁定, 或 private shared 东西变量来掩护所有实例所共有的数据。

在小我私家看来,也不是绝对安适,这里就举出一个例子:

假定有一个类:

class A { private Object a=new Object(); private Object b=new Object(); public void x() { lock(a) { //..... lock(b) { //.... } } } public void y() { lock(b) { //..... lock(a) { //.... } } } }

此刻假定有两个线程同时执行函数x()和y();功效private东西a和b分袂在外层lock锁定,接着两个线程在内部又立马需求b和a,a,b相互占有又相互需求,措施死锁。

所以具体要看情况而定,但是界说 private 东西来锁定至少可以降低危害。