编程中出现死锁问题的常见程度如何?

时间:2009-09-01 06:19:59

标签: deadlock

我用多种语言编程,但我不知道代码中存在死锁。

我认为这意味着它不会发生。

这是否经常发生(在编程中,数据库中的),我应该关注它吗?

6 个答案:

答案 0 :(得分:14)

如果两个条件成立,可能会出现死锁:你有多个theads,他们争夺多个资源。

你写多线程代码吗?您可以通过启动自己的线程来明确地执行此操作,或者您可以在创建线程的框架中工作,这样您就可以在多个线程中运行,而无需在代码中看到它。

示例:Java Servlet API。你编写了一个servlet或JSP。您部署到应用程序服务器。有几个用户访问了您的网站,因此也访问了您的servlet。服务器可能每个用户都有一个线程。

现在考虑如果在为请求提供服务时需要获取某些资源会发生什么:

if ( user Is Important ){
     getResourceA();
}

getResourceB();

if (today is Thursday ) {
    getResourceA();
} 


// some more code

releaseResourceA();
releaseResoruceB();

在上面的人为举例中,考虑周四当重要用户的请求到来时会发生什么,并且或多或少地同时发生不重要用户的请求。

重要用户的线程获得Resoruce A并且想要B.不太重要的用户获得资源B并且想要A.也不会释放他们已经拥有的资源...死锁。

如果您正在编写明确使用同步的代码,这实际上很容易发生。最常见的是,我发现在使用数据库时会发生这种情况,幸运的是,数据库通常会出现死锁检测,因此我们可以找出错误。

防范僵局:

  1. 以明确定义的顺序获取资源。在最后的示例中,如果资源A总是在资源B之前获得,则不会发生死锁。
  2. 如果可能,请使用超时,这样您就不会无限期地等待资源。这将允许您检测争用并应用防御1。

答案 1 :(得分:9)

很难想象它在现实中发生的频率(在生产代码中?在开发中?)并且这并不能真正了解多少代码易受攻击无论如何。 (通常情况下,僵局只会在非常特殊的情况下发生。)

我见过几次,虽然最近看到的是Oracle驱动程序(根本不在数据库中),因为终结器在另一个线程试图获取连接的同时运行。幸运的是,我发现了另一个错误,让我首先避免终结器运行...

基本上死锁几乎总是由于试图获得一个锁(B)同时持有另一个(A),而另一个线程反过来完全相同。如果一个线程正在等待B被释放,并且持有B的线程正在等待A被释放,则两个线程都不愿意让另一个继续。

确保您始终以相同的顺序获取锁(并以相反的顺序释放它们),并且在大多数情况下您应该能够避免死锁。

有些奇怪的情况你没有直接有两个锁,但它的基本原理是一样的。例如,在.NET中,您可以使用工作线程中的Control.Invoke来更新UI线程上的UI。现在Invoke等待更新处理后再继续。假设您的后台线程持有锁更新需要...再次,工作线程正在等待UI线程,但UI线程无法继续,因为工作线程持有锁。再次陷入僵局。

这是一种需要注意的模式。如果您确定只锁定了所需的位置,请锁定尽可能短的时间段,并记录所有代码的线程安全和锁定策略,应该能够避免死锁。但是,与所有线程主题一样,说起来容易做起来难。

答案 2 :(得分:4)

如果有机会,请查看Java Concurrency in Practice中的前几章。

死锁可能发生在任何并发编程情况中,因此它取决于您处理多少并发。并发编程的几个例子是:多进程,多线程和引入多线程的库。 UI框架,事件处理(例如计时器事件)可以作为线程实现。 Web框架可以生成线程以同时处理多个Web请求。使用多核CPU,您可能会比以前看到更多并发情况。

如果A正在等待B,并且B正在等待A,则循环等待会导致死锁。因此,它还取决于您编写的代码类型。如果使用分布式事务,则可以轻松导致该类型的方案。如果没有分布式交易,您就有可能冒银行账户偷钱。

答案 3 :(得分:3)

全部取决于您编码的内容。不使用锁定的传统单线程应用程序。不是真的。

具有多个锁的多线程代码会导致死锁。

我刚刚完成了重构代码,该代码使用了七个不同的锁而没有正确的异常处理。这有很多死锁问题。

答案 4 :(得分:3)

死锁的常见原因是当您有不同的线程(或进程)以不同的顺序获取一组资源时。

E.g。如果你有一些资源A和B,如果线程1获得A然后是B,并且线程2获得B然后获得A,则这是一个等待发生的死锁。

这个问题有一个简单的解决方案:让所有线程始终以相同的顺序获取资源。例如。如果你的所有线程按顺序获得A和B,你将避免死锁。

答案 5 :(得分:1)

死锁是指两个进程相互依赖的情况 - 一个无法在另一个进程之前完成。因此,如果您在任何时间运行多个代码流,则可能只会在代码中出现死锁。

开发多线程应用程序意味着您需要考虑死锁。单线程应用程序不太可能出现死锁 - 但并非不可能,显而易见的例子是您可能正在使用容易死锁的数据库。