如何保证没有死锁

时间:2010-02-17 21:49:41

标签: multithreading deadlock

我在接受采访时遇到了一个问题。

给定两个线程,每个线程都有一个锁,如何保证没有死锁。

我的知识是避免死锁并不容易,这就是我被卡住的原因。任何人都可以暗示一下。

谢谢!

7 个答案:

答案 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)

这是死锁的两个标准原因:

  1. 锁定订购死锁:
    当两个线程尝试以不同的顺序获取相同的锁时,会发生这种情况。顺序将是这样的:
    i)线程A获取Lock LEFT
    ii)线程B获取Lock RIGHT
    iii)线程A尝试锁定右侧
    iv)线程B尝试锁定左侧
    --->两人都会永远等待

    解决方案:查看代码并确保没有循环锁定依赖项。如果线程会以相同的顺序询问锁定,则永远不会发生死锁。

  2. 动态锁定顺序死锁: 如果在运行时定义了锁并且您无法控制,则可能仍会出现上述情况,从而导致死锁。例如 -

    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 }
    
  3. 注意:当您调用外来方法并且无法控制这些外来方法如何调用锁时,您无法避免死锁:(