Ich hatte den Eindruck, dass Speicherbelastungen nicht über eine Acquiring-Last im C++ 11-Speichermodell gehisst werden konnten. Aber wenn man sich den Code anschaut, den gcc 4.8 erzeugt, scheint das nur für andere atomare Lasten zu gelten, nicht für den gesamten Speicher. Wenn das stimmt und das Laden von Lasten nicht den gesamten Speicher synchronisiert (nur std::atomics
), dann bin ich nicht sicher, wie es möglich wäre, allgemeine Mutexe in Bezug auf std :: atomic zu implementieren.Heben von nicht-atomaren Lasten durch Erfassen atomarer Lasten
Der folgende Code:
extern std::atomic<unsigned> seq;
extern std::atomic<int> data;
int reader() {
int data_copy;
unsigned seq0;
unsigned seq1;
do {
seq0 = seq.load(std::memory_order_acquire);
data_copy = data.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
seq1 = seq.load(std::memory_order_relaxed);
} while (seq0 != seq1);
return data_copy;
}
Produziert:
_Z6readerv:
.L3:
mov ecx, DWORD PTR seq[rip]
mov eax, DWORD PTR data[rip]
mov edx, DWORD PTR seq[rip]
cmp ecx, edx
jne .L3
rep ret
Was mir richtig aussieht.
jedoch das Ändern von Daten ein int
eher als std::atomic
:
extern std::atomic<unsigned> seq;
extern int data;
int reader() {
int data_copy;
unsigned seq0;
unsigned seq1;
do {
seq0 = seq.load(std::memory_order_acquire);
data_copy = data;
std::atomic_thread_fence(std::memory_order_acquire);
seq1 = seq.load(std::memory_order_relaxed);
} while (seq0 != seq1);
return data_copy;
}
Dies erzeugt:
_Z6readerv:
mov eax, DWORD PTR data[rip]
.L3:
mov ecx, DWORD PTR seq[rip]
mov edx, DWORD PTR seq[rip]
cmp ecx, edx
jne .L3
rep ret
Also, was ist los?
Wenn Sie atomare Operationen umschreiben, um 'laden (rel); fence (acq); 'ändert sich in der zweiten Version die Ausgabe asm? – yohjp
@yoyjp Beziehen Sie sich auf das Laden von 'seq0'? Wenn ja, dann hat das keinen Einfluss auf den generierten Code. – jleahy
Nein, ich erwähnte 'seq1'. Ein "acquire fence", der eine Semantik besitzt, besteht aus 'seq1.load (relaxed) -> fence (acquire)' ops order, nicht 'fence (acquire) -> seq1.load (relaxed)' in C++ 11 memory Modell. C++ 's "Zaun" ** nur ** beeinflusst _happens-before-Beziehung_ zwischen atomaren Operationen und/oder Zäunen, es hat ** no ** direkten Einfluss auf nicht-atomare vars. In diesem Punkt unterscheidet sich C++ 'Fence' ziemlich von der Speicherbarrierenanweisung des Prozessors/Compilers (wie zB mfence of x86). – yohjp