asm volatile("": : :"memory")
wird oft als Speicherbarriere verwendet (z. B. im Linux-Kernel barrier
Makro).
Das klingt ähnlich wie das, was der GCC eingebaut hat __sync_synchronize
tut.
Sind diese beiden ähnlich?
Wenn nicht, was sind die Unterschiede, und wann würde man das eine gegenüber dem anderen verwenden?
Es gibt einen signifikanten Unterschied – die erste Option (inline asm) macht zur Laufzeit tatsächlich nichts, es wird dort kein Befehl ausgeführt und die CPU weiß nichts davon. Es dient nur zur Kompilierzeit, um den Compiler anzuweisen, im Rahmen seiner Optimierungen keine Lade- oder Speichervorgänge über diesen Punkt (in irgendeine Richtung) hinaus zu verschieben. Es heißt SW-Barriere.
Die zweite Barriere (eingebaute Synchronisierung) würde sich einfach in eine HW-Barriere übersetzen, wahrscheinlich eine Fence-Operation (mfence/sfence), wenn Sie x86 verwenden, oder ihre Entsprechungen in anderen Architekturen. Die CPU kann auch verschiedene Optimierungen zur Laufzeit durchführen, die wichtigste ist tatsächlich die Ausführung von Operationen außerhalb der Reihenfolge – diese Anweisung weist sie an, sicherzustellen, dass Ladevorgänge oder Speicherungen diesen Punkt nicht passieren können und auf der richtigen Seite beobachtet werden müssen der Synchronisationspunkt.
Hier ist noch eine gute erklärung:
Arten von Gedächtnisbarrieren
Wie oben erwähnt, können sowohl Compiler als auch Prozessoren die Ausführung von Anweisungen so optimieren, dass eine Speicherbarriere verwendet werden muss. Eine Speicherbarriere, die sowohl den Compiler als auch den Prozessor betrifft, ist eine Hardware-Speicherbarriere, und eine Speicherbarriere, die nur den Compiler betrifft, ist eine Software-Speicherbarriere.
Zusätzlich zu Hardware- und Softwarespeicherbarrieren kann eine Speicherbarriere auf Speicherlesevorgänge, Speicherschreibvorgänge oder beides beschränkt werden. Eine Speicherbarriere, die sowohl Lese- als auch Schreibvorgänge betrifft, ist eine Vollspeicherbarriere.
Es gibt auch eine Klasse von Speicherbarrieren, die spezifisch für Umgebungen mit mehreren Prozessoren ist. Dem Namen dieser Speicherbarrieren wird “smp” vorangestellt. Auf einem Mehrprozessorsystem sind diese Barrieren Hardwarespeicherbarrieren und auf Einprozessorsystemen sind sie Softwarespeicherbarrieren.
Das Makro barrier() ist die einzige Software-Speicherbarriere und eine vollständige Speicherbarriere. Alle anderen Speicherbarrieren im Linux-Kernel sind Hardwarebarrieren. Eine Hardwarespeicherbarriere ist eine implizite Softwarebarriere.
Ein Beispiel dafür, wann eine SW-Barriere nützlich ist: Betrachten Sie den folgenden Code –
for (i = 0; i < N; ++i) {
a[i]++;
}
Diese einfache Schleife, die mit Optimierungen kompiliert wurde, würde höchstwahrscheinlich entrollt und vektorisiert werden. Hier ist der Assembler-Code gcc 4.8.0 -O3, der gepackte (Vektor-)Operationen generiert:
400420: 66 0f 6f 00 movdqa (%rax),%xmm0
400424: 48 83 c0 10 add $0x10,%rax
400428: 66 0f fe c1 paddd %xmm1,%xmm0
40042c: 66 0f 7f 40 f0 movdqa %xmm0,0xfffffffffffffff0(%rax)
400431: 48 39 d0 cmp %rdx,%rax
400434: 75 ea jne 400420 <main+0x30>
Wenn Sie jedoch Ihre Inline-Assembly bei jeder Iteration hinzufügen, darf gcc die Reihenfolge der Operationen hinter der Barriere nicht ändern, sodass sie nicht gruppiert werden können, und die Assembly wird zur skalaren Version der Schleife:
400418: 83 00 01 addl $0x1,(%rax)
40041b: 48 83 c0 04 add $0x4,%rax
40041f: 48 39 d0 cmp %rdx,%rax
400422: 75 f4 jne 400418 <main+0x28>
Wenn die CPU diesen Code jedoch ausführt, ist es erlaubt, die Operationen “unter der Haube” neu zu ordnen, solange das Speicherordnungsmodell nicht beschädigt wird. Dies bedeutet, dass die Ausführung der Operationen außerhalb der Reihenfolge erfolgen kann (sofern die CPU dies unterstützt, wie dies heutzutage meistens der Fall ist). Ein HW-Zaun hätte das verhindert.
Ein Kommentar zur Nützlichkeit von Nur-SW-Barrieren:
Auf einigen Mikrocontrollern und anderen eingebetteten Plattformen haben Sie möglicherweise Multitasking, aber kein Cache-System oder keine Cache-Latenz und daher keine HW-Barriereanweisungen. Sie müssen also Dinge wie SW-Spinlocks tun. Die SW-Barriere verhindert Compiler-Optimierungen (Lese-/Schreib-Kombination und Neuordnung) in diesen Algorithmen.
[email protected]
ist wahrscheinlich ein besserer Ort, um zu fragen. Und Ihre Frage hängt von der aktuellen Version Ihres GCC-Compilers ab!– Basile Starynkevitch
13. November 2013 um 21:51 Uhr
Es ist in Ordnung, hier zu fragen. StackOverflow ist so konzipiert, dass es besser ist als Mailinglisten und Foren, da die richtige Antwort nach oben schwebt und irrelevante Diskussionen wie diese minimiert werden.
– David Grayson
11. Juli 2015 um 19:30 Uhr
… und die Antworten werden mit anderen geteilt 🙂
– Mark Watson
16. März um 14:37 Uhr