我在代码审核期间建议
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
}
它有什么不同?第一个代码不如何表现出第二个会出现错误的错误?
答案 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/如何实现此方法,但正如我所说,这是一个实现细节。