Miałem wrażenie, że ładowanie pamięci nie może zostać podniesione ponad ładunek przejęty w modelu pamięci C++ 11. Jednak patrząc na kod, który produkuje gcc 4.8, wydaje się, że tylko w przypadku innych ładunków atomowych, a nie całej pamięci. Jeśli to prawda, a ładowanie odbiorów nie synchronizuje całej pamięci (tylko std::atomics
), to nie jestem pewny, jak byłoby możliwe zastosowanie muteksów ogólnego przeznaczenia w kategoriach std :: atomic.Podnoszenie ładunków nieatomowych poprzez przejęcie obciążeń atomowych
Poniższy kod:
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;
}
Produkuje:
_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
który wygląda poprawna do mnie.
jednak zmianę danych być int
zamiast 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;
}
Wytwarza to:
_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
Więc co się dzieje?
Jeśli przepisujesz kolejność atomów na 'load (rel); fence (acq); 'w drugiej wersji, czy zmienia się jej wyjście asm? – yohjp
@yoyjp Czy odnosisz się do ładowania 'seq0'? Jeśli tak, to nie, nie ma to wpływu na generowany w ogóle kod. – jleahy
Nie, wspomniałem "seq1". "Przejęcie ogrodzenia", które uzyskało semantykę, składa się z 'seq1.load (relaxed) -> fence (nabycie)' ops order, a nie 'fence (acquire) -> seq1.load (relaxed)' w pamięci C++ 11 Model. "Ogrodzenie" C++ ** tylko ** wpływa na _happens-before relationship_ pomiędzy operacjami atomowymi i/lub płotami, ma ** ** wpływ bezpośredni na nieatomowe vary. W tym miejscu "ogrodzenie" C++ różni się znacznie od instrukcji zapory pamięciowej procesora/kompilatora (np. Mfence x86). – yohjp