锁定关键字调用Monitor.Enter(Object)或Enter(Object,Boolean)?

时间:2013-02-22 12:05:38

标签: c# .net locking monitor

在.NET Framework 4.5的Monitor文档中,我找到了一个句子,它说lock关键字使用Monitor的Enter(Object, Boolean)方法:

  

Enter和Exit方法提供的功能与C#lock语句(Visual Basic中的SyncLock)提供的功能相同,只是lock和SyncLock将Enter(Object,Boolean)方法重载和Exit方法包装在一起。尝试... finally块(尝试...最后在Visual Basic中)以确保释放监视器。

另一方面,在Monitors的问题中,有:

  

Visual Basic SyncLock和C#lock语句使用MonitorEnter获取锁定,MonitorExit使用它来释放它。

上面的MonitorEnter指的是与之前版本不同的Enter方法版本,即:Enter(Object)

Thread Synchronization (C# and Visual Basic) for Visual Studio 2012中,有一个示例锁定如何监视Monitor:

System.Object obj = (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
    DoSomething();
}
finally
{
    System.Threading.Monitor.Exit(obj);
}

还有Enter(Object)版本。

什么是真的? 锁定语句会调用Enter(Object, Boolean)还是Enter(Object)? 它是如何真正完成的有什么不同?

1 个答案:

答案 0 :(得分:5)

来自Eric Lippert’s Blog

  

回想一下,lock(obj){body} [在C#3.0及更早版本]是

的语法糖
var temp = obj;
Monitor.Enter(temp);
try { body }
finally { Monitor.Exit(temp); }
     

这里的问题是,如果编译器在监视器输入和try-protected区域之间生成无操作指令,那么运行时可能会在监视器输入之后但在尝试之前抛出线程中止异常。在那种情况下,最终永远不会运行,因此锁泄漏,可能最终导致程序死锁。如果在未经优化和优化的构建中这是不可能的,那将是很好的。

     

在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 Language Specification说:

  

表单的锁定声明

lock (x) ...
     

其中x是引用类型的表达式,恰好等同于

System.Threading.Monitor.Enter(x);
try {
   ...
}
finally {
   System.Threading.Monitor.Exit(x);
}
     

除了x只被评估一次。