ARM64: LDXR/STXR vs LDAXR/STLXR
Unter iOS gibt es zwei ähnliche Funktionen OSAtomicAdd32
und OSAtomicAdd32Barrier
. Ich bin gespannt, Wann müssen Sie die Barrier
Variante.
Demontiert, Sie sind:
_OSAtomicAdd32:
ldxr w8, [x1]
add w8, w8, w0
stxr w9, w8, [x1]
cbnz w9, _OSAtomicAdd32
mov x0, x8
ret lr
_OSAtomicAdd32Barrier:
ldaxr w8, [x1]
add w8, w8, w0
stlxr w9, w8, [x1]
cbnz w9, _OSAtomicAdd32Barrier
mov x0, x8
ret lr
In welchen Szenarien würden Sie brauchen, die Last-Erwerben /Store-Release-Semantik des letzteren? Kann LDXR
/STXR
Anweisungen nachbestellt werden? Wenn Sie können, ist es möglich, dass ein atomarer update "verloren" in dem fehlen einer Barriere? Von dem, was ich gelesen habe, es scheint nicht, wie das geschehen kann, und wenn das stimmt, dann warum würden Sie brauchen, die Barrier
Variante? Vielleicht nur, wenn Sie zufällig auch die Notwendigkeit einer DMB
für andere Zwecke?
Dank!
Du musst angemeldet sein, um einen Kommentar abzugeben.
OSAtomicAdd32Barrier()
besteht für Personen, die mitOSAtomicAdd()
für etwas, das jenseits nur Atomare Inkrement. Insbesondere sind Sie der Umsetzung Ihrer eigenen multi-processing-Synchronisations-primitive basieren aufOSAtomicAdd()
. Zum Beispiel, erstellen Sie Ihre eigenen mutex-Bibliothek.OSAtomicAdd32Barrier()
verwendet schwere Barriere Anweisungen durchzusetzen speicheranordnung auf beiden Seiten des atomaren operation. Dies ist nicht wünschenswert, bei normaler Nutzung.Zusammenfassen:
1), Wenn Sie nur wollen, zum Inkrementieren eines integer in eine thread-sichere Weise, verwenden Sie
OSAtomicAdd32()
2) Wenn Sie stecken mit einem Haufen Alter code, der dummerweise davon ausgegangen
OSAtomicAdd32()
können verwendet werden, als interprocessor speicheranordnung und Spekulationen Barriere, ersetzen Sie es mitOSAtomicAdd32Barrier()
ldxr
,add
,stxr
in einer Schleife, bisstxr
gelingt".Oh, die Geistes-Biege-horror von schwach-Speicher bestellen...
Dem ersten snippet ist Ihre grundlegende Atomare read-modify-write -, wenn jemand anderes berührt, was auch immer-Adresse
x1
Punkte zu, der store-exclusive wird scheitern und es erneut versuchen, bis es gelingt. So weit So gut. Allerdings gilt dies nur für die Adresse (oder mehr zurecht region) abgedeckt durch die exklusive monitor, so, während es gut für Atomarität, es ist unwirksam für synchronisation nichts anderes als dieser Wert.Betrachten einen Fall, wo CPU1 wartet für CPU0 zum schreiben von Daten in einen Puffer. CPU1 sitzt da und wartet auf irgendeine Art von synchronisation Objekt (sagen wir mal ein semaphor), warten auf CPU0, um es zu aktualisieren, um zu signalisieren, dass neue Daten bereit ist.
Nun, was passiert in Schritt 3? Vielleicht ist es alles eingetreten ist in Ordnung. Sehr wahrscheinlich die hardware entschieden, dass, da gab es keine Adresse Abhängigkeit lassen würde, die speichern die semaphore gehen Sie vor dem speichern der Daten-Adresse. Vielleicht ist die semaphore store Treffer in dem cache, in der Erwägung, dass die Daten nicht. Vielleicht ist es nur getan, weil von komplizierten Gründen nur die hardware-Jungs verstehen. So oder so ist es durchaus möglich für CPU1, um zu sehen, die semaphor-update vor der neuen Daten getroffen hat, die Speicher, also wieder Lesen, die ungültige Daten.
Um dies zu beheben, CPU0 müssen eine Barriere zwischen den Schritten 1 und 2, um sicherzustellen, dass die Daten auf jeden Fall hat geschrieben vor die semaphore geschrieben. Nachdem das Atomare schreiben werden eine Barriere ist ein schöner einfacher Weg, dies zu tun. Aber da die Hürden sind ziemlich performance-erniedrigende, die Sie wollen, dass die leichten no-barrier-version als auch für Situationen, in denen Sie nicht brauchen, diese Art von vollständiger synchronisation.
Nun, die noch weniger intuitive Teil ist, dass CPU1 konnte auch nachbestellen seinen Lasten. Wieder da es ist keine Adresse Abhängigkeit, es wäre frei, zu spekulieren, die Daten laden, bevor die semaphore Last unabhängig von CPU0 Barriere. Also CPU1 muss auch seine eigenen Barriere zwischen den Schritten 4 und 5.
Für die mehr autoritär, aber ziemlich schwer zu gehen, version gelesen zu haben von ARM Barriere Lackmus-Tests und Kochbuch. Seien Sie gewarnt, dieses Zeug kann verwirrend 😉
Als ein beiseite, in diesem Fall die architektonische Semantik von acquire/release die Dinge zu komplizieren weiter. Da Sie nur Einweg-Schranken, während
OSAtomicAdd32Barrier
fügt bis zu eine Barriere relativ zum code vor und nach es es nicht wirklich garantieren eine Reihenfolge relativ zu den atomaren operation selbst - siehe diese Diskussion von Linux weitere Erklärung. Natürlich, das ist aus der theoretischen Sicht der Architektur; in Wirklichkeit ist es nicht denkbar, dass der A7-hardware, hat die "einfache" Möglichkeit, die Verkabelung bisLDAXR
nurDMB+LDXR
, und so weiter, das heißt, Sie können sich mit diesem, da Sie die Freiheit, code zu Ihrer eigenen Umsetzung, sondern als die Spezifikation.Ich würde vermuten, dass das ist einfach ein Weg der Reproduktion der bestehenden Architektur-unabhängige Semantik für diese operation.
Mit der
ldaxr
/stlxr
- pair-Mädchen, das oben-Sequenz sorgt für die richtige Bestellung, wenn die AtomicAdd32 dient als Synchronisations-Mechanismen (mutex/semaphore) - unabhängig davon, ob der resultierende höhere-Ebene-operation ist ein Erwerb oder Veröffentlichung.Also - es geht nicht um die Durchsetzung der Konsistenz der atomaren hinzufügen, aber über die Durchsetzung der Bestellung zwischen Erwerb/freigeben eines mutex und alle Operationen auf der Ressource, die geschützt durch das mutex.
Es ist weniger effizient als die
ldxar
/stxr
oderldxr
/stlxr
würden Sie in einem normalen nativen Synchronisationsmechanismus, aber wenn Sie vorhandene Plattform-unabhängigen code in der Erwartung einer atomaren hinzufügen, mit denen der Semantik, dies ist wahrscheinlich der beste Weg, es zu implementieren.