很难找到死锁并且非常不舒服.
如何在代码中找到死锁的错误源?有没有"死锁模式"?
在我的特殊情况下,它处理数据库,但这个问题对每个死锁都是开放的.
更新:最近的MSDN文章,识别并发问题的工具和技术,也可能是有意义的
在MSDN文章死锁监视器中的Stephen Toub 说明了发生死锁所需的以下四个条件:
有限数量的特定资源.对于C#中的监视器(当你使用lock关键字时使用的是什么),这个有限的数字是一个,因为监视器是一个互斥锁(意味着一次只有一个线程可以拥有一个监视器).
保留一个资源并请求另一个资源的能力.在C#中,这类似于在释放第一个锁之前锁定一个对象然后锁定另一个对象,例如:
lock(a) { ... lock(b) { ... } }
没有先发制人的能力.在C#中,这意味着一个线程不能强制另一个线程释放锁.
循环等待条件.这意味着存在一个线程循环,每个线程都在等待下一个释放资源,然后才能继续.
他继续解释说避免死锁的方法是避免(或阻止)条件四.
Joe Duffy讨论了几种 避免和检测死锁的技术,包括一种称为锁定均衡的技术.在锁定级别中,锁定被赋予数值,并且线程必须仅获取具有比已经获取的锁更高的数字的锁.这可以防止循环的可能性.在当今的典型软件应用程序中,通常很难做得很好,并且在每次锁定获取时无法跟踪锁定均衡会导致死锁.
经典的死锁场景是A持有锁X并且想要获得锁Y,而B持有锁Y并且想要获得锁X.既然两者都不能完成他们想要做的事情,两者都将永远等待(除非超时是用过的).
在这种情况下,如果A和B以相同的顺序获取锁,则可以避免死锁.
确保所有事务以相同的顺序影响表是避免最常见的死锁的关键.
例如:
交易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上获得锁定,事务B在表B上获得锁定,因此在第二个命令完成之前,它们都没有锁定第二个命令.
所有其他形式的死锁通常是在分配资源的情况下通过高强度使用和内部SQL Server死锁引起的.
据我所知,没有死锁模式(以及编写大量多线程交易应用程序的12年).但是,TimedLock类在查找代码中存在的死锁时没有大量返工.
http://www.randomtree.org/eric/techblog/archives/2004/10/multithreading_is_hard.html
基本上,(在dotnet/c#中)使用"使用TimedLock.Lock(xxx)"搜索/替换所有"lock(xxx)"语句
如果检测到死锁(在指定的超时内无法获取锁定,默认为10秒),则抛出异常.我的本地版本也会立即记录堆栈跟踪.走上堆栈跟踪(最好使用行号进行调试构建),您将立即看到在故障点保持哪些锁,以及它试图获得哪个锁.
在dotnet 1.1中,在所描述的死锁情况下,运气会让所有被锁定的线程同时抛出异常.因此,您将获得2+堆栈跟踪,以及解决问题所需的所有信息.(2.0+可能已经在内部改变了线程模型,以至于不幸运,我不确定)