什么是僵局?


Answers:


206

当多个进程试图同时访问同一资源时。

一个过程失败了,必须等待另一个过程完成。

一个死锁时,等待的过程中仍保存到另一个资源,它所收到的第一需要,可以完成发生。

举个例子:

资源A和资源B由流程X和Y使用

  • X开始使用A。
  • X和Y尝试开始使用B
  • Y“获胜”并首先获得B
  • 现在Y需要使用A
  • A被X锁定,正在等待Y

避免死锁的最佳方法是避免进程以这种方式交叉。尽可能减少锁定任何东西的需要。

在数据库中,请避免在单个事务中对不同表进行大量更改,避免使用触发器,并尽可能切换到乐观/脏/无锁读取。


9
我在这里使用流程作为概括,而不是专门用于OS流程。这些可能是线程,但也可能是完全不同的应用程序或数据库连接。模式是相同的。
基思

1
嗨,在这种情况下:线程A锁定了资源A,并且进程很长。线程B等待锁定资源A。CPU时间使用率:20%,您可以考虑出现死锁情况吗?
rickyProgrammer17年

2
@rickyProgrammer不,这只是一个常规的锁定等待,尽管差异有点学术性。B等待慢A是锁,B等待A等待B是死锁。
基思(Keith)

所以僵局更多的是与锁定的资源等待这些资源两个进程被释放..
rickyProgrammer

2
@rickyProgrammer,由于循环队列,无论您等待多长时间,该锁都不会免费。
基思(Keith)

126

让我解释一下犯罪电影中出现僵局的真实示例(不是真实示例)。想象一下,犯罪分子将人质扣为人质,而警察也将人质作为犯罪分子的朋友。在这种情况下,如果警察不让他的朋友放手,罪犯就不会放开人质。另外,除非罪犯释放人质,否则警察不会放任罪犯的朋友。这是一种无休止的不信任局面,因为双方都坚持彼此采取第一步。

犯罪与警察现场

在此处输入图片说明

如此简单,当两个线程需要两个不同的资源,并且每个线程都拥有另一个需要的资源锁时,这就是一个死锁。

僵局的另一个高级解释:破碎的心

您正在与一个女孩约会,吵架后的第二天,双方都为彼此伤心欲绝,等待着我对不起和我想念您的电话。在这种情况下,当且仅当其中一方收到对方的I-am-sorry呼叫,双方才希望彼此通信。因为双方都不会开始通信并处于被动状态,所以双方都将等待对方开始通信,最终陷入僵局。


线程应该属于不同的进程吗?属于同一进程的线程也会导致死锁吗?
lordvcs

1
@diabolicfreak线程是否属于同一进程并不重要。
山姆·马来耶

2
现实生活中的另一个例子可能是四辆汽车同时在四个方向上穿越两条相等的道路。每个人都需要从右侧让车,所以没有人可以前进。
LoBo

35

只有当您同时拥有两个或两个以上的锁并且以不同的顺序抓住它们时,才会发生死锁。

避免出现死锁的方法是:

  • 避免有锁(如果可能),
  • 避免有多个锁
  • 始终以相同的顺序锁。

防止死锁(始终以相同顺序获取锁)的第三点至关重要,这在编码实践中很容易被遗忘。
徐强

20

要定义死锁,首先我要定义过程。

流程 众所周知,流程不过是一个program正在执行的流程。

资源 执行程序过程需要一些资源。资源类别可能包括内存,打印机,CPU,打开的文件,磁带驱动器,CD-ROM等。

死锁 当两个或多个进程持有一些资源并试图获取更多资源,并且只有在完成执行后才能释放资源,死锁是一种情况或状况。

死锁情况

在此处输入图片说明

在上图中,有两个过程P1p2,有两个资源R1R2

资源R1被分配给处理P1,资源R2被分配给处理p2。为了完成过程P1的执行,需要资源R2,因此P1请求R2,但是R2已分配给P2

以相同的方式,进程P2完成其执行需要R1,但R1已分配给P1

这两个进程只有在完成执行之前,才能释放资源。因此,两者都在等待其他资源,并且它们将永远等待。所以这是一个死锁条件。

为了使死锁发生,必须满足四个条件。

  1. 互斥 -每种资源当前要么正好分配给一个进程,要么可用。(两个进程不能同时控制相同的资源或位于其关键部分)。
  2. 保留和等待 -当前保留资源的进程可以请求新资源。
  3. 无抢占 -进程拥有资源后,其他进程或内核将无法抢占资源。
  4. 循环等待 -每个进程都在等待获取由另一个进程持有的资源。

