Monitor.TryEnter(lockObject,timeout)是否过载不安全? (。净)

时间:2015-02-24 18:36:45

标签: c#

我在代码审核期间建议

bool acquiredLock = false;
try {
    Monitor.TryEnter(lockObject, 500, ref acquiredLock);
    if (acquiredLock) {
        // do something
    }
    else {
        // fallback strategy
   }
}
finally
{
    if (acquiredLock)
    {
        Monitor.Exit(lockObject);
    }
}

而不是更简单的

if (Monitor.TryEnter(lockObject, 500)) {
      try {
          // do something...
      } 
      finally {
          Monitor.Exit(lockObject);
      }
} else {
     // fallback strategy
}

它有什么不同?第一个代码如何表现出第二个会出现错误的错误?

4 个答案:

答案 0 :(得分:6)

假设在您的第二个片段中实际致电Monitor.Exit,差异在the documentation中解释:

  

此重载始终设置传递给ref参数lockTaken的变量的值,即使该方法抛出异常,因此变量的值是测试是否可靠的方法锁必须被释放。

换句话说,使用第二个代码段,在获取锁之后但在方法返回之前抛出异步异常(例如,线程被中止)可能是可行的。即使有finally块,您也无法轻易判断是否需要释放锁定。使用ref参数,获取"监视器"和" ref参数设置为true"动作是原子的 - 当方法退出时变量具有错误的值是不可能的,但它会退出。

从C#4开始,当针对支持此重载的平台时,这也是C#编译器生成的代码。

答案 1 :(得分:0)

当第二个片段没有时,您的第一个片段正在退出显示器。您希望在完成关键程序段后释放监视器。

答案 2 :(得分:0)

除了关于退出其他海报的完全有效点之外...... documentation for the TryEnter method声明它可以抛出三个例外中的一个,所以从技术上讲,是的,它可能会在特定情况下轰炸你的应用程序。

答案 3 :(得分:0)

即使该方法名为TryEnter,它实际上也会引发异常,您需要正确处理它们。如果它抛出异常并且您没有处理它并释放监视器,则可能会出现死锁情况。

这可能有点过于谨慎,因为如果你看看它实际抛出的异常,它会在尝试获取锁之前很可能抛出它们。但这是一个实现细节,你无法确定它。

您可以查看http://referencesource.microsoft.com/如何实现此方法,但正如我所说,这是一个实现细节。

相关问题