2012-04-09 6 views
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); 
} 

これがデッドロックになることができる方法は、二つのスレッド経由でトランザクションを呼び出し()メソッド(またはプロセス?)対価口座と同時に、すなわち:

トランザクション(節約、チェック、1);スレッド1および

トランザクション(確認、節約、2);

私の理解が乏しいことから、何が起こっているのか、なぜデッドロックが発生しているのかは、両方のスレッドがロックを取得しようとしているためロック順序が守られていないためです。

私の迅速かつ汚いソリューションは、(機能トランザクションの外側でロックを移動させることであろう)と呼ばれるとき、それは次のようになりどこへ:

//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という単語を入れてモニターを使うこともできますか?それは働くだろうか?それはそれを行うよりスマートな方法のようです。

また、私はこのことについて全く理解していないかもしれないので、私の説明が正確でない場合は、特に学校を教えてください。ありがとう。二つのセクションに、このクリティカルセクションの分離

答えて

5

を私は何が起こっているかと思うと、なぜそれがデッドロック取得され、両方のスレッドがしようとしているので、ロックの順序が守られていないためでありますあなたのような一つのスレッドが行うことは言うように、ロックに

を取得するには、ここでの問題は次のとおりです。

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

デッドロックが解決されると思います。 fromtoが同じエンティティであることを確認することもできます。

+0

+1これは簡単で正確な解決方法です。 – usr

+0

私はそれが与えられていないので、解決策を決定するためにそのコンテキストでアカウントIDを使用して教授が私と大丈夫だろうかどうか私はそれには同意するでしょう。現実の世界では、なぜこれが完全にはうまくいかないのか分かりません。 – montag

+0

明らかに、 'Account' @montagで比較できる他の独自のフィールドを使うことができます。しかし、私は質問の要件を理解しています。トランザクション内でロックを移動することも別の解決策です。 – Gray

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つにまとめるという簡単な解決策は、のロック順序がすべて同じであることを確認することです。 この場合、ロックを並べ替えることができ、最初にロックするために小さなものを選択できます。このような状況に防止デッドロックの詳細については

は私の質問を参照 - Multiple mutex locking strategies and why libraries don't use address comparison

+0

Javaでsynchronizedキーワードを使用して、同時に2つのスレッドによってトランザクションが決して呼び出されないようにすることはできませんでしたか? – montag

+0

'Account'オブジェクトとsynchronizedを使用する場合(ロックする前にこれらのオブジェクトを選択して順番にロックされるようにしてください)、動作するはずですが、より詳細な解答を得るのに十分なJavaは分かりません。 –

+0

これは本当です。私はあなたが正しいと信じています。だから、基本的には、このソリューションが機能する唯一の理由は、誰も同時に資金を預け入れる必要がないからです。分かったと思います。ご協力ありがとうございました。 – montag

0

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

+0

アプリケーションはどのように構造化されるべきですか?ロックを2つ取ることを避けるにはどうすればいいですか? – usr

関連する問題