以上条件均满足。


8

当线程正在等待永远不会发生的事情时,就会发生死锁。

通常,它发生在线程正在等待以前所有者从未释放过的互斥量或信号量时。

当您遇到涉及两个线程和两个锁的情况时,也经常发生这种情况:

Thread 1               Thread 2

Lock1->Lock();         Lock2->Lock();
WaitForLock2();        WaitForLock1();   <-- Oops!

通常,您检测到它们是因为您期望发生的事情永远不会发生,或者应用程序完全挂起。


当线程正在等待无法发生的事情时,就会发生死锁。
2014年

4

您可以在Deadlock下查看这些精彩的文章。它是用C#语言编写的,但对于其他平台来说,想法仍然相同。我在这里引用以方便阅读

当两个线程各自等待对方拥有的资源时,就会发生死锁,因此两个线程都无法继续进行。最简单的方法是使用两个锁:

object locker1 = new object();
object locker2 = new object();

new Thread (() => {
                    lock (locker1)
                    {
                      Thread.Sleep (1000);
                      lock (locker2);      // Deadlock
                    }
                  }).Start();
lock (locker2)
{
  Thread.Sleep (1000);
  lock (locker1);                          // Deadlock
}

4

死锁是OS中多处理/多编程问题中的常见问题。假设有两个进程P1,P2和两个全局共享资源R1,R2,并且在关键部分都需要访问这两个资源

最初,OS将R1分配给进程P1,将R2分配给进程P2。当两个进程同时运行时,它们可能会开始执行其代码,但是当一个进程到达关键部分时就会出现问题。因此,进程R1将等待进程P2释放R2,反之亦然...因此,它们将永远等待(DEADLOCK CONDITION)。

一个小类比...

您的母亲(OS),
您(P1),
您的兄弟(P2),
苹果(R1),
刀(R2),
关键部位(用刀切苹果)。

一开始,您的母亲就给您苹果和刀给您的兄弟。
双方都很开心,正在玩(执行他们的代码)。
大家都想在某个时候切苹果。
你不想把苹果给你的兄弟。
你兄弟不想把刀给你。
因此,你们两个都将等待很长一段时间:)


2

当两个线程获得锁定而阻止它们中的任何一个前进时,就会发生死锁。避免它们的最好方法是精心开发。许多嵌入式系统通过使用看门狗计时器(计时器在系统挂起一定时间后重置系统)来保护它们。


2

当有一个循环的线程或进程链,每个线程或进程都拥有一个锁定的资源,并试图锁定该链中下一个元素所拥有的资源时,就会发生死锁。例如,两个分别持有锁A和锁B的线程都试图获取另一个锁。


我投票赞成你。您的答案比上面更简洁,因为它们使混乱死锁通过进程或线程发生。有人说过程,有人说线程:)
hainguyen

1

一个经典且非常简单的程序,用于了解死锁情况:-

public class Lazy {

    private static boolean initialized = false;

    static {
        Thread t = new Thread(new Runnable() {
            public void run() {
                initialized = true;
            }
        });

        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println(initialized);
    }
}

当主线程调用Lazy.main时,它将检查Lazy类是否已初始化,并开始初始化该类。现在,主线程将初始化设置为false,创建并启动一个后台线程,其运行方法将初始化设置为true,并等待后台线程完成。

这次,该类当前正在由另一个线程初始化。在这种情况下,当前线程(即后台线程)在Class对象上等待,直到初始化完成。不幸的是,正在执行初始化的线程(主线程)正在等待后台线程完成。因为这两个线程现在正在互相等待,所以程序处于DEADLOCKED状态。


0

死锁是系统的一种状态,其中没有单个进程/线程能够执行操作。正如其他人所提到的,死锁通常是每个进程/线程希望获得对已由另一个(甚至相同)进程/线程锁定的资源的锁定的情况的结果。

有多种方法可以找到它们并避免它们。一个人非常努力地思考和/或尝试了许多事情。但是,处理并行性非常困难,并且大多数(如果不是全部)人将无法完全避免问题。

如果您认真对待此类问题,则可以使用一些更正式的方法。我知道的最实用的方法是使用过程理论方法。在这里,您可以使用某种过程语言(例如CCS,CSP,ACP,mCRL2,LOTOS)对系统进行建模,并使用可用的工具(模型)检查死锁(以及可能还有其他一些属性)。使用的工具集示例包括FDR,mCRL2,CADP和Uppaal。一些勇敢的灵魂甚至可以通过使用纯粹的象征性方法来证明他们的系统没有死锁(定理证明;寻找Owicki-Gries)。

