2013-07-27 16 views
8

Czytałem odpowiedź na to pytanie dotyczące lotnych słowo kluczowe:Przykład C++ "bariera pamięci"

https://stackoverflow.com/a/2485177/997112

osoba mówi:

Rozwiązanie zapobiega zamianom jest użycie bariera pamięci, , która wskazuje zarówno kompilatorowi, jak i procesorowi, że brak dostępu do pamięci może zostać zmieniony w tym punkcie. Umieszczenie takich barier wokół naszego zmiennego dostępu o zmiennej wartości zapewnia, że ​​nawet nieulotny dostęp nie zostanie zmieniony na lotny, dzięki czemu możemy napisać bezpieczny dla wątków kod .

Jednak bariery pamięci zapewniają również, że wszystkie oczekujące odczyty/zapisy są wykonane wykonane po przekroczeniu bariery, więc skutecznie daje nam to wszystko, czego potrzebujemy, co powoduje, że lotny niepotrzebny. Możemy tylko usunąć całkowicie zmienny kwalifikator.

Jak ta "bariera pamięci" została zaimplementowana w C++?

EDIT:

mógłby ktoś podać prosty przykład kodu proszę?

+0

@HansPassant nie ma prostego przykładu bariery pamięci C++ w pytaniu, które łączyłeś z – user997112

+0

Kto obiecał, że będzie to proste? To jest C++, to powinno być trudne. Gdyby tak nie było, to każdy mógł być programistą C++ :) Przynajmniej słowo "Memory Barrier" w tytule pytania powinno być podpowiedzią, że jest to dokładnie to samo pytanie. –

Odpowiedz

6

Jest to bardzo zależne od sprzętu. Od dość długiego documentation of memory barrier jądra Linux:

The Linux kernel has eight basic CPU memory barriers: 

TYPE    MANDATORY    SMP CONDITIONAL 
===============  ======================= =========================== 
GENERAL    mb()     smp_mb()  
WRITE    wmb()     smp_wmb() 
READ    rmb()     smp_rmb() 
DATA DEPENDENCY  read_barrier_depends() smp_read_barrier_depends() 

Weźmy jeden z nich w szczególności: smp_mb(). Jeśli otworzysz asm/x86/um/asm/barrier.h, można zauważyć, że gdy CONFIG_SMP jest zdefiniowana,

#define smp_mb() mb() 

A jeśli przewijać w górę, można zobaczyć, że w zależności od platformy, mb ma różne implementacje:

// on x86-32 
#define mb()  alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) 
// on other platforms 
#define mb()  asm volatile("mfence" : : : "memory") 

Więcej informacje na temat różnic między tymi 2 rzeczami zostały omówione w this thread. Mam nadzieję, że to pomoże.

+0

są te wywołania systemowe? Czy programista nie może sam stworzyć bariery pamięci? – user997112

+3

nie są one wywołaniami systemowymi (btw, możesz znaleźć wszystkie wywołania systemowe, uruchamiając 'man 2 syscalls'). Kompilator C++ zastąpi twoje wywołanie 'mb()' odpowiednią instrukcją ASM w skompilowanym kodzie. Możesz sam stworzyć barierę pamięci, która polegałaby na wywołaniu niektórych instrukcji montażu, tak jak robi to kod źródłowy Linuksa. – qdii

6

bariera pamięci są trywialne używać w C++ 11:

std::atomic<int> i; 

Wszystko dostęp do i będą chronione przez bariery pamięci.

3

Zazwyczaj istnieją "funkcje wewnętrzne" - są to specjalne funkcje, które kompilator ma szczególną wiedzę na temat działania (w szczególności, że są to bariery pamięciowe). Nazwy różnią się od kompilatora do kompilatora (i czasami dla różnych architektur tego samego kompilatora).

Na przykład MSVC używa _ReadBarrier, WriteBarrier i _ReadWriteBarrier

W x86 byłoby produkować lfence, sfence lub mfence dyspozycję - co odpowiednio oznacza "obciążenie", "Store" i "Wszystkie operacje pamięciowe" barier - innymi słowy, lfence będzie barierą dla operacji odczytu pamięci, sfence będzie barierą "zapisu zapisu", a mfence będzie barierą zarówno dla operacji odczytu, jak i zapisu.