Ich verstehe, was Livelock ist, aber ich habe mich gefragt, ob jemand ein gutes codebasiertes Beispiel dafür hat. Und mit codebasiert meine ich nicht "zwei Personen, die versuchen, in einem Korridor aneinander vorbeizukommen". Wenn ich das noch einmal lese, verliere ich mein Mittagessen.
concurrency
livelock
Alex Miller
quelle
quelle
Antworten:
Hier ist ein sehr einfaches Java-Beispiel für Livelock, bei dem ein Mann und eine Frau versuchen, Suppe zu essen, aber nur einen Löffel zwischen sich haben. Jeder Ehepartner ist zu höflich und gibt den Löffel weiter, wenn der andere noch nichts gegessen hat.
quelle
getOwner
Methode nicht auch synchronisiert werden? Von effektivem Java "hat die Synchronisation keine Auswirkung, es sei denn, sowohl Lesen als auch Schreiben ".Thread.join()
lieber verwenden alsThread.sleep()
, weil er darauf warten möchte, dass der Ehepartner sein Essen macht?getOwner
Methode muss synchronisiert werden, da selbst wenn die Methode synchronisiertsetOwner
ist, dies nicht garantiert, dass der Thread, dergetOwner
das Feld verwendet (oderowner
direkt auf das Feld zugreift ), die vom anderen Thread vorgenommenen Änderungen siehtsetOwner
. Dieses Video erklärt dies sehr sorgfältig: youtube.com/watch?v=WTVooKLLVT8synchronized
Schlüsselwort für diesetOwner
Methode verwenden, da Lesen und Schreiben eine atomare Aktion für die Referenzvariable ist.Abgesehen von flippigen Kommentaren ist ein bekanntes Beispiel der Code, der versucht, Deadlock-Situationen zu erkennen und zu behandeln. Wenn zwei Threads einen Deadlock erkennen und versuchen, sich gegenseitig "beiseite zu treten", bleiben sie ohne Sorgfalt in einer Schleife stecken, die immer "beiseite tritt" und es nie schafft, sich vorwärts zu bewegen.
Mit "beiseite treten" meine ich, dass sie das Schloss aufheben und versuchen würden, den anderen es erwerben zu lassen. Wir könnten uns die Situation mit zwei Threads vorstellen, die dies tun (Pseudocode):
Abgesehen von den Rennbedingungen haben wir hier eine Situation, in der beide Threads, wenn sie gleichzeitig eintreten, in der inneren Schleife laufen, ohne fortzufahren. Dies ist offensichtlich ein vereinfachtes Beispiel. Eine naiive Lösung wäre, eine gewisse Zufälligkeit in die Wartezeit der Threads zu setzen.
Die richtige Lösung besteht darin, immer die Sperrenerbschaft zu respektieren . Wählen Sie eine Reihenfolge, in der Sie die Schlösser erwerben, und halten Sie sich daran. Wenn beispielsweise beide Threads immer lock1 vor lock2 erhalten, besteht keine Möglichkeit eines Deadlocks.
quelle
Da keine Antwort als akzeptierte Antwort markiert ist, habe ich versucht, ein Beispiel für eine Live-Sperre zu erstellen.
Das ursprüngliche Programm wurde von mir im April 2012 geschrieben, um verschiedene Konzepte des Multithreading zu erlernen. Dieses Mal habe ich es geändert, um Deadlock, Race Condition, Livelock usw. zu erstellen.
Lassen Sie uns zuerst die Problemstellung verstehen.
Cookie Maker Problem
Es gibt einige Zutatenbehälter : ChocoPowederContainer , WheatPowderContainer . CookieMaker entnimmt etwas Pulver aus Zutatenbehältern , um ein Cookie zu backen . Wenn ein Cookie-Hersteller feststellt, dass ein Container leer ist, sucht er nach einem anderen Container, um Zeit zu sparen. Und wartet, bis Filler den gewünschten Behälter füllt. Es gibt einen Füllstoff, der den Behälter in regelmäßigen Abständen überprüft und eine bestimmte Menge füllt, wenn ein Behälter dies benötigt.
Bitte überprüfen Sie den vollständigen Code auf Github ;
Lassen Sie mich die Implementierung kurz erläutern.
Werfen wir einen Blick in den Code:
CookieMaker.java
IngredientContainer.java
Alles läuft gut, bis Filler die Behälter füllt. Wenn ich jedoch vergesse, den Füllstoff zu starten, oder der Füllstoff unerwartet verlassen wird, ändern die Sub-Threads ständig ihren Status, damit andere Hersteller den Behälter überprüfen können.
Ich habe auch einen Daemon- ThreadTracer erstellt, der Thread-Zustände und Deadlocks überwacht. Dies ist die Ausgabe von der Konsole;
Sie werden feststellen, dass Sub-Threads und ihre Zustände ändern und warten.
quelle
Ein reales Beispiel (wenn auch ohne exakten Code) sind zwei konkurrierende Prozesse, die live gesperrt werden, um einen SQL Server-Deadlock zu korrigieren, wobei jeder Prozess denselben Wiederholungsalgorithmus für Wiederholungsversuche verwendet. Obwohl es das Glück des Timings ist, habe ich gesehen, dass dies auf separaten Computern mit ähnlichen Leistungsmerkmalen als Reaktion auf eine Nachricht geschieht, die einem EMS-Thema hinzugefügt wurde (z. B. das Speichern einer Aktualisierung eines einzelnen Objektdiagramms mehr als einmal) und nicht gesteuert werden kann die Sperrreihenfolge.
Eine gute Lösung wäre in diesem Fall, konkurrierende Verbraucher zu haben (verhindern Sie die doppelte Verarbeitung so weit oben in der Kette wie möglich, indem Sie die Arbeit auf nicht verwandte Objekte aufteilen).
Eine weniger wünschenswerte (ok, Dirty-Hack) Lösung besteht darin, das Timing-Pech (Art der Kraftunterschiede bei der Verarbeitung) im Voraus zu brechen oder es nach dem Deadlock durch Verwendung verschiedener Algorithmen oder eines zufälligen Elements zu brechen. Dies kann immer noch Probleme verursachen, da die Reihenfolge der Sperren für jeden Prozess möglicherweise "klebrig" ist und dies ein bestimmtes Minimum an Zeit in Anspruch nimmt, das bei der erneuten Wartezeit nicht berücksichtigt wird.
Eine weitere Lösung (zumindest für SQL Server) besteht darin, eine andere Isolationsstufe (z. B. Snapshot) auszuprobieren.
quelle
Ich habe das Beispiel von 2 Personen codiert, die in einem Korridor vorbeikommen. Die beiden Fäden meiden sich, sobald sie feststellen, dass ihre Richtungen gleich sind.
quelle
C # -Version von Jelbourns Code:
quelle
Ein Beispiel hierfür ist die Verwendung eines zeitgesteuerten tryLock, um mehr als eine Sperre zu erhalten. Wenn Sie nicht alle erhalten können, ziehen Sie sich zurück und versuchen Sie es erneut.
Ich könnte mir vorstellen, dass ein solcher Code problematisch wäre, da viele Threads kollidieren und darauf warten, eine Reihe von Sperren zu erhalten. Aber ich bin mir nicht sicher, ob dies für mich als einfaches Beispiel sehr überzeugend ist.
quelle
tryLockAll()
mit den Sperren inlocks
derselben Reihenfolge verwendet werden, gibt es kein Livelock.Python-Version von Jelbourns Code:
quelle
Ich ändere die Antwort von @jelbourn. Wenn einer von ihnen bemerkt, dass der andere hungrig ist, sollte er (sie) den Löffel loslassen und auf eine weitere Benachrichtigung warten, damit ein Livelock passiert.
quelle
quelle