c#中lock作用,c#中lock
1.你为什么要上锁?你锁了什么?
当我们使用线程的时候,最高效的方式当然是异步,也就是每个线程同时运行,不需要互相依赖和等待。然而,当不同的线程需要访问一个资源时,就需要一个同步机制。也就是说,在对同一个资源进行读写操作时,一定要使资源同时只被一个线程操作,这样才能保证每一个操作都是有效的、即时的,也就是保证其操作的原子性。Lock是C#中最常用的同步方法,其格式为lock(objectA){codeB}。
Lock(objectA){codeB}看起来很简单,但它实际上有三个含义,这对于正确使用它是必不可少的:
1.对象a是否已被锁定?那我就不锁了,不然就等到objectA发布。
2.锁定后,在codeB执行期间,其他线程不能调用codeB或使用objectA。
3.执行完codeB后释放objectA,codeB可以被其他线程访问。
2.锁(这个)怎么了?
让我们看一个例子:
C1级
{
private bool死锁=true//这个方法使用了lock,我们希望lock的代码一次只能被一个线程访问。
public void LockMe(对象o)
{
锁(储物柜)
{
while(陷入僵局)
{
死锁=(bool)o;
控制台。WriteLine(Foo:我被锁定:();
线程。睡眠(500);
}
}
}
//所有线程可以同时访问的方法
public void DoNotLockMe()
{
控制台。WriteLine(我没有被锁定:));
}
}班级计划
{
静态void Main(string[] args)
{
C1 c1=新C1();
//调用t1线程中的LockMe,并将deadlock设置为true(会发生死锁)
线程t1=新线程(c1。lock me);
t1。开始(真);
线程。睡眠(100);
//在主线程中锁定c1
锁定(c1)
{
//调用未被锁定的方法
c1。DoNotLockMe();
//调用lock方法,尝试释放死锁。
c1。LockMe(假);
}
}
}
程序运行结果如上图所示。在t1线程中,LockMe调用lock(this),这是主函数中的c1。此时,在主线程中调用lock(c1)时,要等t1中的lock块结束后才能访问c1,也就是所有c1相关的操作都无法完成,所以我们看到,即使是c1。DoNotLockMe()尚未执行。
我们稍微修改一下C1的代码,保持mian()主函数中的代码不变:
C1级
{
private bool死锁=true
私有对象锁=新对象();
//这个方法使用了lock,我们希望lock的代码一次只能被一个线程访问。
public void LockMe(对象o)
{
锁(储物柜)
{
while(陷入僵局)
{
死锁=(bool)o;
控制台。WriteLine(Foo:我被锁定:();
线程。睡眠(500);
}
}
}
//所有线程可以同时访问的方法
public void DoNotLockMe()
{
控制台。WriteLine(我没有被锁定:));
}
}
程序运行结果如上图所示。这一次,我们使用一个私有成员作为锁柜,并且在LockMe中只锁定这个私有锁柜,而不是整个对象。此时再次运行程序,可以看到即使t1出现死锁,DoNotLockMe()仍然可以被主线程访问;LockMe()仍然不可访问,因为t1还没有释放其中锁定的锁。
关键点:
1.lock (this)的缺点是,一个线程(比如本例中的t1)通过执行使用 lock(this)的类的方法(比如本例中的LockMe())锁定一个对象后,整个对象就不能被其他线程(比如本例中的主线程)访问了——因为很多人在其他线程(比如本例中的主线程)使用这个类时会使用类似的方法。
2.锁定的不仅仅是锁段中的代码,锁本身也是线程安全的。
3.我们应该使用不影响其他操作的私有对象作为locker。
4.使用lock时,锁定的对象(locker)必须是引用类型。如果是值类型的话,那么每次被锁的时候都会被装箱成一个新的引用对象(其实如果你用值类型的话,C#编译器(3.5.30729.1)编译的时候会报错)。
C的值类型包括:结构(数值型、bool型、自定义结构)、枚举、可空型。C的引用类型包括:数组、用户定义的类、接口、委托、对象和字符串。
因此,如果有如下定义:
A级
{
}
结构S
{
}
int I;
对象o;
字符串str
A A=new A();
S S=new S();
请注意下面的语法是正确的还是错误的。
Lock(i){}//错误
Lock(o){}//正确
Lock(str){}//正确
Lock(a){}//正确
锁{}//错误
Lock语句基本上使用Monitor。进入并监控。退出,也就是说,监控。使用lock(this)时执行Enter(this ),并监视。Exit(this)在花括号结束时执行。他的意义是什么?对于任何对象,所有方法的地址都放在其内存的第一部分。在第二部分,有一个索引,它指向CLR的SyncBlock缓存区中的一个SyncBlock。这是什么意思?也就是说,当您执行Monitor。Enter(Object),如果对象的索引值为负,则从SyncBlock缓存中选择一个SyncBlock,将其地址放入对象的索引中。这样,object标记的锁就完成了。如果其他线程想要执行监控。再次进入(object)操作,它们将得到object为正的索引并等待。直到索引变成负数,也就是线程使用Monitor。Exit(object)使索引为负。
system . threading . monitor . enter(x);
尝试
{
.
}
最后
{
system . threading . monitor . exit(x);
}
一些系统类提供专用于锁定的成员。例如,数组类型提供SyncRoot。许多集合类型也提供SyncRoot。和自定义类推荐私有只读静态对象,例如:
私有静态只读对象obj=new object();
为什么要设置为只读?这时,如果你改变锁代码段中obj的值,其他线程将不受阻碍,因为互斥的对象已经改变,而对象。ReferenceEquals将不可避免地返回false。
其他参考连接:
http://www.jb51.net/article/57220.htm
http://www.2cto.com/kf/201110/108043.html
http://www.csharpwin.com/csharpspace/12362r6119.shtml
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。