Database 防止模拟银行数据库中的死锁

Database 防止模拟银行数据库中的死锁,database,multithreading,deadlock,semaphore,Database,Multithreading,Deadlock,Semaphore,这是一个涉及死锁的模拟银行数据库问题。我已经有了我认为是答案,但我很好奇这是否是一个好的解决方案。提出的问题如下: 如何在以下代码中防止死锁 void transaction(Account from, Account to, double amount) { Semaphore lock1, lock2; lock1 = getLock(from); lock2 = getLock(to); wait(lock1); wait(lock2);

这是一个涉及死锁的模拟银行数据库问题。我已经有了我认为是答案,但我很好奇这是否是一个好的解决方案。提出的问题如下:

如何在以下代码中防止死锁

void transaction(Account from, Account to, double amount)
{
    Semaphore lock1, lock2;
    lock1 = getLock(from);
    lock2 = getLock(to);

    wait(lock1);
       wait(lock2);

          withdraw(from, amount);
          deposit(to, amount);

       signal(lock2);
    signal(lock1);
 }
这种死锁的方式是通过两个线程(或进程?)同时调用对方帐户的transaction()方法,即:

交易(储蓄、支票、1);在线程1和

交易(支票、储蓄、2);在线程2中

从我的理解来看,我认为发生了什么以及为什么它会陷入僵局是因为没有遵守锁顺序,因为两个线程都试图(从彼此那里)获取锁

我的快速而肮脏的解决方案是将锁移到函数transaction()之外的位置,在调用时它看起来像这样:

 //somewhere in main
    Semaphore lock1, lock2;
    lock1 = getLock(from);
    lock2 = getLock(to);

    wait(lock1);
       wait(lock2);

       transaction(checking, savings, 2);

       signal(lock2);
    signal(lock1);
    //.....
事务处理如下所示:

void transaction(Account from, Account to, double amount)
{
   withdraw(from, amount);
   deposit(to, amount);
}
这样,它们就永远不能同时执行,因为事务在技术上是关键部分。如果这是一个java程序,您是否也可以通过在函数声明中的void之后添加synchronized一词来使用监视器?这样行吗?这似乎是一个更聪明的方法


我也可能根本不理解这一点,所以请随意教我,特别是如果我的解释不准确的话。谢谢。

将此关键部分分为两部分:

void transaction(Account from, Account to, double amount)
{
    Semaphore lock1, lock2;
    lock1 = getLock(from);
    lock2 = getLock(to);

    wait(lock1);
          withdraw(from, amount);
    signal(lock1);


    wait(lock2);      
          deposit(to, amount);
    signal(lock2);
}
将是现实世界中最好的解决方案,因为分离这一关键部分不会导致它们之间出现任何不必要的状态(也就是说,永远不会出现提款超过可能的情况)

保持关键部分完整的简单解决方案是确保所有事务中的锁顺序相同。 在这种情况下,您可以对锁进行排序,然后选择较小的一个先锁定

有关在这些情况下防止死锁的更多详细信息,请参阅我的问题-

我认为发生了什么以及为什么它会陷入僵局是因为没有遵守锁的顺序,因为两个线程都试图获得锁

这里的问题是,正如您所提到的,像这样的一个线程:

wait(fromLock);
   wait(toLock);
而另一个可能会:

wait(toLock);
   wait(fromLock);
这可能会导致死锁

你需要做的是确保它们总是以相同的顺序锁定。您可以以某种方式使用帐户id来确定锁的顺序:

if (from.id < to.id) {
   wait(fromLock)
     wait(toLock)
       transaction(checking, savings, 2);
     signal(toLock);
   signal(fromLock);
} else {
   wait(toLock)
     wait(FromLock)
       transaction(checking, savings, 2);
     signal(FromLock);
   signal(toLock);
}
if(from.id

我相信这将解决任何僵局。您可能还希望检查从
到的
是否为同一实体。

任何事务在等待另一个锁时都不应持有一个锁。如果无法获得所需的一个锁,则应释放所有已获得的锁。

因此,不能在Java中使用synchronized关键字来确保两个线程不会同时调用事务?如果使用synchronized with
Account
objects(在锁定之前,您将选择这些对象,以便按顺序锁定它们)它应该可以工作,但我对Java的了解还不够好,无法给你提供更详细的答案。这是真的。我相信你是对的。因此,基本上这个解决方案工作的唯一原因是,没有人需要在同一时间存款或取款,因此你可以一个接一个地存款。我想我明白了。谢谢你的帮助。这令人惊讶。这不会导致系统中的总金额减少吗?暂时是的。但是没有交错,这会导致总金额永久性减少(比如没有锁)。那么,应用程序应该如何构造?我们如何避免使用两个锁?我同意,我只是不知道教授是否同意我在这种情况下使用帐户ID来确定解决方案,因为我们没有得到它们。但是,在现实世界中,我不明白为什么这不能完美工作。显然,你可以使用在
帐户
@montag上可比较的其他唯一字段。但我理解问题的要求。将锁移到事务中是另一种解决方案。