6

释放它!, Michael Nygard 解释说,许多灾难性的系统故障往往是由一连串的错误引起的。例如,两个线程死锁。现在线程池中的线程减少了两个,因此其他线程上的负载增加,从而增加了死锁可能性。突然,服务器根本没有响应,因为线程池耗尽,这导致负载均衡器将流量转移到其他服务器(它们都运行相同的代码),这增加了它们发生死锁的可能性。突然整个农场都离线了。

大多数 RDBMS 服务器检测死锁并决定一个“失败者”(一个事务被中止,另一个可以继续)。相比之下,在 C# 中,lock语句将无限期地等待获取锁。

但是,您可以调用Monitor.TryEnter(lockObject, TimeSpan)来请求锁定或超时。如果超时到期并且无法获取锁,则返回 false。有些人将其包装在 using 语句中以保持良好的语法。

所以我的问题是,您是否总是使用超时获取锁?与死锁场景相比,超时会产生哪些问题?

4

4 回答 4

6

我通常使用超时。这里最大的问题是,如果达到超时,请求操作将被中止。这显然比死锁更可取。但是那里有一个更大的问题:如果操作很关键并且您因为其他事情陷入僵局而开始中止,如果您的设计不合理,您最终可能会导致您通过这种方法描述的农场下降问题(虽然更软:你的应用程序将不再工作,但你并没有失去控制)。

主要区别在于您实际上在这里拥有控制权,而如果线程开始死锁,那么一旦故障开始,您就无法在代码中解决问题。

于 2009-01-30T19:52:46.040 回答
1

作为一般规则,我从不创建具有无限超时的锁。它只会导致难以发现和难以调试的死锁。添加超时检查不需要任何额外的工作,即使它只是抛出异常,并且如果您遇到死锁,它几乎会立即通知您。更重要的是,它可以帮助您找到可能不会导致完全死锁的 bu 锁的瓶颈。

于 2009-01-30T19:54:14.587 回答
1

您能否从锁定尝试超时的情况中优雅地恢复?如果可以,那么一定要使用超时。如果你不能,那么超时就没有什么意义了。当你恢复执行时你会做什么?充其量您可以退出并显示错误消息。超时有其用途,但它们也可以用作隐藏微妙线程错误的一种方式,因此我认为最好的建议是谨慎使用。

于 2009-01-30T19:58:01.070 回答
0

可以证明不会发生死锁。也可以在运行时证明即使不依赖于竞争条件也可能发生死锁(例如,参见 Linux 的lockdep)。

因此,总是尝试锁定是没有意义的。这取决于情况。

于 2009-01-30T19:54:29.483 回答