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

Tim*_*ith 3 c#

在代码审查期间我被建议做

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

而不是更简单

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

它有什么不同?第一个代码怎么能没有出现第二个代码会出现错误的错误?

Jon*_*eet 6

假设你的第二个片段实际上Monitor.Exit是在调用,文档中解释了差异:

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

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

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