Lock关键字调用Monitor.Enter(Object)或Enter(Object,Boolean)
本文关键字:Object Enter Boolean 关键字 Lock 调用 Monitor | 更新日期: 2023-09-27 18:00:27
在.NET Framework 4.5的Monitor文档中,我发现一句话,说lock关键字使用Monitor的Enter(Object,Boolean)方法:
Enter和Exit方法提供的功能与C#lock语句(Visual Basic中的SyncLock)提供的功能相同,只是lock和SyncLock将Enter(Object,Boolean)方法重载和Exit法包装在try…finally块(Visual Basic的try…finally)中,以确保监视器被释放。
另一方面,在监视器的Overview中有:
Visual Basic SyncLock和C#锁语句使用MonitorEnter获取锁,使用MonitorExit释放锁。
上面的MonitorEnter是指与以前不同版本的Enter方法,即:Enter(Object)
在Visual Studio 2012的线程同步(C#和Visual Basic)中,有一个锁包装Monitor的示例:
System.Object obj = (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
DoSomething();
}
finally
{
System.Threading.Monitor.Exit(obj);
}
还有Enter(对象)版本。
什么是真的?lock语句调用Enter(Object,Boolean)还是Enter(Object)?实际操作方式是否存在差异?
来自Eric Lippert的博客:
回想一下,
lock(obj){body}
(在C#3.0及更早版本中)是的语法糖var temp = obj; Monitor.Enter(temp); try { body } finally { Monitor.Exit(temp); }
这里的问题是,如果编译器在监视器输入和try保护区域之间生成无操作指令,则运行时可能在监视器输入之后但在try之前抛出线程中止异常。在这种情况下,finally永远不会运行,因此锁会泄漏,可能最终会使程序死锁。如果这在未优化和优化的构建中是不可能的,那就太好了。
在C#4.0中,我们更改了锁,这样它现在就可以像一样生成代码
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); { body } } finally { if (lockWasTaken) Monitor.Exit(temp); }
这个问题现在变成了别人的问题;Monitor.Enter的实现负责以一种不受线程中止异常干扰的方式原子地设置标志。
所以现在一切都很好,对吧?
遗憾的是,没有。[…]
另一方面,C#4.0语言规范说:
形式的锁定语句
lock (x) ...
其中x是引用类型的表达式,精确地等效于
System.Threading.Monitor.Enter(x); try { ... } finally { System.Threading.Monitor.Exit(x); }
除了x只被评估一次之外。