In Java ist das Aktualisieren der Variablen double und long möglicherweise nicht atomar, da double / long als zwei separate 32-Bit-Variablen behandelt werden.
Wenn ich in C ++ 32-Bit-Intel-Prozessor + Microsoft Visual C ++ - Compiler verwende, wird Doppeloperation (8 Byte) atomar aktualisiert?
Ich kann nicht viel Spezifikation zu diesem Verhalten finden.
Wenn ich "atomare Variable" sage, hier ist was ich meine:
Thread A versucht 1 in die Variable x zu schreiben. Thread B versucht, 2 in die Variable x zu schreiben.
Wir erhalten den Wert 1 oder 2 aus der Variablen x, aber keinen undefinierten Wert.
Dies ist hardwarespezifisch und hängt von der Architektur ab. Für x86 und x86_64 sind 8-Byte-Schreib- oder Lesevorgänge garantiert atomar, wenn sie ausgerichtet sind. Zitat aus dem Intel Architecture Memory Ordering Whitepaper:
Intel 64 Speicher Bestellgarantien das für jeden der folgenden Speicherzugriffsanweisungen, die konstituierende Speicheroperation erscheint als einzigen Speicherzugriff auszuführen unabhängig vom Speichertyp:
Anweisungen, die ein einzelnes Byte lesen oder schreiben.
Anweisungen, die ein Wort (2 Bytes) lesen oder schreiben, dessen Adresse ist auf einer 2-Byte-Grenze ausgerichtet.
Anweisungen, die ein Doppelwort (4 Bytes) lesen oder schreiben, dessen Adresse ist auf einer 4-Byte-Grenze ausgerichtet.
- Anweisungen, die ein Vierwort (8 Bytes) lesen oder schreiben, dessen Adresse ist an einer 8-Byte-Grenze ausgerichtet.
Alle gesperrten Anweisungen (implizit gesperrt xchg Anweisung und andere read-modify-write-Anweisungen mit a Sperrpräfix) sind ein unteilbares und unterbrechungsfreie Reihenfolge der Ladung (en) gefolgt von Geschäften unabhängig von Speichertyp und Ausrichtung.
Man kann davon ausgehen, dass das Aktualisieren eines double niemals atomar ist, auch wenn seine Größe mit der int-Garantie identisch ist. Der Grund dafür ist, dass es einen anderen Verarbeitungspfad gibt, da es sich um einen unkritischen und teuren Datentyp handelt. Zum Beispiel erwähnen selbst Datenbarrieren normalerweise, dass sie nicht auf Fließkommadaten / Operationen im Allgemeinen anwendbar sind.
Visual C ++ wird primitiven Typen zuweisen (siehe Artikel ) und Dies sollte zwar garantieren, dass Bits während des Schreibens in den Speicher nicht verzerrt werden (8-Byte-Alignment befindet sich immer in einer 64- oder 128-Bit-Cache-Zeile). Der Rest hängt davon ab, wie die CPU nicht-atomare Daten im Cache behandelt und ob sie lesen / spülen Eine Cache-Zeile ist unterbrechbar. Also, wenn Sie durch Intel Docs für die Art von Kern graben, die Sie verwenden, und es gibt Ihnen die Garantie, dann können Sie sicher gehen.
Der Grund, warum die Java-Spezifikation so konservativ ist, ist, dass sie auf einem alten 386 und auf Corei7 genauso laufen soll. Was natürlich wahnhaft ist aber ein Versprechen ist ein Versprechen, daher verspricht es weniger :-)
Der Grund, warum ich sage, dass Sie CPU doc suchen müssen, ist, dass Ihre CPU eine alte 386 oder ähnlich sein könnte :-)) Vergessen Sie nicht, dass Ihre 8-Byte-Block auf einer 32-Bit-CPU dauert 2 "Runden" für den Zugriff, so dass Sie auf die Gnade der Mechanik des Cache-Zugriffs angewiesen sind.
Cache-Zeilenspülung, die eine viel höhere Datenkonsistenz garantiert, gilt nur für eine einigermaßen aktuelle CPU mit Intel-ian-Garantie (automatische Cache-Konsistenz).
Ich würde nicht in irgendeiner Architektur denken, Thread / Kontextwechsel würde das Aktualisieren eines Registers auf halbem Weg unterbrechen, so dass Sie zum Beispiel 18 Bits von den 32 Bits aktualisiert erhalten, die es aktualisieren würde. Dies gilt auch für die Aktualisierung eines Speicherplatzes (vorausgesetzt, es handelt sich um eine Basiszugriffseinheit, 8,16,32,64 Bits usw.).
Also wurde diese Frage beantwortet? Ich habe ein einfaches Testprogramm ausgeführt, das ein Double ändert:
%Vor% Ich habe es ohne Optimierungen (gcc -O0) kompiliert, und alle Zuweisungsoperationen werden mit einzelnen Assembleranweisungen wie fldl .LC0
und faddp %st, %st(1)
durchgeführt. ( i += 84626.433
hat natürlich zwei Operationen, faddp
und fstpl
).
Kann ein Thread wirklich innerhalb einer einzelnen Anweisung wie faddp
?
Tags und Links c++ visual-c++