2

これは、デッドロックを伴う模擬銀行データベースの問題です。私はすでに答えだと思うものを持っていますが、これが良い解決策であるかどうか興味があります。提起された質問は次のとおりです。

次のコードでデッドロックを防ぐにはどうすればよいですか?:

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);
 }

これがデッドロックになる可能性がある方法は、2つのスレッド(またはプロセス?)を介して、反対のアカウントで同時に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の後にsyncedという単語を入れてモニターを使用することもできますか?それはうまくいくでしょうか?それはそれを行うためのより賢い方法のようです。

私もこれをまったく理解していないかもしれないので、特に私の説明が正確でない場合は、遠慮なく私を学校に通してください。ありがとう。

4

3 に答える 3

5

何が起こっているのか、なぜデッドロックになっているのかは、両方のスレッドがロックを取得しようとしているため、ロックの順序が守られていないためだと思います

ここでの問題は、次のような 1 つのスレッドがあることを述べているとおりです。

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);
}

私はそれがデッドロックを解決すると信じています。fromまた、とtoが同じエンティティであることを確認することもできます。

于 2012-04-09T16:23:58.223 に答える
2

この重要なセクションを 2 つのセクションに分けます。

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);
}

この重要なセクションを分離しても、それらの間で望ましくない状態が発生しないため、現実の世界では最良のソリューションになります (つまり、可能な以上のお金が引き出される状況は決してありません)。

クリティカル セクションを 1 つの部分に残す簡単な解決策は、ロックの順序がすべてのトランザクションで同じであることを確認することです。この場合、ロックを並べ替えて、最初にロックする小さい方を選択できます。

これらの状況でのデッドロック防止の詳細については、私の質問を参照してください -複数のミューテックス ロック戦略と、ライブラリがアドレス比較を使用しない理由

于 2012-04-09T16:21:01.363 に答える
0

別のロックを待機している間、トランザクションが 1 つのロックを保持することはありません。必要なロックの 1 つを取得できない場合は、取得したすべてのロックを解放する必要があります。

于 2012-04-09T16:42:55.390 に答える