C# 银行僵局问题

C# 银行僵局问题,c#,multithreading,C#,Multithreading,我有个问题,我无法解决这个问题 void Transfer(Account a, Account b, decimal amount) { lock (a) { lock (b) { if (a.Balance < amount) throw new InsufficientFundsExc(); a

我有个问题,我无法解决这个问题

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;
                         }
                   }
}
无效转账(账户a、账户b、小数金额)
{
锁(a){
锁(b){
如果(a.余额<金额)
抛出新的不足的FundsExc();
a、 余额-=金额;
b、 余额+=金额;
}
}
}

问题是“这是银行账户之间的转账。“锁(…)”结构用于对抗竞争条件。这是什么问题?您建议什么解决方案?您能帮助我吗?

如果您在从a到B的转账的同时从B到a,它可能会死锁,因为您没有锁顺序

  • 线程1锁定一个线程
  • 螺纹2锁紧B
  • 线程1等待B
  • 线程2等待
  • 死的
但为什么这段代码首先是多线程的呢


您需要始终按照相同的顺序使用锁。例如,为每个锁指定一个整数Id,并始终首先锁定较低的Id。

如果您可以订购帐户(通过Id号或其他方式),您始终可以先锁定ID较低的线程。这将确保没有线程尝试在另一个线程锁定
a
然后
b
的同时锁定
a
然后
b
,因为它们都会先锁定
a

死锁

同时调用传输(a,b,10.0)和传输(b,a,10.0)时 第一次呼叫将锁定一个 然后第二个可以在第一个可以锁定a之前锁定b
而且两者都不能继续->死锁

正如CodeInChaos所建议的,您的问题是潜在的死锁。如果您不理解什么是死锁,那么我建议您阅读

这篇文章用实际的术语解释了这个问题,并提出了一些解决方案,包括使用

编辑:

为了进一步将您的问题与本文联系起来,银行账户是fork(即,共享资源只能被独占使用,因此需要被锁定),访问代码的线程是哲学家(即,不时需要使用可锁定资源的实体).

@RatchetFreak对为什么会发生这种情况的回答一针见血。我认为,您面临的主要问题是锁是一种非常低级的构造,这使得很难理智地考虑线程场景


我建议(如果可能的话)使用一套稍微高一点的结构让自己的生活更轻松。丹尼尔·钱伯斯有一套很好的轻量实用程序来实现这一点。

想象一下,两位非常固执的女士和丈夫一起去度假。第二天早上醒来,发现男人们不见了。只剩下一件衣服:一条裙子和一件衬衫(似乎其中一个男人喜欢穿女人的衣服——这可以解释很多)。女士们意识到需要去买东西——食物、衣服、新丈夫。她们都认为“好吧,我穿上衣服就走”,一个穿上裙子,另一个穿上衬衫。她们看到发生了什么,但都太固执了,不愿改变计划(而且他们太害羞了,不敢半裸出门)。他们的固执就像一台愚蠢的计算机在执行一个“当时看起来不错”的程序。他们不能/不会自动修改他们在遇到“运行时错误”时所采取的看似合理的方法,所以他们都注定要饿死。这是一个死锁:等待你无法得到的资源,因为有人在等待你正在吞噬自己的东西

如果有更多的远见和计划,他们本可以找到一个战略,确保其中一人脱身。例如:

  • 根据所要查找的对象排序:
    • e、 g.只有当你已经拿到裙子时,你才能拿衬衫(至少带锁,两条线中的一条线有争议,可以在不撕成两半的情况下拿到),或者
  • 基于潜在所有者的订单:
    • 如果双方都想同时出去,谁的生日早一点就可以先去,或者如果是同一天,谁的个子高一点,等等,或者
  • 这两种方法都会再次剥离,并在一个短暂但随机的间隔后重试

等等。

我的问题是,“这是家庭作业吗?”你考虑了什么?你在哪里遇到了问题?你能提供你试图解决问题的数据吗?我添加了家庭作业标记。@user744303:如果这不是家庭作业,请删除该标记。为什么你首先要多线程处理这个问题?根据我的经验,多线程处理昂贵的计算有时是有用的,但多线程处理整个问题域通常是一个坏主意。为什么这属于c#、java、c和vb?请您详细解释一下,并告诉我如何解决这个问题。请始终按相同的顺序使用锁。或者干脆将多线程放在一起。这看起来不像是一种首先需要多线程的情况。而且通常是d实践或至少容易出错(通常是设计薄弱的标志)在这个例子中,
Transfer
方法显示了这个问题,因为如果不锁定逻辑上不具有相同所有者的两个资源,就很难实现。如果是家庭作业,自己做。如果不是家庭作业,而是一个实实在在的问题,则抛出多线程。I我不会为你做作业。那么你应该学习很多关于多线程的知识,或者根本不使用它。多线程很难,很容易犯随机发生的错误,而且很少有必要。我建议在昂贵的计算中有选择地使用多线程。