2012-04-09 14 views
2

Dies ist ein falsches Bankdatenbankproblem mit Deadlock. Ich habe bereits, was ich denke, ist die Antwort, aber ich bin neugierig, ob dies eine gute Lösung ist. Die Frage stellt, ist die folgende: (oder Prozesse)Verhindern von Deadlock in einer Scheinbankdatenbank

Wie Sie Deadlock im folgenden Code verhindern ?:

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

Die Art und Weise dieses Deadlock ist über zwei Threads werden kann Aufruf der Transaktion() -Methode zur gleichen Zeit mit gegnerischen Konten, dh:

Transaktion (Einsparungen, Prüfung, 1); in Thread 1 und

Transaktion (Überprüfung, Einsparungen, 2); in Thread 2.

Von meinem schlechten Verständnis, denke ich, was passiert und warum es festgefahren ist, weil die Sperre Reihenfolge nicht befolgt wird, da beide Threads versuchen, eine Sperre (von einander?) zu bekommen.

Meine quick and dirty Lösung wäre, die Schleusen außerhalb der Funktion Transaktion zu bewegen(), wo es so aussehen würde, wenn sie aufgerufen:

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

    wait(lock1); 
     wait(lock2); 

     transaction(checking, savings, 2); 

     signal(lock2); 
    signal(lock1); 
    //..... 

mit der Transaktion wie folgt aussehen:

void transaction(Account from, Account to, double amount) 
{ 
    withdraw(from, amount); 
    deposit(to, amount); 
} 

So können sie nie gleichzeitig ausgeführt werden, da die Transaktion technisch der kritische Abschnitt ist. Wenn dies ein Java-Programm wäre, könnten Sie auch Monitore verwenden, indem Sie das Wort nach void in die Funktionsdeklaration einfügen? Funktioniert das? Das scheint ein klügerer Weg zu sein.

Ich mag das auch nicht verstehen, also fühlen Sie sich frei, mich zu schulen, besonders wenn meine Erklärungen nicht genau sind. Vielen Dank.

Antwort

5

denke ich, was los ist und warum es festgefahren zu werden, ist, weil die Sperre Ordnung, da beide Threads nicht befolgt versucht werden erhalten hier ein Schloss

Das Problem, wie Sie, dass ein Thread wie erwähnen ist:

wait(fromLock); 
    wait(toLock); 

, während ein anderer dies tun könnte:

wait(toLock); 
    wait(fromLock); 

was zu einem Deadlock führen kann.

Was Sie tun müssen, ist sicherzustellen, dass sie immer in der gleichen Reihenfolge sperren. Sie könnten irgendwie die ID des Kontos verwenden, um die Reihenfolge der Sperren herauszufinden:

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

Ich glaube, das wird alle Deadlocks auflösen. Sie können auch eine Überprüfung für die from und to die gleiche Entität sein.

+0

+1 Dies ist eine einfache und korrekte Lösung. – usr

+0

Ich würde zustimmen, dass es ist, ich weiß nur nicht, ob der Professor in Ordnung mit mir sein würde, die Konto IDs in diesem Kontext zu verwenden, um die Lösung zu bestimmen, da wir ihnen nicht gegeben wurden. In der realen Welt sehe ich jedoch nicht, warum das nicht perfekt funktionieren würde. – montag

+0

Offensichtlich können Sie ein anderes eindeutiges Feld verwenden, das auf dem "Account" @montag vergleichbar ist. Aber ich verstehe die Anforderungen der Frage. Das Verschieben der Sperren innerhalb der Transaktion ist eine andere Lösung. – Gray

2

Die Trennung dieses kritischen Abschnitts in zwei Abschnitte:

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

die beste Lösung in der realen Welt sein, weil diesen kritischen Abschnitt zu trennen, sie führt nicht zu einem unerwünschten Zustand zwischen (das heißt, es wird nie eine Situation geben, in der mehr Geld abgezogen wird, als es möglich ist).

Die einfache Lösung, um den kritischen Abschnitt in einem Stück zu lassen, ist sicherzustellen, dass die Sperranordnung in allen Transaktionen identisch ist. In diesem Fall können Sie die Sperren sortieren und die kleinere zum Sperren auswählen.

Weitere Informationen über Deadlock sehen meine Frage in diesen Situationen zu verhindern - Multiple mutex locking strategies and why libraries don't use address comparison

+0

Sie konnten also das synchronisierte Schlüsselwort in Java nicht verwenden, um sicherzustellen, dass die Transaktion niemals von zwei Threads gleichzeitig aufgerufen wird? – montag

+0

Wenn Sie synchronisiert mit "Account" -Objekten verwenden (und Sie diese Objekte vor dem Sperren auswählen, so dass sie in der Reihenfolge gesperrt werden) sollte es funktionieren, aber ich weiß nicht, Java gut genug, um Sie detailliertere Antwort zu geben. –

+0

Das ist wahr. Ich glaube, du hast Recht. Der einzige Grund, warum diese Lösung funktioniert, ist, dass niemand jemals gleichzeitig Geld einzahlen oder abheben müsste, daher könnten Sie nacheinander buchen. Ich denke ich verstehe. Danke für Ihre Hilfe. – montag

0

Keine Transaktion sollte jemals an einer Sperre festhalten, während sie auf eine andere wartet. Wenn es eine der benötigten Sperren nicht erhalten kann, sollte es alle diejenigen freigeben, die es erworben hat.

+0

Wie sollte die Anwendung dann strukturiert sein? Wie können wir vermeiden, zwei Schlösser zu nehmen? – usr