Eines der häufigsten Probleme beim Schreiben von Multithread-Anwendungen sind Deadlocks.
Meine Fragen an die Community sind:
Was ist ein Deadlock?
Wie erkennt man sie?
Behandeln Sie sie?
Und schließlich, wie verhindern Sie, dass sie auftreten?
Eines der häufigsten Probleme beim Schreiben von Multithread-Anwendungen sind Deadlocks.
Meine Fragen an die Community sind:
Was ist ein Deadlock?
Wie erkennt man sie?
Behandeln Sie sie?
Und schließlich, wie verhindern Sie, dass sie auftreten?
Antworten:
Eine Sperre tritt auf, wenn mehrere Prozesse gleichzeitig versuchen, auf dieselbe Ressource zuzugreifen.
Ein Prozess verliert und muss warten, bis der andere abgeschlossen ist.
Ein Deadlock tritt auf, wenn der Wartevorgang noch an einer anderen Ressource festhält, die der erste benötigt, bevor er beendet werden kann.
Ein Beispiel:
Ressource A und Ressource B werden von Prozess X und Prozess Y verwendet
Der beste Weg, um Deadlocks zu vermeiden, besteht darin, zu vermeiden, dass Prozesse auf diese Weise gekreuzt werden. Reduzieren Sie die Notwendigkeit, alles so weit wie möglich zu sperren.
Vermeiden Sie in Datenbanken, viele Änderungen an verschiedenen Tabellen in einer einzigen Transaktion vorzunehmen, vermeiden Sie Trigger und wechseln Sie so weit wie möglich zu optimistischen / Dirty / Nolock-Lesevorgängen.
Lassen Sie mich ein reales (nicht wirklich reales) Beispiel für eine Deadlock-Situation aus den Kriminalfilmen erklären. Stellen Sie sich vor, ein Verbrecher hält eine Geisel und dagegen hält ein Polizist auch eine Geisel, die ein Freund des Verbrechers ist. In diesem Fall wird der Verbrecher die Geisel nicht gehen lassen, wenn der Polizist seinen Freund nicht gehen lässt. Auch der Polizist wird den Freund des Verbrechers nicht loslassen, es sei denn, der Verbrecher lässt die Geisel frei. Dies ist eine endlose, nicht vertrauenswürdige Situation, da beide Seiten auf dem ersten Schritt voneinander bestehen.
Wenn also zwei Threads zwei verschiedene Ressourcen benötigen und jeder von ihnen die Sperre der Ressource hat, die der andere benötigt, ist dies ein Deadlock.
Sie sind mit einem Mädchen zusammen und einen Tag nach einem Streit sind beide Seiten gebrochen und warten auf einen Anruf, bei dem es mir leid tut und ich Sie verpasst habe . In dieser Situation wollen beide Seiten miteinander kommunizieren , wenn und nur wenn einer von ihnen eine empfängt I-am-Entschuldigung Anruf von der anderen Seite . Da keiner von beiden die Kommunikation starten und in einem passiven Zustand warten wird, warten beide darauf, dass der andere die Kommunikation startet, was zu einer Deadlock-Situation führt.
Deadlocks treten nur auf, wenn Sie zwei oder mehr Sperren haben, die gleichzeitig erworben werden können und in unterschiedlicher Reihenfolge erfasst werden.
Möglichkeiten zur Vermeidung von Deadlocks sind:
Um Deadlock zu definieren, würde ich zuerst den Prozess definieren.
Prozess : Wie wir wissen, ist der Prozess nichts anderes als eine program
Ausführung.
Ressource : Um einen Programmprozess auszuführen, werden einige Ressourcen benötigt. Zu den Ressourcenkategorien gehören Speicher, Drucker, CPUs, geöffnete Dateien, Bandlaufwerke, CD-ROMs usw.
Deadlock : Deadlock ist eine Situation oder Bedingung, in der zwei oder mehr Prozesse einige Ressourcen halten und versuchen, weitere Ressourcen zu erwerben, und sie die Ressourcen erst freigeben können, wenn sie dort ausgeführt werden.
Deadlock-Zustand oder Situation
In dem obigen Diagramm gibt es zwei Prozesse P1 und p2 und es gibt zwei Ressourcen R1 und R2 .
Die Ressource R1 ist dem Prozess P1 und die Ressource R2 dem Prozess p2 zugeordnet . Um die Ausführung des Prozesses P1 abzuschließen , wird also die Ressource R2 benötigt fordert P1 R2 an , aber R2 ist bereits P2 zugeordnet .
Auf die gleiche Weise Prozess P2 , um seine Ausführung abzuschließen, R1 , aber R1 ist bereits P1 zugeordnet .
Beide Prozesse können ihre Ressource erst freigeben, wenn sie ihre Ausführung abgeschlossen haben. Beide warten also auf weitere Ressourcen und werden für immer warten. Dies ist also eine DEADLOCK- Bedingung.
Damit ein Deadlock auftreten kann, müssen vier Bedingungen erfüllt sein.
und alle diese Bedingungen sind im obigen Diagramm erfüllt.
Ein Deadlock tritt auf, wenn ein Thread auf etwas wartet, das niemals auftritt.
In der Regel tritt dies auf, wenn ein Thread auf einen Mutex oder ein Semaphor wartet, das bzw. das vom Vorbesitzer nie freigegeben wurde.
Es kommt auch häufig vor, wenn Sie eine Situation mit zwei Threads und zwei Sperren wie folgt haben:
Thread 1 Thread 2
Lock1->Lock(); Lock2->Lock();
WaitForLock2(); WaitForLock1(); <-- Oops!
Sie erkennen sie im Allgemeinen, weil Dinge, von denen Sie erwarten, dass sie niemals passieren, oder die Anwendung vollständig hängt.
Sie können sich diese wunderbaren Artikel unter Deadlock ansehen . Es ist in C #, aber die Idee ist für andere Plattformen immer noch dieselbe. Ich zitiere hier zum einfachen Lesen
Ein Deadlock tritt auf, wenn jeweils zwei Threads auf eine Ressource warten, die von der anderen gehalten wird, sodass keiner fortfahren kann. Dies lässt sich am einfachsten mit zwei Schlössern veranschaulichen:
object locker1 = new object();
object locker2 = new object();
new Thread (() => {
lock (locker1)
{
Thread.Sleep (1000);
lock (locker2); // Deadlock
}
}).Start();
lock (locker2)
{
Thread.Sleep (1000);
lock (locker1); // Deadlock
}
Deadlock ist ein häufiges Problem bei Multiprocessing- / Multiprogramming-Problemen im Betriebssystem. Angenommen, es gibt zwei Prozesse P1, P2 und zwei global gemeinsam nutzbare Ressourcen R1, R2, und im kritischen Abschnitt muss auf beide Ressourcen zugegriffen werden
Zu Beginn weist das Betriebssystem R1 dem Prozess P1 und R2 dem Prozess P2 zu. Da beide Prozesse gleichzeitig ausgeführt werden, können sie mit der Ausführung ihres Codes beginnen. Das PROBLEM tritt jedoch auf, wenn ein Prozess den kritischen Abschnitt erreicht. Der Prozess R1 wartet also darauf, dass der Prozess P2 R2 freigibt, und umgekehrt ... Also warten sie für immer (DEADLOCK-ZUSTAND).
Eine kleine ANALOGIE ...
Deine Mutter (OS),
du (P1),
dein Bruder (P2),
Apple (R1),
Messer (R2),
kritischer Abschnitt (Apfel mit Messer schneiden).Deine Mutter gibt dir am Anfang den Apfel und das Messer an deinen Bruder.
Beide sind glücklich und spielen (Ausführen ihrer Codes).
Jeder von euch möchte irgendwann den Apfel schneiden (kritischer Abschnitt).
Du willst deinem Bruder den Apfel nicht geben.
Dein Bruder will dir das Messer nicht geben.
Ihr beide werdet also lange, sehr lange warten :)
Ein Deadlock tritt auf, wenn zwei Threads Sperren erwerben, die verhindern, dass einer von beiden fortschreitet. Der beste Weg, sie zu vermeiden, ist eine sorgfältige Entwicklung. Viele eingebettete Systeme schützen vor ihnen, indem sie einen Watchdog-Timer verwenden (einen Timer, der das System zurücksetzt, wenn es für einen bestimmten Zeitraum hängt).
Ein Deadlock tritt auf, wenn es eine kreisförmige Kette von Threads oder Prozessen gibt, die jeweils eine gesperrte Ressource enthalten und versuchen, eine Ressource zu sperren, die vom nächsten Element in der Kette gehalten wird. Zum Beispiel zwei Threads, die jeweils Sperre A und Sperre B halten und beide versuchen, die andere Sperre zu erlangen.
Ein klassisches und sehr einfaches Programm zum Verständnis der Deadlock- Situation: -
public class Lazy {
private static boolean initialized = false;
static {
Thread t = new Thread(new Runnable() {
public void run() {
initialized = true;
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println(initialized);
}
}
Wenn der Hauptthread Lazy.main aufruft, prüft er, ob die Klasse Lazy initialisiert wurde, und beginnt mit der Initialisierung der Klasse. Der Hauptthread setzt jetzt initialisiert auf false, erstellt und startet einen Hintergrundthread, dessen Ausführungsmethode auf true initialisiert gesetzt wird, und wartet, bis der Hintergrundthread abgeschlossen ist.
Dieses Mal wird die Klasse derzeit von einem anderen Thread initialisiert. Unter diesen Umständen wartet der aktuelle Thread, bei dem es sich um den Hintergrundthread handelt, auf das Class-Objekt, bis die Initialisierung abgeschlossen ist. Leider wartet der Thread, der die Initialisierung durchführt, der Hauptthread, auf den Abschluss des Hintergrundthreads. Da die beiden Threads jetzt aufeinander warten, ist das Programm DEADLOCKED.
Ein Deadlock ist ein Zustand eines Systems, in dem kein einzelner Prozess / Thread eine Aktion ausführen kann. Wie von anderen erwähnt, ist ein Deadlock normalerweise das Ergebnis einer Situation, in der jeder Prozess / Thread eine Sperre für eine Ressource erwerben möchte, die bereits von einem anderen (oder sogar demselben) Prozess / Thread gesperrt ist.
Es gibt verschiedene Methoden, um sie zu finden und zu vermeiden. Man denkt sehr viel nach und / oder probiert viele Dinge aus. Der Umgang mit Parallelität ist jedoch notorisch schwierig und die meisten (wenn nicht alle) Menschen werden Probleme nicht vollständig vermeiden können.
Einige formellere Methoden können hilfreich sein, wenn Sie sich ernsthaft mit solchen Problemen befassen. Die praktischste Methode, die mir bekannt ist, ist die Verwendung des prozess-theoretischen Ansatzes. Hier modellieren Sie Ihr System in einer Prozesssprache (z. B. CCS, CSP, ACP, mCRL2, LOTOS) und verwenden die verfügbaren Tools, um (Modell-) nach Deadlocks (und möglicherweise auch einigen anderen Eigenschaften) zu suchen. Beispiele für zu verwendende Tools sind FDR, mCRL2, CADP und Uppaal. Einige mutige Seelen könnten sogar beweisen, dass ihre Systeme mit rein symbolischen Methoden festgefahren sind (Theorembeweis; Suche nach Owicki-Gries).
Diese formalen Methoden erfordern jedoch in der Regel einige Anstrengungen (z. B. Erlernen der Grundlagen der Prozesstheorie). Aber ich denke, das ist einfach eine Folge der Tatsache, dass diese Probleme schwierig sind.
Ein Deadlock ist eine Situation, in der weniger Ressourcen verfügbar sind, als von den verschiedenen Prozessen angefordert wird. Dies bedeutet, dass, wenn die Anzahl der verfügbaren Ressourcen geringer wird als vom Benutzer angefordert, der Prozess zu diesem Zeitpunkt in einen Wartezustand versetzt wird. Manchmal steigt das Warten mehr und es besteht keine Möglichkeit, das Problem des Ressourcenmangels zu überprüfen Diese Situation wird als Deadlock bezeichnet. Tatsächlich ist Deadlock ein großes Problem für uns und tritt nur unter Multitasking-Betriebssystemen auf. Deadlock kann unter Single-Tasking-Betriebssystemen nicht auftreten, da alle Ressourcen nur für die Aufgabe vorhanden sind, die gerade ausgeführt wird.
Oben sind einige Erklärungen nett. Hoffe das kann auch nützlich sein: https://ora-data.blogspot.in/2017/04/deadlock-in-oracle.html
In einer Datenbank möchte eine Sitzung (z. B. ora), dass eine Ressource von einer anderen Sitzung (z. B. Daten) gehalten wird, diese Sitzung (Daten) jedoch auch eine Ressource, die von der ersten Sitzung (ora) gehalten wird. Es können auch mehr als 2 Sitzungen beteiligt sein, aber die Idee wird dieselbe sein. Tatsächlich verhindern Deadlocks, dass einige Transaktionen weiterhin funktionieren. Beispiel: Angenommen, ORA-DATA hält Sperre A und fordert Sperre B an, und SKU hält Sperre B und fordert Sperre A an.
Vielen Dank,
Ein Deadlock tritt auf, wenn ein Thread darauf wartet, dass ein anderer Thread beendet wird und umgekehrt.
Wie vermeide ich?
- Vermeiden Sie verschachtelte Sperren.
- Vermeiden Sie unnötige Sperren.
- Verwenden Sie thread join ()
Wie erkennt man das?
Führen Sie diesen Befehl in cmd aus:
jcmd $PID Thread.print
Referenz : Geeksforgeeks
Deadlocks treten nicht nur bei Sperren auf, obwohl dies die häufigste Ursache ist. In C ++ können Sie einen Deadlock mit zwei Threads und ohne Sperren erstellen, indem Sie einfach jeden Thread-Aufruf join () für das std :: thread-Objekt für den anderen festlegen.
Die Verwendung der Sperrung zur Steuerung des Zugriffs auf gemeinsam genutzte Ressourcen ist anfällig für Deadlocks, und der Transaktionsplaner allein kann deren Auftreten nicht verhindern.
Beispielsweise verwenden relationale Datenbanksysteme verschiedene Sperren, um die ACID-Eigenschaften von Transaktionen zu gewährleisten .
Unabhängig davon, welches relationale Datenbanksystem Sie verwenden, werden beim Ändern (z. B. UPDATE
oder DELETE
) eines bestimmten Tabellendatensatzes immer Sperren erworben . Ohne das Sperren einer Zeile, die durch eine aktuell ausgeführte Transaktion geändert wurde, wäre Atomicity gefährdet .
Wie in diesem Artikel erläutert , tritt ein Deadlock auf, wenn zwei gleichzeitige Transaktionen nicht ausgeführt werden können, da jeder darauf wartet, dass der andere eine Sperre aufhebt, wie in der folgenden Abbildung dargestellt.
Da sich beide Transaktionen in der Sperrenerfassungsphase befinden, gibt keine der beiden eine Sperre frei, bevor die nächste erworben wird.
Wenn Sie einen Concurrency Control-Algorithmus verwenden, der auf Sperren basiert, besteht immer das Risiko, dass Sie in einer Deadlock-Situation ausgeführt werden. Deadlocks können in jeder Parallelitätsumgebung auftreten, nicht nur in einem Datenbanksystem.
Beispielsweise kann ein Multithreading-Programm einen Deadlock verursachen, wenn zwei oder mehr Threads auf zuvor erfasste Sperren warten, sodass kein Thread Fortschritte erzielen kann. Wenn dies in einer Java-Anwendung geschieht, kann die JVM einen Thread nicht einfach zwingen, seine Ausführung zu stoppen und seine Sperren aufzuheben.
Selbst wenn die Thread
Klasse eine stop
Methode verfügbar macht , ist diese Methode seit Java 1.1 veraltet, da sie dazu führen kann, dass Objekte nach dem Stoppen eines Threads in einem inkonsistenten Zustand belassen werden. Stattdessen definiert Java eineinterrupt
Methode, die als Hinweis fungiert, da ein unterbrochener Thread die Unterbrechung einfach ignorieren und ihre Ausführung fortsetzen kann.
Aus diesem Grund kann sich eine Java-Anwendung nicht von einer Deadlock-Situation erholen, und es liegt in der Verantwortung des Anwendungsentwicklers, die Anforderungen für die Sperrenerfassung so anzuordnen, dass niemals Deadlocks auftreten können.
Ein Datenbanksystem kann jedoch einen bestimmten Befehl zum Erwerb von Sperren nicht erzwingen, da nicht vorhersehbar ist, welche anderen Sperren eine bestimmte Transaktion weiter erwerben möchte. Das Beibehalten der Sperrreihenfolge liegt in der Verantwortung der Datenzugriffsschicht, und die Datenbank kann nur bei der Wiederherstellung nach einer Deadlock-Situation helfen.
Das Datenbankmodul führt einen separaten Prozess aus, der das aktuelle Konfliktdiagramm nach Wartezyklen durchsucht (die durch Deadlocks verursacht werden). Wenn ein Zyklus erkannt wird, wählt das Datenbankmodul eine Transaktion aus und bricht sie ab, wodurch die Sperren aufgehoben werden, sodass die andere Transaktion Fortschritte erzielen kann.
Im Gegensatz zur JVM ist eine Datenbanktransaktion als atomare Arbeitseinheit konzipiert. Daher verlässt ein Rollback die Datenbank in einem konsistenten Zustand.
Weitere Informationen zu diesem Thema finden Sie auch in diesem Artikel .
Mutex ist im Wesentlichen eine Sperre, die geschützten Zugriff auf gemeinsam genutzte Ressourcen bietet. Unter Linux lautet der Thread-Mutex-Datentyp pthread_mutex_t. Initialisieren Sie es vor dem Gebrauch.
Um auf freigegebene Ressourcen zugreifen zu können, müssen Sie den Mutex sperren. Befindet sich der Mutex bereits in der Sperre, blockiert der Aufruf den Thread, bis der Mutex entsperrt wird. Nach Abschluss des Besuchs freigegebener Ressourcen müssen Sie diese entsperren.
Insgesamt gibt es einige ungeschriebene Grundprinzipien:
Beziehen Sie die Sperre, bevor Sie die freigegebenen Ressourcen verwenden.
Halten Sie das Schloss so kurz wie möglich.
Lösen Sie die Sperre, wenn der Thread einen Fehler zurückgibt.