Multithreading 为什么会出现死锁?Can';你不能在过程中释放锁吗?

Multithreading 为什么会出现死锁?Can';你不能在过程中释放锁吗?,multithreading,deadlock,Multithreading,Deadlock,假设一个人试图从银行账户A向银行账户B转账20美元,另一个人同时试图从银行账户B向银行账户A转账30美元。为什么这会导致僵局?每个线程不能执行以下操作: 线程1 获得某人的锁 从支票中提取20美元 解除某人的锁 获得B的锁 B加20美元 松开B的锁 线程2 获得B的锁 从银行提取30美元 松开B的锁 获得某人的锁 在一张支票上加30美元 解除某人的锁 我知道如果在每个线程的末尾释放资源,这将导致死锁。但是,为什么线程不能在处理完资源后立即释放资源的锁呢?死锁发生在两个资源等待对方释放资源时。当你

假设一个人试图从银行账户A向银行账户B转账20美元,另一个人同时试图从银行账户B向银行账户A转账30美元。为什么这会导致僵局?每个线程不能执行以下操作:

线程1 获得某人的锁 从支票中提取20美元 解除某人的锁 获得B的锁 B加20美元 松开B的锁

线程2 获得B的锁 从银行提取30美元 松开B的锁 获得某人的锁 在一张支票上加30美元 解除某人的锁


我知道如果在每个线程的末尾释放资源,这将导致死锁。但是,为什么线程不能在处理完资源后立即释放资源的锁呢?

死锁发生在两个资源等待对方释放资源时。当你穿过一条狭窄的街道时,只有一个人能立刻通过,突然你和另一个人从相反的方向相遇。现在,你们都将等待对方释放资源(即street),直到那时你们都将处于死锁状态

这里是第一个人必须将资金从帐户A转移到B,他必须获得两个帐户才能执行从A点到B点的交易,帐户持有人1正在等待帐户B被释放,但是,帐户持有人2正在等待帐户A被释放,如果你能想象的话,这会形成一个无限循环等待条件(或死锁)

现在考虑上面所提出的,线程1不能释放A的锁,除非事务完成。如果这一切都像你说的那样发生了呢!如果在获得20$后,线程A的锁被释放并扣除20$,并且帐户B的事务由于任何异常而失败,那么现在必须回滚事务,假设帐户A被其他线程占用!您可以看到这可能会导致无限期等待和进一步的数据不一致异常。假设用户向B发送20美元,然后立即停用他的帐户,如果交易失败,这笔钱将流向何处

给定场景的可能解决方案(死锁发生后):

  • 无互斥(意味着没有锁定,什么都没有!好吧,你更清楚,如果你把你的资源(比如肉)留给饥饿的狗(线程),会发生什么。你的系统最终会变成狗(只是开玩笑,很简单:这不可能不遵循互斥原则)

  • 允许优先购买 •操作系统可以从当前所有者处撤销资源

  • 无等待等待 •等待资源时,当前不得持有任何资源

  • 按顺序请求资源 •在等待资源“x”时,当前不得持有任何资源“y”•如您所见:如果您的程序满足#3,则满足#4


  • 这是我的看法

    以下是1线程转账的步骤:

  • 获取锁A
  • 从银行提取20美元
  • 获取锁B
  • B加20美元
  • 松开锁B
  • 松开锁A
  • 所以,为什么它不在从A中提取20美元后释放锁A呢?转账必须是一项交易。这意味着只有在完成上述6个步骤后才标记为成功。如果出现问题,它必须回滚所有内容

    让我们想象一下,在第4步,
    将$20添加到B
    ,由于某种原因,它失败了。这使得线程回滚,
    将$20添加回A
    。此时,如果
    锁A
    被其他线程占用,将导致无限期等待和一些进一步的问题

    这就是为什么它必须保持锁A直到事务完成

    假设一个人试图将20美元从银行账户A转到银行账户B,另一个人同时试图将30美元从银行账户B转到银行账户A,为什么会导致僵局

    不会的。真正的银行业不是这样运作的

    你大概是在通过某种类比或简化版本来论证这个概念

    线程1获取A的锁从A的锁中提取$20释放A的锁获取B的锁向B添加$20释放B的锁

    这样的事情很可能在真实的代码中完成

    需要注意的是,如果出于某种原因,我们无法获得锁B,我们需要再次获得锁A以返还20美元,因为如果我们无法在失败的情况下返还20美元,那么我们就不会有一个交易会完全成功或完全失败,而20美元可能会消失。因此,如果这之后有可能的话无法获得锁B我们可能无法再次获得锁A,这是不可接受的。如果某些东西可能在A和B上获得锁,然后根据它们保护的值做出决定,这也是不可接受的;它们的总和在这一点上是不正确的

    另一种可能的方法是订购锁。如果A总是在B之前,那么无论以何种方式转移资金,两个线程都将始终尝试在B之前获取锁A,并且死锁永远不会发生。一个重要的警告是,如果您拥有锁B,并且意识到您也需要锁A,则必须在获取之前释放锁B锁A

    另一种可能的方法是,在死锁状态下,一个事务会丢失,其工作会撤消,其锁可能会在重试之前释放,或者可能会在出现异常时释放(或者在出现异常之前重试一定次数)。这在数据库锁定中很常见。但请注意,这需要一些控制代码知道所做的工作,以便可以撤消。这适用于事务数据库,但不适用于大多数多线程程序