C# 学习Lock关键字

为了避免多个线程同时操作同一资源,引起数据错误,通常我们会将这个资源加上锁,这样在同一时间只能有一个线程操作资源。在C#中我们使用lock关键字来锁定资源,那lock关键字是如何实现锁定的呢?

代码如下:
在这里插入图片描述
上面代码应该都能看懂,可以实现在某一时刻,只允许一个线程访问功能,避免多个线程同时访问。我们来看一下Lock的实现,其实Lock是C#的语法糖,本质上是C#的Monitor类,等价于下面代码:
在这里插入图片描述
我们接着讲。我们还是看lock(_lockObj)这一行,简单地想一想,lock关键字把_lockObj对象锁住了,别的线程就进不来了,那它是怎么锁的呢?是在对象上打了标记吗?是把线程ID打了标记吗?我们先看一下堆中_lockObj的对象结构。如下图:
在这里插入图片描述
可以看到,对象在堆中除了数据区以外,还有两片区域:MethodTableRef、SyncBlockValue。其中MethodTableRef是指向MethodTable中这个类型(Type)定义,简单说就是这个对象是什么class定义的。SyncBlockValue 就是Lock的重点了。如下图:
![
SyncBlockValue 这个值为DWORD类型,占用4个字节,也就是32位。一般将32位分为两段,前6位用以表示不同的功能(这里假设第5位是锁定位),后26位用以表示对象的hash值、或者是SyncBlock的索引值。
上锁过程:线程AB几乎同时访问Lock语句,A先到Lock查找第5位是否有值,无值则到图中的g_pSyncTable申请一个同步锁SyncBlock,并且在同步锁中记录A的线程ID信息,最后将同步锁地址赋值给后26bit,这样_lockObj就被线程A锁住。B后到同样查找第5位是否有值,发现被锁住了,然后去SyncBlock检查锁住的线程ID是否和自己一致,不一致的话,它就会一直等待,直到线程A释放锁。

注意:

1. Lock的是引用类型的对象,string类型除外,不能是值类型,编译会报错,并且不能为空。
2. Lock推荐的做法是使用静态的、只读的、私有的锁定对象。
3. 保证Lock的对象在外部无法修改才有意义,如果lock的对象在外部改变了,对其他线程就会畅通无阻,失去了Lock的意义。

以上是自己结合资料的理解,有错误请指正。

猜你喜欢

转载自blog.csdn.net/Ling_SevoL_Y/article/details/127793764
今日推荐