什么是僵局?
编写多线程应用程序时,遇到的最常见问题之一是死锁。
我对社区的问题是:
- 什么是僵局?
- 我们如何检测到它们?
- 你会处理吗?
- 最后,我们如何防止它们发生?
解决方案
回答
当多个进程尝试同时访问同一资源时,将发生锁定。
一个过程失败了,必须等待另一个过程完成。
当等待进程仍保留第一个需要完成的另一个资源时,就会发生死锁。
举个例子:
资源A和资源B由流程X和Y使用
- X开始使用A。
- X和Y尝试开始使用B
- Y"获胜"并首先获得B
- 现在Y需要使用A
- A被X锁定,正在等待Y
避免死锁的最佳方法是避免进程以这种方式交叉。尽可能减少锁定任何东西的需要。
在数据库中,请避免在单个事务中对不同表进行大量更改,避免使用触发器,并尽可能切换到乐观/脏/无锁读取。
回答
当两个线程获得锁定而阻止它们中的任何一个前进时,就会发生死锁。避免它们的最佳方法是精心开发。许多嵌入式系统通过使用看门狗计时器(计时器在系统挂起一定时间后重置系统)来保护它们。
回答
当线程正在等待永远不会发生的事情时,就会发生死锁。
通常,它发生在线程正在等待以前所有者从未释放过的互斥量或者信号量时。
当我们遇到涉及两个线程和两个锁的情况时,也经常发生这种情况:
Thread 1 Thread 2 Lock1->Lock(); Lock2->Lock(); WaitForLock2(); WaitForLock1(); <-- Oops!
通常,我们检测到它们是因为我们期望发生的事情永远不会发生,或者应用程序完全挂起。
回答
只有当我们同时拥有两个或者两个以上的锁并且以不同的顺序抓住它们时,才会发生死锁。
避免出现死锁的方法是:
- 避免有锁(如果可能的话),
- 避免有多个锁
- 始终以相同的顺序锁。
回答
死锁是系统的一种状态,其中没有单个进程/线程能够执行操作。正如其他人所提到的,死锁通常是每个进程/线程希望获取对已被另一个(甚至相同)进程/线程锁定的资源的锁定的情况的结果。
有多种方法可以找到它们并避免它们。一个人非常努力地思考和/或者尝试了许多事情。但是,处理并行性非常困难,并且大多数(如果不是全部)人将无法完全避免问题。
如果我们认真对待此类问题,则可以使用一些更正式的方法。我知道的最实用的方法是使用过程理论方法。在这里,我们可以使用某种过程语言(例如CCS,CSP,ACP,mCRL2,LOTOS)对系统进行建模,并使用可用的工具来对死锁(也可能还有其他一些属性)进行(建模)检查。使用的工具集示例包括FDR,mCRL2,CADP和Uppaal。一些勇敢的灵魂甚至可以通过使用纯粹的象征性方法来证明他们的系统没有死锁(定理证明;寻找Owicki-Gries)。
但是,这些形式化方法通常确实需要付出一些努力(例如,学习过程理论的基础知识)。但是我想这仅仅是这些问题很难解决的结果。