2014-12-06 11 views
11

W architekturze x86 zapasy w tej samej lokalizacji pamięci mają całkowitą kolejność, np. Zobacz this video. Jakie są gwarancje w modelu pamięci C++ 11?Czy dwa luźne zapisy do tej samej lokalizacji w różnych wątkach będą zawsze widoczne w tej samej kolejności przez inne wątki?

Dokładniej, w

-- Initially -- 
std::atomic<int> x{0}; 

-- Thread 1 -- 
x.store(1, std::memory_order_release); 

-- Thread 2 -- 
x.store(2, std::memory_order_release); 

-- Thread 3 -- 
int r1 = x.load(std::memory_order_acquire); 
int r2 = x.load(std::memory_order_acquire); 

-- Thread 4 -- 
int r3 = x.load(std::memory_order_acquire); 
int r4 = x.load(std::memory_order_acquire); 

będzie wynik r1==1, r2==2, r3==2, r4==1 wolno (na jakiejś architekturze innej niż x86)? Co się stanie, jeśli zastąpię wszystkie memory_order przez std::memory_order_relaxed?

Odpowiedz

7

Nie, taki wynik nie jest dozwolony. §1.10 [intro.multithread]/P8 18 (podając N3936/C++ 14, ten sam tekst znajduje się w punktach 6 i 16 dla N3337/C++ 11):

8 Wszystkie modyfikacje szczególnym celem atomowy M występują w pewnym danego zamówienia, zwany celu modyfikacja M.

18 Jeżeli obliczenie wartość a obiektu atomowy M zdarza się przed wartości obliczeniowej B M i a bierze swój wartość z efektu ubocznego X na M, wówczas wartość obliczona przez B będzie albo wartością zapamiętaną przez X, albo wartością zapamiętaną przez efekt uboczny Y na M, gdzie Y, ows X w kolejność modyfikacji M. [Uwaga: Ten wymóg jest znany jako spójność odczytu. - koniec uwaga]

W kodzie istnieją dwa skutki uboczne, a przez P8 występują one w jakimś konkretnym celu całkowitego. W wątku 3 obliczenie wartości do obliczenia wartości, która ma być przechowywana w r1, ma miejsce wcześniej niż, tak więc wiemy, że sklep realizowany przez wątek 1 poprzedza sklep realizowany przez wątek 2 w kolejności modyfikacji x. W tym przypadku, Thread 4 nie może obserwować r3 == 2, r4 == 1 bez wywoływania afoul z p18. Jest to niezależne od użytego memory_order.

Jest notatkę w p21 (p19 w N3337), które są istotne:

[Uwaga: Cztery Powyższe wymagania spójność skutecznie Zabroń kompilatora zmiany kolejności operacji atomowych do pojedynczego obiektu, nawet jeśli obie operacje są zrelaksowanymi ładunkami. Dzięki temu gwarancja spójności pamięci podręcznej jest zapewniona przez większość sprzętu dostępnego dla operacji atomowych C++ . - koniec uwaga]

+0

Czy możesz mi pomóc zrozumieć p18? Czy synonim "obliczania wartości" jest synonimem synonimu load-from-atomic i 'side effect' z store-to-atomic? –

+0

@ TobiasBrüll Obciążenie to obliczenie wartości; Sklep jest efektem ubocznym. –

+0

Jakie inne rodzaje obliczeń wartości istnieją? A jakie inne efekty uboczne? –

4

według C++ 11 [intro.multithread]/6 „Wszystkie modyfikacje konkretnego obiektu atomowej M występuje w jakiejś konkretnej zamówienia, zwany celu modyfikacji M” W związku z tym odczyty obiektu atomowego przez konkretny wątek nigdy nie zobaczą wartości "starszych" niż te, które wątek już zaobserwował. Zauważ, że tutaj nie ma wzmianki o zamawianiu pamięci, więc ta właściwość jest prawdziwa dla wszystkich z nich - seq_cst do relaxed.

W przykładzie podanym w PO, kolejność modyfikacji x może być (0,1,2) lub (0,2,1). Wątek, który zaobserwował daną wartość w tej kolejności modyfikacji, nie może później zaobserwować wcześniejszej wartości. Wynik r1==1, r2==2 oznacza, że ​​kolejność modyfikacji x to (0,1,2), ale r3==2, r4==1 implikuje, że jest to sprzeczność między (0,2,1). Tak więc wynik nie jest możliwy w implementacji zgodnej z C++ 11.

Powiązane problemy