2013-09-02 4 views
7

Es ist bekannt, dass auf x86 für die Operationen load() und store() Speicherbarrieren memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel keine Prozessoranweisungen für den Cache und Pipeline und Montage-Code immer std::memory_order_relaxed entspricht erfordert, und diese Beschränkungen sind nur dann erforderlich, für die Optimierung der Compiler: http://www.stdthread.co.uk/forum/index.php?topic=72.0Benötigt die Semantik von `std :: memory_order_acquire` Prozessoranweisungen auf x86/x86_64?

Und dieser Code Zerlegen Code bestätigt dies für store() (MSVS2012 x86_64):

std::atomic<int> a; 
    a.store(0, std::memory_order_relaxed); 
000000013F931A0D mov   dword ptr [a],0 
    a.store(1, std::memory_order_release); 
000000013F931A15 mov   dword ptr [a],1 

Aber dieser Code dies für load() (MSVS2012 x86_64) nicht comfirm, mit lock cmpxchg:

int val = a.load(std::memory_order_acquire); 
000000013F931A1D prefetchw [a] 
000000013F931A22 mov   eax,dword ptr [a] 
000000013F931A26 mov   edx,eax 
000000013F931A28 lock cmpxchg dword ptr [a],edx 
000000013F931A2E jne   main+36h (013F931A26h) 

    std::cout << val << "\n"; 

Aber Anthony Williams said:

some_atomic.load (std :: memory_order_acquire) macht genau Drop to eine einfache Ladeanweisung und some_atomic.store (Std :: memory_order_release) fällt auf eine einfache speichern Anweisung.

Wo bin ich falsch, und nicht die Semantik von std::memory_order_acquire erfordert Prozessoranweisungen auf x86/x86_64 lock cmpxchg oder nur einen einfachen Ladebefehl mov wie sagte Anthony Williams?

ANTWORT: Es ist die gleiche wie dieser Bug-Report: http://connect.microsoft.com/VisualStudio/feedback/details/770885

+1

Ich bin mir nicht sicher, was der Compiler erzeugt, ist notwendigerweise ein guter Weg, um die Anforderungen einer bestimmten Funktionalität zu bestimmen - es ist nicht unbekannt, dass Compiler "mehr tun, als sie brauchen". –

+0

@Mats Petersson Ja, aber es gibt nichts einfacher als nichts zu tun. Und das wurde vom Compiler verlangt, nichts als 'mov'. Wirklich die Entwickler von Microsoft haben mit dieser die einfachste Aufgabe gescheitert: "nichts tun"? :) – Alex

+0

Ich weiß MS VC (mindestens einige Versionen) wird zusätzliche "Sperren" auf Variablen als "volatile" deklariert generieren - nicht, weil der C++ - Standard es erfordert, sondern weil einige Bits des Codes verwendet, um plötzlich auf Single-Core-Prozessoren arbeiten funktionieren schlecht, wenn Sie SMP-Systeme verwenden. Dies ähnelt einer dieser Situationen. –

Antwort

6

Nein, die Semantik von std::memory_order_acquire nicht Prozessorbefehle auf x86/x86_64 nicht erfordert.

Alle Operationen load()/store() auf x86_64 erfordern keine Prozessorbefehle (Sperre/Zaun) genau atomic.store(val, std::memory_order_seq_cst);, die (LOCK) XCHG oder alternativ MOV (into memory),MFENCE erfordert.

Prozessorspeicher-Barrieren-Anweisungen für x86 (außer CAS), und auch ARM und PowerPC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

Disassembler GCC 4.8.1 x86_64 - GDB - load():

20  temp = a.load(std::memory_order_relaxed); 
    21  temp = a.load(std::memory_order_acquire); 
    22  temp = a.load(std::memory_order_seq_cst); 
0x46140b <+0x007b>   mov 0x38(%rsp),%ebx 
0x46140f <+0x007f>   mov 0x34(%rsp),%esi 
0x461413 <+0x0083>   mov 0x30(%rsp),%edx 

Disassembler GCC 4.8.1 x86_64 - GDB - Shop():

a.store(temp, std::memory_order_relaxed); 
a.store(temp, std::memory_order_release); 
a.store(temp, std::memory_order_seq_cst); 
0x4613dc <+0x004c>   mov %eax,0x20(%rsp) 
0x4613e0 <+0x0050>   mov 0x38(%rsp),%eax 
0x4613e4 <+0x0054>   mov %eax,0x20(%rsp) 
0x4613e8 <+0x0058>   mov 0x38(%rsp),%eax 
0x4613ec <+0x005c>   mov %eax,0x20(%rsp) 
0x4613f0 <+0x0060>   mfence 
0x4613f3 <+0x0063>   mov %ebx,0x20(%rsp) 

Disassembler MSVS 2012 x86_64 - load() - es ist die gleiche wie dieser Bugreport: http://connect.microsoft.com/VisualStudio/feedback/details/770885:

temp = a.load(std::memory_order_relaxed); 
000000013FE51A1F prefetchw [a] 
000000013FE51A24 mov   eax,dword ptr [a] 
000000013FE51A28 nop   dword ptr [rax+rax] 
000000013FE51A30 mov   ecx,eax 
000000013FE51A32 lock cmpxchg dword ptr [a],ecx 
000000013FE51A38 jne   main+40h (013FE51A30h) 
000000013FE51A3A mov   dword ptr [temp],eax 
    temp = a.load(std::memory_order_acquire); 
000000013FE51A3E prefetchw [a] 
000000013FE51A43 mov   eax,dword ptr [a] 
000000013FE51A47 nop   word ptr [rax+rax] 
000000013FE51A50 mov   ecx,eax 
000000013FE51A52 lock cmpxchg dword ptr [a],ecx 
000000013FE51A58 jne   main+60h (013FE51A50h) 
000000013FE51A5A mov   dword ptr [temp],eax 
    temp = a.load(std::memory_order_seq_cst); 
000000013FE51A5E prefetchw [a] 
    temp = a.load(std::memory_order_seq_cst); 
000000013FE51A63 mov   eax,dword ptr [a] 
000000013FE51A67 nop   word ptr [rax+rax] 
000000013FE51A70 mov   ecx,eax 
000000013FE51A72 lock cmpxchg dword ptr [a],ecx 
000000013FE51A78 jne   main+80h (013FE51A70h) 
000000013FE51A7A mov   dword ptr [temp],eax 

Disassembler MSVS 2012 x86_64 - store():

a.store(temp, std::memory_order_relaxed); 
000000013F8C1A58 mov   eax,dword ptr [temp] 
000000013F8C1A5C mov   dword ptr [a],eax 

    a.store(temp, std::memory_order_release); 
000000013F8C1A60 mov   eax,dword ptr [temp] 
000000013F8C1A64 mov   dword ptr [a],eax 

    a.store(temp, std::memory_order_seq_cst); 
000000013F8C1A68 mov   eax,dword ptr [temp] 
000000013F8C1A6C xchg  eax,dword ptr [a]