什么是死锁的常见原因?

死锁很难find,非常不舒服的删除。

我怎样才能find我的代码中的死锁的错误来源? 有没有“僵局模式”?

在我的特殊情况下,它处理数据库,但是这个问题对于每一个僵局都是开放的。

更新:这个最近的MSDN文章, 识别并发问题的工具和技术 ,也可能是有趣的


Stephen Toub在MSDN上的文章死锁监视器指出了发生死锁所必需的以下四个条件:

  • 数量有限的特定资源。 对于C#中的监视器(使用lock关键字时使用的内容),由于监视器是互斥锁(意思是一次只有一个线程可以拥有一个监视器),因此此限制数为1。

  • 持有一种资源并请求另一种资源的能力。 在C#中,这类似于locking一个对象,然后在释放第一个锁之前locking另一个对象,例如:

lock(a) { ... lock(b) { ... } } 
  • 没有抢占能力。 在C#中,这意味着一个线程不能强制另一个线程释放一个锁。

  • 一个循环的等待条件。 这意味着有一个线程循环,每个线程都在等待下一个释放资源,然后才能继续。

他继续解释说,避免僵局的方法是避免(或挫败)条件四。

Joe Duffy讨论了几种避免和检测死锁的技术,包括一种称为locking均衡的技术。 在locking级别中,锁被分配数字值,并且线程只能获得比已经获取的锁数量更多的锁。 这防止了循环的可能性。 在当今典型的软件应用程序中做得很好也是很困难的,而且每次锁获取失败都会导致死锁。

经典的死锁场景是A持有锁X并且想要获取锁Y,而B持有锁Y并且想要获得锁X.由于两个都不能完成他们正在尝试做的事情,所以最终会永远等待(除非超时用过的)。

在这种情况下,如果A和B以相同顺序获取锁,则可以避免死锁。

据我所知没有任何死锁模式(以及1​​2年的大量multithreading交易应用程序)。但是TimedLock类在寻找存在于代码中的死锁方面非常有帮助,而没有大量的返工。

http://www.randomtree.org/eric/techblog/archives/2004/10/multithreading_is_hard.html

基本上,(在dotnet / c#中)你用“使用TimedLock.Lock(xxx)”来search/replace你所有的“lock(xxx)”语句

如果检测到死锁(在指定的超时时间内无法获取locking,则默认为10秒),则会引发exception。 我的本地版本也立即logging堆栈跟踪。 走上堆栈跟踪(最好是使用行号进行debugging构build),您将立即看到在失败点保存了哪些锁,以及尝试获取哪个锁。

在dotnet 1.1中,在所描述的死锁情况下,幸运的是所有被locking的线程将同时抛出exception。 所以你会得到2+栈跟踪和解决问题所需的所有信息。 (2.0+可能已经改变了内部的线程模型,不能这么幸运,我不确定)

确保所有事务以相同的顺序影响表是避免最常见的死锁的关键。

例如:

交易A

 UPDATE Table A SET Foo = 'Bar' UPDATE Table B SET Bar = 'Foo' 

交易B

 UPDATE Table B SET Bar = 'Foo' UPDATE Table A SET Foo = 'Bar' 

事务A在表A上获取locking时,这极有可能导致死锁, 事务B在表B上获取locking,因此,在另一个完成之前,它们都不会获得第二个命令的locking。

所有其他forms的死锁通常是由高强度的使用和SQL Server在内部分配资源的同时发生死锁。

是 – 当进程尝试以随机顺序获取资源时发生死锁。 如果所有的进程都试图以相同的顺序获取相同的资源,那么死锁的可能性就会大大降低,如果不能消除的话。

当然,这并不总是很容易安排…

我推荐阅读Herb Sutter的这篇文章。 它解释了死锁问题背后的原因,并提出了解决这个问题的框架。

典型的情况是不匹配的更新计划(表不总是以相同的顺序更新)。 然而,在高处理量下,出现死锁并不罕见。

我倾向于接受僵局作为生活的一个事实,它会在某一天或那一天发生,所以我有我的DAL准备处理和重试一个僵持的操作。

最常见的(根据我不科学的观察)数据库死锁的情况很简单:

  • 两个进程读取某个数据(例如一个数据库logging),都获取相关资源上的共享锁(通常是一个DB页面),
  • 两个都试图进行更新,试图将他们的锁升级到独家的 – 瞧,僵局。

这可以通过指定“FOR UPDATE”子句(或类似的,取决于特定的RDBMS)来避免,如果读取之后是更新。 这样一来,进程从一开始就获得了独占locking,使上述情况变得不可能。

出现两个进程每个都等待其他进程完成的情况,结果是两个进程都是挂起的。 它最comonily多任务和clint /服务器。

死锁主要发生在存在多个从属锁的情况下。 在一个线程中,另一个线程尝试以相反的顺序locking互斥体。 一个人应该注意使用一个互斥体来避免死锁。

解除locking后,请务必完成操作。 如果您有多个锁,例如访问订单是ABC,则发布订单也应该是ABC。

在我上一个项目中,我遇到了SQL Server数据库中的死锁问题。 find原因的问题是,我的软件和第三方软件正在使用相同的数据库,并在同一个表上工作。 究竟是什么导致了僵局呢? 我结束了写一个SQL查询来找出哪些进程的SQL语句导致死锁。 你可以在这里find这个声明: SQL Server上的死锁

为了避免死锁,有一种叫做Bankeralgorithm的algorithm 。

这一个也提供了有用的信息, 以避免死锁。

Interesting Posts