银行情况的僵局问题

时间:2011-05-08 22:46:08

标签: c# multithreading

我有问题,我无法解决此问题

void Transfer(Account a, Account b, decimal amount) 
{
       lock (a) {
             lock (b) {
                         if (a.Balance < amount)
                         throw new InsufficientFundsExc();
                         a.Balance -= amount;
                         b.Balance += amount;
                         }
                   }
}
问题是“这是银行账户之间的转移。”锁定(...)“结构用于对抗竞争条件。这个问题是什么?你提出什么解决方案?你可以帮助我吗?

6 个答案:

答案 0 :(得分:10)

如果你在从B转移到A的同时从A转移到B,它可能会死锁,因为你没有锁定命令。

  • 线程1锁定A
  • 线程2锁定B
  • 线程1等待B
  • 线程2等待A

但为什么这个代码首先是多线程的呢?

您需要始终以相同的顺序获取锁。例如,通过为每个锁提供一个整数Id并始终首先锁定较低的ID。

答案 1 :(得分:4)

如果您可以订购帐户(按ID号或其他内容),您可以随时锁定具有较低ID的帐户。这将确保没有线程尝试锁定a然后b同时锁定a然后b的另一个线程,因为它们将锁定a第一

答案 2 :(得分:3)

死锁

转移时(a,b,10.0);和转移(b,a,10.0);被同时调用 第一个电话会锁定一个 然后第二个可以在第一个锁定之前锁定b 并且都不能继续 - &gt;死锁

答案 3 :(得分:0)

正如CodeInChaos所说,你的问题可能是一个僵局。如果你不明白什么是死锁,那么我建议你阅读dining philosophers problem on Wikipedia

本文以实际方式解释了这个问题,并提出了一些解决方案,包括使用locking order

编辑:
为了进一步将您的问题与文章联系起来,银行账户是分叉(即只能专门使用的共享资源,因此需要锁定),访问代码的线程是哲学家(即不时需要使用的实体)可锁定的资源)。

答案 4 :(得分:0)

@RatchetFreak打了他的回应,为什么会发生这种情况。我认为你遇到的一个主要问题是锁是一个非常低级的构造,这使得很难想到线程方案的合理性。

我建议(如果可能的话)使用一组略高级别的结构,让自己的生活更轻松。 Daniel Chamber's在his library中具有很好的轻量级实用程序。

答案 5 :(得分:0)

想象一下,两个非常顽固的女士和丈夫一起去度假屋。他们第二天早上醒来,发现男人们走了。唯一剩下的衣服:裙子和衬衫(似乎其中一个男人喜欢穿女式服装 - 可以解释很多)。女士们意识到需要去买东西 - 食物,衣服,新婚夫妇。他们都认为“好吧,我会把衣服穿上去”,一个穿上裙子而另一个穿上衬衫。他们看到发生了什么,但每个人都太顽固了,无法改变他们的计划(并且太害羞而不能半裸出去)。他们的顽固性类似于一个愚蠢的计算机,遵循一个“当时看起来很好”的程序。他们不能/不会自动修改他们在遇到“运行时错误”时看似明智的方法,因此他们注定要饿死。那是一个死锁:等待你无法获得的资源,因为有人在等你自己在做什么。

通过更多的远见和计划,他们可以找到一种策略来确保其中一人退出。例如:

  • 根据所寻找的物品订购:
    • e.g。只有当你已经穿上裙子时才可以穿上这件衬衫(至少有锁具,两个线程中的一个可以保证在没有撕裂的情况下获得它),或者
  • 基于潜在所有者的订单:
    • 如果两个人都想同时出门,那么谁的生日早些时候可以先行,或者如果相同那么谁更高等等,或者
  • 再次剥离并在短暂但随机的间隔后尝试