但是,这些形式化方法通常确实需要付出一些努力(例如,学习过程理论的基础知识)。但是我想这仅仅是这些问题很难解决的结果。


0

当不同进程请求的可用资源数量较少时,就会发生死锁。这意味着,当可用资源的数量少于用户请求的数量时,该过程将进入等待状态。有时,等待数量会增加,因此没有机会检查资源不足的问题。这种情况称为死锁。实际上,死锁对我们来说是一个主要问题,死锁仅在多任务操作系统中发生。死锁在单任务操作系统中无法发生,因为所有资源仅存在于当前正在运行的任务中......


0

以上是一些很好的解释。希望这也可能有用:https : //ora-data.blogspot.in/2017/04/deadlock-in-oracle.html

在数据库中,当一个会话(例如ora)想要另一个会话(例如数据)持有的资源时,但该会话(数据)也想要一个第一会话(ora)持有的资源。也可以涉及两个以上的会议,但想法是相同的。实际上,死锁会阻止某些事务继续工作。例如:假设ORA-DATA持有锁A并请求锁B,而SKU持有锁B并请求锁A。

谢谢,


0

当一个线程正在等待其他线程完成时,就会发生死锁,反之亦然。

如何避免?
-避免嵌套锁
-避免不必要的锁
-使用线程join()

您如何检测到它?
在cmd中运行以下命令:

jcmd $PID Thread.print

参考:geeksforgeeks


0

尽管这是最常见的原因,但死锁不仅仅与锁一起发生。在C ++中,您可以通过让每个线程在std :: thread对象上调用另一个的join()来创建具有两个线程且没有锁的死锁。


0

基于锁的并发控制

使用锁定来控制对共享资源的访问容易产生死锁,并且仅事务调度程序无法防止其发生。

例如,关系数据库系统使用各种锁来保证事务ACID属性

无论您使用哪种关系数据库系统,在修改(例如UPDATEDELETE)某个表记录时都将始终获取锁。如果不锁定被当前正在运行的事务修改的行,原子性将受到损害

什么是僵局

正如我在本文中所解释的,当两个并发事务无法进行时会发生死锁,因为每个事务都在等待另一个释放锁,如下图所示。

在此处输入图片说明

因为两个事务都处于锁获取阶段,所以没有人在获取下一个之前释放锁。

从僵局中恢复

如果您使用的是依赖于锁的并发控制算法,则始终存在在死锁情况下运行的风险。死锁可能发生在任何并发环境中,而不仅仅是数据库系统中。

例如,如果两个或多个线程正在等待先前获取的锁,则多线程程序可能会死锁,从而使任何线程都无法取得任何进展。如果这在Java应用程序中发生,则JVM不能仅仅强制Thread停止其执行并释放其锁。

即使Thread该类公开了一个stop方法,该方法自Java 1.1以来也已被弃用,因为它可能导致对象在线程停止后处于不一致状态。相反,Java定义了一个interrupt方法,该方法充当提示,因为被中断的线程可以简单地忽略该中断并继续执行。

因此,Java应用程序无法从死锁情况中恢复,并且应用程序开发人员有责任以永远不会发生死锁的方式对锁获取请求进行排序。

但是,数据库系统无法强制执行给定的锁获取顺序,因为无法预见某个事务将要进一步获取哪些其他锁。保留锁定顺序成为数据访问层的责任,并且数据库只能帮助从死锁情况中恢复。

数据库引擎运行一个单独的进程,该进程扫描当前冲突图以查找锁定等待周期(由死锁引起)。当检测到周期时,数据库引擎将选择一个事务并中止该事务,从而释放其锁,以便其他事务可以取得进展。

与JVM不同,数据库事务被设计为基本的工作单元。因此,回滚使数据库保持一致状态。

有关此主题的更多详细信息,请同时阅读本文


-2

互斥锁本质上是一个锁,它提供对共享资源的受保护的访问。在Linux下,线程互斥锁数据类型为pthread_mutex_t。使用之前,请对其进行初始化。

要访问共享资源,您必须锁定互斥锁。如果互斥锁已处于锁定状态,则调用将阻塞线程,直到互斥锁解锁为止。访问共享资源完成后,您必须将其解锁。

总体而言,有一些未成文的基本原则:

  • 使用共享资源之前,请获取锁。

  • 尽可能短地握住锁。

  • 如果线程返回错误,则释放锁。


3
这描述了一个锁,而不是死锁。
罗恩侯爵,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.