2015-04-28 16 views
5

Zgodnie z tym https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html, zwolniony magazyn jest zaimplementowany jako MOV (do pamięci).Czy instrukcja MOV x86 implementuje magazyn atomowy C++ 11 memory_order_release?

Według jego http://en.cppreference.com/w/cpp/atomic/memory_order

memory_order_release:

Operacja sklep z tej kolejności pamięci wykonuje operację uwalniania : brak pamięci dostęp do bieżącego wątku może zostać zreorganizowane po tym sklepie. Zapewnia to, że wszystkie zapisy w bieżącym wątku są widoczne w innych wątkach, które przejmują tę samą zmienną atomową i zapisują, że przenoszą zależność do zmiennej atomowej, widocznej w innych wątkach, które pochłaniają tę samą atomową.

Rozumiem, że gdy jest stosowany memory_order_release, wszystkie sklepy pamięci wykonane wcześniej należy zakończyć przed tym.

int a; 
a = 10; 
std::atomic<int> b; 
b.store(50, std::memory_order_release); // i can be sure that 'a' is already 10, so processor can't reorder the stores to 'a' and 'b' 

PYTANIE:, jak to możliwe, że tylko instrukcja MOV jest wystarczająca dla takiego zachowania? W jaki sposób MOV mówi procesorowi, aby zakończył wszystkie poprzednie sklepy?

+1

Zapomniałeś wspomnieć o "na x86" – Cubbi

+0

@cubbi: prawda, to ważne, zrobione – Krab

+0

Ponieważ jest to dynamiczny zaplanowany ISA, chip zawsze zakłada najgorszy przypadek. – user3528438

Odpowiedz

3

To wydaje się być odwzorowanie, przynajmniej w kod skompilowany z kompilatora Intel, gdzie widzę:

0000000000401100 <_Z5storeRSt6atomicIiE>: 
    401100:  48 89 fa    mov %rdi,%rdx 
    401103:  b8 32 00 00 00   mov $0x32,%eax 
    401108:  89 02     mov %eax,(%rdx) 
    40110a:  c3      retq 
    40110b:  0f 1f 44 00 00   nopl 0x0(%rax,%rax,1) 

0000000000401110 <_Z4loadRSt6atomicIiE>: 
    401110:  48 89 f8    mov %rdi,%rax 
    401113:  8b 00     mov (%rax),%eax 
    401115:  c3      retq 
    401116:  0f 1f 00    nopl (%rax) 
    401119:  0f 1f 80 00 00 00 00 nopl 0x0(%rax) 

kodu:

#include <atomic> 
#include <stdio.h> 

void store(std::atomic<int> & b) ; 

int load(std::atomic<int> & b) ; 

int main() 
{ 
    std::atomic<int> b ; 

    store(b) ; 

    printf("%d\n", load(b)) ; 

    return 0 ; 
} 

void store(std::atomic<int> & b) 
{ 
    b.store(50, std::memory_order_release) ; 
} 

int load(std::atomic<int> & b) 
{ 
    int v = b.load(std::memory_order_acquire) ; 

    return v ; 
} 

Obecny Intel architecture documents, tom 3 (Podręcznik programowania systemu), wyjaśnia to doskonale. Zobacz:

8.2.2 Kolejność w pamięci P6 i nowszych procesorów Rodziny

  • Odsłon nie zostanie zmieniona z innymi czyta.
  • Zapisy nie są porządkowane ze starszymi odczytami.
  • zapisuje do pamięci nie zostanie zmieniona z innych zapisów, z następującymi wyjątkami: ...

Pełen model pamięci jest tam wyjaśnione. Zakładam, że Intel i użytkownicy standardu C++ pracowali razem, aby uzyskać najlepsze odwzorowanie dla każdej operacji kolejności pamięci, która jest zgodna z modelem pamięci opisanym w tomie 3, i ustalono zwykłe magazyny i obciążenia. być wystarczającym w tych przypadkach.

Należy pamiętać, że fakt, że dla tego zamówionego sklepu nie są wymagane specjalne instrukcje na x86-64, nie oznacza, że ​​będzie on uniwersalny. Dla powerpc spodziewałbym się zobaczyć coś w rodzaju instrukcji lwsync wraz ze sklepem, a na hpux (ia64) kompilator powinien używać instrukcji st4.rel.

4

Jest pamięć zamawiania w czasie wykonywania (przez CPU) i jest kolejność pamięci podczas kompilacji. memory_order_release zapobiega zmianie kolejności dostępu do danych przez kompilator.Przeczytaj this article (a także wiele innych dobrych na tym blogu), aby uzyskać więcej informacji.

Powiązane problemy