我在接受采访时遇到了一个问题。
给定两个线程,每个线程都有一个锁,如何保证没有死锁。
我的知识是避免死锁并不容易,这就是我被卡住的原因。任何人都可以暗示一下。
谢谢!
答案 0 :(得分:11)
描述有点缺乏,但是如果你强制执行一个锁定顺序(例如,如果锁是A和B,除非你已经锁定A,否则永远不会锁定B,并且在B被锁定时永远不会释放A),然后死锁赢了不会发生。
答案 1 :(得分:3)
已知deadlock avoidance algorithms可以检测是否即将发生死锁并避免系统进入该状态。例如,Banker's Algorithm。
答案 2 :(得分:1)
使用单个锁定,除非一个人拒绝释放锁定,否则不可能陷入僵局 - 在这种情况下,等待线程被称为饥饿。对于多个锁,它们必须按照获取它们的相反顺序释放,并且两个线程必须就订单达成一致。
您要避免的是这种情况:
A锁定1等待锁定2
B锁2等待锁1
答案 3 :(得分:1)
锁定顺序优于超时/死锁检测,但有时需要超时,特别是如果您不控制系统中的所有组件:因此数据库中的死锁超时/检测。如果所有的呼叫者都足够聪明,那么永远不会发生死锁,但通常不是所有的呼叫者都足够聪明。
答案 4 :(得分:1)
面试官的答案可能是WaitForMultipleObjects()。这是一个同时锁定(或更多)资源的Windows API。
答案 5 :(得分:0)
并发/并行编程的许多工作都集中在无锁设计上。不是你的问题的确切答案,但正如安德鲁已经在这个帖子中提到的,避免死锁的最好方法是根本不锁定。很多非常聪明的人都在研究并发性问题。
答案 6 :(得分:0)
这是死锁的两个标准原因:
锁定订购死锁:
当两个线程尝试以不同的顺序获取相同的锁时,会发生这种情况。顺序将是这样的:
i)线程A获取Lock LEFT
ii)线程B获取Lock RIGHT
iii)线程A尝试锁定右侧
iv)线程B尝试锁定左侧
--->两人都会永远等待
解决方案:查看代码并确保没有循环锁定依赖项。如果线程会以相同的顺序询问锁定,则永远不会发生死锁。
动态锁定顺序死锁: 如果在运行时定义了锁并且您无法控制,则可能仍会出现上述情况,从而导致死锁。例如 -
void transferFund( Account A, Account B, Amount x)
{
synchronized(A)
{
synchronized(B)
{
// do transfer update balance
}
}
}
死锁的序列将是: 线程1 - transferFund(A1,B1,10); 线程2 - transferFund(B1,A1,20);
解决方案:修复避免这些死锁,引发一些逻辑以确保线程始终使用相同的顺序来获取锁。例如 -
if( A1.hashCode() < B1.hashCode())
{ Lock A1 then Lock B1 }
else
{ Lock B1 then Lock A1 }
注意:当您调用外来方法并且无法控制这些外来方法如何调用锁时,您无法避免死锁:(