c# lock用法

  • A+
所属分类:Unity3d

lock 的目的很明确:就是不想让别人使用这段代码,体现在多线程情况下,只允许当前线程执行该代码区域,其他线程等待直到该线程执行结束;这样可以多线程避免同时使用某一方法造成数据混乱。

一般定义如下:

private static readonly object obj = new object();

lock(obj)

{

'''代码块

}

 

MSDN给出:我们lock的一般是对象,不是数值和字符串。

  1、为什么不能lock值类型

比如lock(1)呢?lock本质上Monitor.Enter,Monitor.Enter会使值类型装箱,每次lock的是装箱后的对象。lock 其实是类似编译器的语法糖,因此编译器直接限制住不能lock值类型。退一万步说,就算能编译器允许你lock(1),但是 object.ReferenceEquals(1,1)始终返回false(因为每次装箱后都是不同对象),也就是说每次都会判断成未申请互斥锁,这样 在同一时间,别的线程照样能够访问里面的代码,达不到同步的效果。同理lock((object)1)也不行。

    2、Lock字符串

那么lock("xxx")字符串呢?MSDN上的原话是:

锁定字符串尤其危险,因为字符串被公共语言运行库 (CLR)“暂留”。 这意味着整个程序中任何给定字符串都只有一个实例,同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何 位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。

    3、MSDN推荐的Lock对象

通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于 对象)也可能导致问题。

而且lock(this)只对当前对象有效,如果多个对象之间就达不到同步的效果。

而自定义类推荐用私有的只读静态对象,比如:

private static readonly object obj = new object();

为什么要设置成只读的呢?这是因为如果在lock代码段中改变obj的值,其它线程就畅通无阻了,因为互斥锁的对象变了,object.ReferenceEquals必然返回false。

 

 

用法:

private void Do()
{
thread t1=new thread(doSomething);
thread t2=new thread(doSomething);
t1.Start();
t2.Start();
}
private static readonly object locker= new object();
private void doSomething()
{
...........
.........
lock(locker)
{
FunLog() ;
}
........
}

比如说上面这样,当t1执行到lock时,检测发现locker不在锁定列表中,它会记录locker的内存地址,加入到锁定列表,并开始执行lock的锁定代码段;t2再执行到lock时,检测发现locker的内存地址是在锁定列表中的,于是线程等待;t1执行完FunLog到达lock结尾,将locker地址从锁定列表删除;t2检测发现locer已不在锁定列表中,它会记录locker的内存地址,加入到锁定列表,并进入执行lock的代码段。

weinxin
我的微信
这是我的微信扫一扫
maple

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: