2017-05-10 8 views
0

Ich habe mich gefragt, ob Clojure eine eingebaute Lösung für das ABA-Problem hat. Ich habe ein Beispiel erstellt, das dieses Problem zeigt, aber irgendwie erkennt Clojure die Änderungen. Liegt das daran, dass Clojures Transaktionen die Referenzen und nicht die Werte vergleichen?ABA mit Clojure Software Transaktionsspeicher

Mein Beispiel:

(def x (ref 42)) 
(def io (atom false)) 
(def tries (atom 0)) 

(def t1 (Thread. (fn [] (dosync (commute x - 42))))) 
(def t2 (Thread. (fn [] (dosync 
          (Thread/sleep 100) 
          (commute x + 42))))) 
(def t3 (Thread. 
    (fn [] 
    (dosync 
     (do 
     (Thread/sleep 1000) 
     (swap! tries inc) 
     (if (= 42 @x) 
      (reset! io true))))))) 

(.start t3) 
(.start t1) 
(.start t2) 

(.join t1) 
@x 
(.join t2) 
@x 
(.join t3) 
@tries 
(if (= true @io) (println "The answer is " @x)) 

Die Versuche zählen ist immer 2, so dass die Transaktion T3 die ref haben müssen Änderungen von T1 und T2 bemerkt. Kennt jemand die Ursache für dieses Verhalten?

Antwort

0

Sie haben Recht, dass dies das erwartete Verhalten ist (obwohl ich erwartet hätte, dass tries 1 ist). Neben den vielen Bücher Clojure diskutieren Software Transactional Memory (STM), können Sie auch

auch überprüfen möchten, ist es in der Regel am besten alter stattdessen zu verwenden von commute, die leicht falsch ist und in der Regel eine "vorzeitige Optimierung" ist.

0

Bevor ich die Frage beantworte, möchte ich nur sagen, dass bei weitem die beste Informationsquelle über Clojures STM - neben dem Quellcode selbst - Mark Volkmanns Software Transactional Memory Artikel ist (die Linkpunkte bei einem Changelog Seite, folgen Sie dem Link zur neuesten Version von dort). Es ist unglaublich umfassend. (Machen Sie sich keine Gedanken über den Zeitstempel von 2009, der STM ändert sich nicht viel.) Wenn Sie genau überlegen wollen, wie die Dinge in Szenarien wie diesem funktionieren, empfehle ich Ihnen, es zu lesen.


Was das Szenario auf der Hand:

Für eine in-Transaktion eines Ref lesen, verspricht das STM einen Wert zurückgeben, die vor der aktuellen Transaktion Versuch begangen wurde. (Es sei denn, die aktuelle Transaktion try hat selbst den In-Transaction-Wert der Ref in Frage gesetzt.) Dieser Wert kann der letzte in die Ref geschriebene Wert sein oder nicht, wenn dies nicht der Fall ist, muss der Read sein zufrieden aus der Geschichte des Ref. Wenn die Historie der Ref keinen solchen Wert enthält, wird eine Störung für die Ref und die Transaktionsversuche aufgezeichnet. Anschließend kann die Länge der History-Kette der Ref aufgrund des Fehlers bis zur maximalen History-Länge der Ref (standardmäßig 10) erhöht werden. Beachten Sie jedoch, dass dies nur geschieht, wenn eine Opportunity vorhanden ist (eine andere schreibt an die Ref) Hilfe bei Transaktionen, die "ausreichend spät" gestartet wurden (so dass ihre Zeitstempel später sind als die eines bestimmten Werts, der in der Historie aufgezeichnet wurde).

Im gegenständlichen Fall seits durch die Zeit t3 die Ref zu lesen Runde bekommt, t1 und t2 ihre Schreiben in x ohne Probleme abgeschlossen haben und x werden nicht mehr in der Lage sein, eine Leseanforderung zu erfüllen, einen Wert von anspruchsvollen vor t3 ist der erste Versuch. (Dies ist darauf zurückzuführen, dass die History-Kette eines Verweises standardmäßig auf Länge 0 beginnt, was bedeutet, dass keine historischen Werte beibehalten werden.) Daher muss t3 einen Fehler für x aufzeichnen und es erneut versuchen.

(Wenn Sie die drei Transaktionen gegen die gleichen Ref und Helfer Atom erneut ausführen - etwa durch wieder alle außer den ersten drei Zeilen in REPL einfügen - Sie tries Sprung zu 4 auf dem zweiten Lauf sehen werden, und dann zu 5 auf dem dritten, die anzeigt, dass ein historischen Wert an diesem Punkt)


auf dem ABA Problem vorhanden ist. weil in

das ABA Problem ist nicht relevant für das STM, ein geeignetes ABA Szenario der "B" wird durch einen anderen Thread und (2) nach dem Speicherort (1) geschrieben das erste Lesen von "A" durch den "Haupt" -Thread (derjenige, der unter dem ABA-Problem leiden soll), und dann ähnlich wird das zweite "A" geschrieben (1) durch einen anderen Thread und (2) nach dem " B "schreiben, und beide" As "werden vom Hauptthread beobachtet, aber das" B "ist nicht - aber wie oben erläutert, können Sie in einer STM-Transaktion keinen Wert beobachten, der von einem anderen Thread nach Ihrem Ref geschrieben wurde Die Transaktion wurde gestartet. Wenn Sie also das erste "A" beobachten, können Sie weder das "B" noch das zweite "A" beobachten.

Das bedeutet nicht, dass keine Parallelität Probleme im Zusammenhang mit dem STM möglich sind - es ziemlich einfach ist, in dem Schreib Skew laufen (beschrieben in the Wikipedia article on snapshot isolation - das ist, was die ensure Funktion zu beheben ist so konzipiert, aber es ist bis zu Benutzercode um es gegebenenfalls anzurufen) commute kann missbraucht werden & c.

+0

Ok, ich verstehe es jetzt. Das Problem war, dass einige Quellen, die ich las, angaben, dass die ABA ein Problem mit STM ist. –