有人能详细解释一下为什么可以在C#中的任何类型的对象上lock
吗?
我了解lock
的用途以及如何使用它。我知道它是如何扩展到Monitor.Enter
/Exit
的。我想要的是对实现细节和设计注意事项的解释。
首先:引擎盖下面发生了什么?例如:对象实例中是否有额外的位(比如RTTI/vtable)使其工作?或者某种基于对象引用的查找表?(如果是,这是如何与GC交互的?)或者其他什么?为什么我不必创建一个特定类型的实例来保存锁数据呢?
(顺便问一下,Enter
和Exit
在本机代码中映射到什么?)
其次,为什么被设计为没有特定类型的锁?(考虑到你通常只是为了这个目的而制作一个new object()
,而且大多数锁定"任何旧对象"的情况都是有问题的。)这种设计选择是由实现细节强迫的吗?还是故意的?如果经过深思熟虑,这是一个好的选择吗?(我意识到第二部分可能需要猜测。)
可以在所有非struct
类型上使用lock
。在堆上每个引用类型的布局中,都有一个用于管理锁的特殊字段(同步块)。CLR如何创建运行时对象中详细介绍了该布局。文章摘录如下:
OBJECTREF不指向对象实例的开头,而是指向DWORD偏移量(4字节)。DWORD被称为对象头,它在SyncTableEntry表中保存一个索引(一个基于1的syncblk编号)。
堆上的对象布局:
sync block index
pointer to type
fields...
推测部分:我相信最初的指导是锁定任何方便的东西,但由于很容易获得外部代码来死锁方法,它很快就被更改为具有特殊的"用于锁定的私有对象"。我认为Framework中甚至有一些类在锁定公共可见对象方面做得很好。。。