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

mon*_*tag 2 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);

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

       signal(lock2);
    signal(lock1);
 }
Run Code Online (Sandbox Code Playgroud)

这可以变为死锁的方式是通过两个线程(或进程?)同时使用对立账户调用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);
    //.....
Run Code Online (Sandbox Code Playgroud)

交易看起来像这样:

void transaction(Account from, Account to, double amount)
{
   withdraw(from, amount);
   deposit(to, amount);
}
Run Code Online (Sandbox Code Playgroud)

这样他们就永远无法同时执行,因为交易在技术上是关键部分.如果这是一个java程序,你是否也可以通过在函数声明中将void一词置为void来使用监听器?那会有用吗?这似乎是一种更聪明的方法.

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

Gra*_*ray 5

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

这里的问题就像你提到的那样一个线程:

wait(fromLock);
   wait(toLock);
Run Code Online (Sandbox Code Playgroud)

而另一个人可能会:

wait(toLock);
   wait(fromLock);
Run Code Online (Sandbox Code Playgroud)

这可能会导致死锁.

您需要做的是确保它们始终以相同的顺序锁定.您可以以某种方式使用帐户的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);
}
Run Code Online (Sandbox Code Playgroud)

我相信这将解决任何僵局.您可能还想检查from并且to是同一个实体.