在Release It!中,Michael Nygard认为许多灾难性的系统故障通常是由一连串的事情导致的。例如,两个线程死锁。现在线程池中的线程少了两个,因此其他线程上的负载增加会增加其死锁的可能性。突然,服务器根本没有响应,因为线程池耗尽,导致负载均衡器将流量转移到其他服务器(所有服务器都运行相同的代码),这增加了他们的可能性死锁突然整个农场都处于脱机状态。
大多数RDBMS服务器检测到死锁并决定“失败者”(一个事务被中止,另一个事务可以继续)。相反,在C#中, lock 语句将无限期地等待获取锁定。
但是,您可以调用Monitor.TryEnter(lockObject, TimeSpan)来请求锁定或超时。如果超时到期并且无法获取锁定,则返回false。有些人wrapped this in using statements保持良好的语法。
所以我的问题是,你是否总是使用超时获取锁定?除了死锁情况外,超时会产生哪些问题?
答案 0 :(得分:5)
我通常会使用超时。这里最大的问题是,如果达到超时,请求操作将被中止。这显然更适合死锁。但是有一个更大的问题:如果操作很关键并且你因为其他东西已经死锁而开始中止,如果你的设计不合理,你可能最终导致你通过这种方法描述的农场减少问题(虽然更软:你的应用程序将不再有效,但你没有失去控制权。)
主要区别在于你实际上有控制权,而如果线程开始死锁,那么在你的代码中没有什么可以在失败开始后解决问题。
答案 1 :(得分:1)
作为一般规则,我从不创建具有无限超时的锁。它只会导致难以发现和难以调试的死锁。添加超时检查不需要任何额外的工作,即使它只是抛出异常,如果你遇到死锁,它几乎会立即通知你。更重要的是,它可以帮助您找到可能不会导致完全死锁的Bulock瓶颈。
答案 2 :(得分:1)
你可以优雅地从锁定尝试超时的情况中恢复吗?如果你可以通过各种方式使用超时。如果你不能,那么超时并不是很重要。当你恢复执行时你打算做什么?最多可以退出并显示错误消息。超时有其用途,但它们也可以用来隐藏细微的线程错误,所以我认为最好的建议是谨慎使用。
答案 3 :(得分:0)
可以证明不会发生死锁。也可以在运行时证明即使不依赖于竞争条件也可能发生死锁(例如,参见Linux的lockdep)。
因此,始终尝试锁定没有意义。这取决于具体情况。