精华内容
下载资源
问答
  • 多线程死锁原因是多个线程同时被阻塞,它们中的一个或全部都在等待某个资源被释放,而该资源又被其他线程锁定。 产生死锁的四个必要条件: 互斥 不可抢占 请求保持 循环等待 死锁原因: 资源不够 进程推进顺序...

    前言

    在找工作中,面试问到了这个,啥也不会,现在记录一下

    一 死锁原因

    多线程死锁的原因是多个线程同时被阻塞,它们中的一个或全部都在等待某个资源被释放,而该资源又被其他线程锁定。

    产生死锁的四个必要条件:

    • 互斥
    • 不可抢占
    • 请求保持
    • 循环等待

    死锁原因:

    • 资源不够
    • 进程推进顺序不合适

    避免死锁方法:

    • 加锁顺序
    • 加锁实现
    • 死锁检测

    二 用GDB调试死锁线程

    2.1 详细过程

    https://blog.csdn.net/atinybirdinit/article/details/41550149

    /*
      死锁调试
      1) -g参数
      2) attach
      3) info threads
      4) thread + number切换到对应的线程或thread apply all bt全部设置断点
    */
    

    在这里插入图片描述

    2.2 笔记记录

    <1> 查找进程id,即PID

    ps -e | grep a.out

    <2> 启动 gdb attach 进程

    gdb a.out 12826 // 12826是PID

    info threads //显示所有线程信息

    thread 2 // 选择进入第二个线程

    bt //查看线程2的堆栈,可以发现该线程堵塞在lock.c第17行

    展开全文
  • 主要介绍了Java 多线程死锁产生以及如何避免死锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 死锁产生原因 系统资源的竞争 进程推进顺序非法进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。 信号量使用不当也会造成死锁。 死锁产生的必要条件,产生死锁必须同时满足以下四个条件,只要...
    1. 死锁的定义

      多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。

    2. 死锁产生的原因

      1. 系统资源的竞争
      2. 进程推进顺序非法进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。
      3. 信号量使用不当也会造成死锁。
    3. 死锁产生的必要条件,产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生

      1. 互斥条件:进程要求对所分配的资源进行排他性控制,即在一段时间内一个资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
      2. 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放
      3. 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,对自己已获得的资源保持不放。
      4. 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。
    4. 如何避免死锁? 在有些情况下死锁是可以避免的。三种用于避免死锁的技术:

      1. 加锁顺序(线程按顺序加锁)
      2. 加锁时限(线程尝试获取锁的时候加上时间,超过时间则放弃对该锁的请求,并释放自己占有的锁)
      3. 死锁检测
    展开全文
  • 多线程死锁

    2017-06-13 15:46:07
    1、【多线程死锁是怎么产生的呢??】 2、【死锁产生的4个必要条件】 3、【死锁产生原因】 4、【产生死锁的几种场景】 5、【死锁避免的策略】


    1、【多线程死锁是怎么产生的呢??】

    多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。

    所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。

    简单的来说的话,

    就是线程1占着锁1,然后向系统提出请求,申请锁2;

    然而此时线程2占着锁2,并向系统提出申请,申请锁1;

    两个线程同时占着一个锁,并申请另一个锁,那么两个线程都会出现僵持状态,无法运行,产生死锁;

    下面我们通过一些实例来说明死锁现象。

    先看生活中的一个实例,2个人一起吃饭但是只有一双筷子,2人轮流吃(同时拥有2只筷子才能吃)。某一个时候,一个拿了左筷子,一人拿了右筷子,2个人都同时占用一个资源,等待另一个资源,这个时候甲在等待乙吃完并释放它占有的筷子,同理,乙也在等待甲吃完并释放它占有的筷子,这样就陷入了一个死循环,谁也无法继续吃饭。。。
    在计算机系统中也存在类似的情况。例如,某计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。


    2、【死锁产生的4个必要条件】

    产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。
    • 互斥条件:(资源独占)一个资源每次只能有一个进程或者线程来访问他;
    • 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
    • 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
    • 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有,


    3、【死锁产生的原因】

    1) 系统资源的竞争

    通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。

    2) 进程推进顺序非法

    进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞。

    信号量使用不当也会造成死锁。进程间彼此相互等待对方发来的消息,结果也会使得这 些进程间无法继续向前推进。例如,进程A等待进程B发的消息,进程B又在等待进程A 发的消息,可以看出进程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。




    4、【产生死锁的几种场景】

    死锁形成的常见情况有以下几种:
    1)忘记释放锁;
    2)单线程重复申请锁;
    3)多线程多锁申请;
    4)环形锁申请;


    5、【死锁避免的策略】

    在有些情况下死锁是可以避免的。三种用于避免死锁的技术:

    1. 加锁顺序(线程按照一定的顺序加锁)
    2. 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
    3. 死锁检测


    加锁顺序

    当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。

    如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。看下面这个例子:

    Thread 1:
      lock A 
      lock B
    
    Thread 2:
       wait for A
       lock C (when A locked)
    
    Thread 3:
       wait for A
       wait for B
       wait for C

    如果一个线程(比如线程3)需要一些锁,那么它必须按照确定的顺序获取锁。它只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。

    例如,线程2和线程3只有在获取了锁A之后才能尝试获取锁C(译者注:获取锁A是获取锁C的必要条件)。因为线程1已经拥有了锁A,所以线程2和3需要一直等到锁A被释放。然后在它们尝试对B或C加锁之前,必须成功地对A加了锁。

    按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁(译者注:并对这些锁做适当的排序),但总有些时候是无法预知的。


    加锁时限

    另外一个可以避免死锁的方法是在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行(译者注:加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。

    以下是一个例子,展示了两个线程以不同的顺序尝试获取相同的两个锁,在发生超时后回退并重试的场景:

    Thread 1 locks A
    Thread 2 locks B
    
    Thread 1 attempts to lock B but is blocked
    Thread 2 attempts to lock A but is blocked
    
    Thread 1's lock attempt on B times out
    Thread 1 backs up and releases A as well
    Thread 1 waits randomly (e.g. 257 millis) before retrying.
    
    Thread 2's lock attempt on A times out
    Thread 2 backs up and releases B as well
    Thread 2 waits randomly (e.g. 43 millis) before retrying.

    在上面的例子中,线程2比线程1早200毫秒进行重试加锁,因此它可以先成功地获取到两个锁。这时,线程1尝试获取锁A并且处于等待状态。当线程2结束时,线程1也可以顺利的获得这两个锁(除非线程2或者其它线程在线程1成功获得两个锁之前又获得其中的一些锁)。

    需要注意的是,由于存在锁的超时,所以我们不能认为这种场景就一定是出现了死锁。也可能是因为获得了锁的线程(导致其它线程超时)需要很长的时间去完成它的任务。

    此外,如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。如果只有两个线程,并且重试的超时时间设定为0到500毫秒之间,这种现象可能不会发生,但是如果是10个或20个线程情况就不同了。因为这些线程等待相等的重试时间的概率就高的多(或者非常接近以至于会出现问题)。
    (译者注:超时和重试机制是为了避免在同一时间出现的竞争,但是当线程很多时,其中两个或多个线程的超时时间一样或者接近的可能性就会很大,因此就算出现竞争而导致超时后,由于超时时间一样,它们又会同时开始重试,导致新一轮的竞争,带来了新的问题。)

    这种机制存在一个问题,在Java中不能对synchronized同步块设置超时时间。你需要创建一个自定义锁,或使用Java5中java.util.concurrent包下的工具。写一个自定义锁类不复杂,但超出了本文的内容。后续的Java并发系列会涵盖自定义锁的内容。


    死锁检测

    死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。

    每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。

    当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1)。

    当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多。线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A。线程A为了检测死锁,它需要递进地检测所有被B请求的锁。从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着。这是它就知道发生了死锁。

    下面是一幅关于四个线程(A,B,C和D)之间锁占有和请求的关系图。像这样的数据结构就可以被用来检测死锁。

    那么当检测出死锁时,这些线程该做些什么呢?

    一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(编者注:原因同超时类似,不能从根本上减轻竞争)。

    一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。









    展开全文
  • 死锁产生原因 系统资源的竞争 通常系统中拥有的不可剥夺资源,其数量不足以满足线程运行的需要,使得线程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能...

    多线程以改善了系统资源的利用率并且提高了系统的处理能力。但是,并发执行同时也带来了新的问题——死锁。所谓的死锁就是多个线程因竞争资源而造成的一种互相等待,如果没有外力作用,这些线程都将无法继续执行

    死锁产生的原因

    系统资源的竞争

    通常系统中拥有的不可剥夺资源,其数量不足以满足多个线程运行的需要,使得线程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。

    线程推进顺序非法

    线程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发线程 P1、P2分别保持了资源R1、R2,而线程P1申请资源R2,线程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞。

    信号量使用不当也会造成死锁。线程间彼此相互等待对方发来的消息,结果也会使得这 些线程间无法继续向前推进。例如,线程A等待线程B发的消息,线程B又在等待线程A 发的消息,可以看出线程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。

    死锁产生的必要条件

    产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。

    1. 互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待
    2. 不剥夺条件:线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能 由获得该资源的线程自己来释放(只能是主动释放)
    3. 请求和保持条件:线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他线程占有,此时请求线程被阻塞,但对自己已获得的资源保持不放
    4. 循环等待条件:存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被 链中下一个线程所请求。即存在一个处于等待状态的线程集合{Pl, P2, …, pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, …, n-1),Pn等待的资源被P0占有

    如何避免

    在有些情况下死锁是可以避免的。三种用于避免死锁的技术:

    1. 加锁顺序
    2. 加锁时限
    3. 死锁检测

    加锁顺序

    当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就容易发生。

    按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要事先知道所有可能会用到的锁,但总有些时候是无法预知的。

    加锁时限

    当一个线程在尝试获取锁的过程中超过了这个时限则该线程应该放弃对该锁进行请求。

    若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行。

    需要注意的是,由于存在锁的超时,所以我们不能认为这种场景就一定是出现了死锁。也可能是因为获得了锁的线程(导致其它线程超时)需要很长的时间去完成它的任务。

    此外,如果有非常多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致这些线程重复地尝试但却始终得不到锁。如果只有两个线程,并且重试的超时时间设定为0到500毫秒之间,这种现象可能不会发生,但是如果是10个或20个线程情况就不同了。因为这些线程等待相等的重试时间的概率就高的多(或者非常接近以至于会出现问题)。

    死锁检测

    死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。

    每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。

    当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。

    那么当检测出死锁时,这些线程该做些什么呢?

    一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(编者注:原因同超时类似,不能从根本上减轻竞争)。

    一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。

    展开全文
  • 一句话总结:资源竞争造成的无限等待,可通过加锁时效、死锁检测来避免 资源竞争造成的无限等待: 1、互斥条件:该进程拥有的资源,其他进程只能等待其释放 2、不剥夺条件:该进程拥有的资源只能由其自己释放 ...
  • 多线程死锁问题

    2017-06-09 09:54:08
    多线程死锁问题
  • 产生死锁原因 竞争资源。当系统中供个进程共享的资源如打印机、公用队列等,其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。 进程间推进顺序非法。进程在运行过程中,请求和释放资源的...
  • 下面小编就为大家带来一篇多线程死锁产生以及如何避免死锁方法(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 多线程编程:线程死锁原因以及解决方法 关于线程死锁这个问题相信程序员在编写多线程程序时会经常遇到的一个经典问题,这种情况往往出现在多个线程同时对临界资源访问时所产生的。 属于临界资源的硬件有打印机、...
  • 多线程死锁产生以及如何避免死锁

    万次阅读 多人点赞 2016-07-13 11:07:45
    多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前...
  • Java多线程死锁问题

    千次阅读 多人点赞 2021-05-11 08:57:52
    多线程编程中,因为抢占资源造成了线程无限等待的情况,此情况称为死锁死锁举例 注意:线程和锁的关系是:一个线程可以拥有多把锁,一个锁只能被一个线程拥有。 当两个线程分别拥有一把各自的锁之后,又尝试去...
  • 一、导致线程死锁原因 个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放,而该资源又被其他线程锁定,从而导致每一个线程都得等其它线程释放其锁定的资源,造成了所有线程都无法正常结束。这是从...
  • 多线程死锁原因和避免方法

    千次阅读 2019-04-23 17:40:00
    在申请锁时发生了交叉闭环,即线程在获得了锁A并且没有释放的情况下去申请锁B,这时,另一个线程已经获得了锁B,在释放锁B之前又要先获得锁A,因此闭环发生,陷入死锁循环。 引用:...
  • 多线程,多进程的存在改善了系统资源的利用率,并提高了系统的处理能力,并发执行也带来了新的问题。—>死锁 一、死锁定义1、生活中的列子两人吃饭,但只有一双筷子, 2人轮流吃(同时拥有2只筷子才能吃), 某个...
  • 本篇学习什么是多线程死锁,怎么避免线程死锁。这个问题,在面试了应该也经常被提到。关于,线程死锁,有这么一个故事。一个饭桌上,有丰盛的菜肴,圆桌围着几个哲学家,问题来了,每个哲学家只有一根筷子。假如必须...
  • 多线程死锁产生和解决

    千次阅读 2017-05-15 22:56:41
    什么是死锁线程死锁一般是发生个线程的个锁之间,比如线程A拥有临界区对象LockA的所有权,等待临界区对象LockB;线程B拥有临界区对象LockB的所有权,等待临界区对象LockA;由于两个线程间相互等待各自的锁,...
  • 多线程死锁相关问题

    2018-04-21 05:49:16
    然而回答的并不是很好,之前一直觉着线程死锁是比较简单的问题,但在面试中却恍然失措,不知道怎样用专业术语去表达且描述的也不够完善,因此借这篇博文我也顺便复习一些操作系统基础知识及Java多线程死锁相关问题。...
  • 多线程 死锁

    2019-03-19 15:30:55
    当业务比较复杂,多线程应用里有可能会发生死锁 演示死锁 1. 线程1 首先占有对象1,接着试图占有对象2 2. 线程2 首先占有对象2,接着试图占有对象1 3. 线程1 等待线程2释放对象2 4. 与此同时,线程2等待线程1...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 136,949
精华内容 54,779
关键字:

多线程死锁产生的原因