2014-12-06 18 views
11

In der x86-Architektur haben Speicher an demselben Speicherort eine Gesamtreihenfolge, siehe z. B. this video. Was sind die Garantien im C++ 11-Speichermodell?Werden zwei entspannte Schreibvorgänge an derselben Stelle in verschiedenen Threads immer in der gleichen Reihenfolge von anderen Threads angezeigt?

Genauer gesagt, in

-- 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); 

würde das Ergebnis r1==1, r2==2, r3==2, r4==1 (auf einer anderen Architektur als x86) erlaubt sein? Was wäre, wenn ich alle memory_order durch std::memory_order_relaxed ersetzen würde?

Antwort

7

Nein, ein solches Ergebnis ist nicht erlaubt. §1.10 [intro.multithread]/p8, 18 (zitiert N3936/C++ 14; der gleiche Text wird in den Absätzen 6 und 16 für N3337/C++ 11 gefunden):

8 bis a alle Modifikationen insbesondere Atom Objekt M tritt bei einiger bestimmten Gesamtordnung, die so genannten Modifikation um von M.

18 Wenn ein Wert Berechnung A ein Atom Objekt M vor einer Wertberechnung von B M passiert, und A hat seine Wert von einem Nebeneffekt X auf M, dann soll der von B berechnete Wert entweder der von X gespeicherte Wert oder der von einem Nebeneffekt Y auf M gespeicherte Wert sein, wobei Y foll ows X in die Modifikationsreihenfolge von M. [Hinweis: Diese Anforderung ist bekannt als lesen-lesen Kohärenz. - Endnote]

In Ihrem Code gibt es zwei Nebenwirkungen und von p8 sie in einer bestimmten Gesamt Reihenfolge auftreten. In Thread 3 passiert die Wertberechnung zur Berechnung des in r1 zu speichernden Wertes vor der von r2, so dass r1 == 1 und r2 == 2 bekannt ist, dass der durch Thread 1 durchgeführte Speicher dem Speicher vorausgeht, der von Thread 2 in der Änderungsreihenfolge x ausgeführt wird. In diesem Fall kann Thread 4r3 == 2, r4 == 1 nicht beobachten, ohne mit p18 zu kollidieren. Dies ist unabhängig von der verwendeten memory_order.

Es eine Notiz in p21 (p19 in N3337), die relevant ist:

[Hinweis: Die vier vorangegangenen Kohärenz Anforderungen effektiv disallow Compiler Umordnung von atomaren Operationen auf ein einzelnes Objekt, sogar wenn beide Operationen entspannte Lasten sind. Dies macht effektiv die Cache-Kohärenz-Garantie, die von der meisten verfügbaren Hardware für C++ atomare Operationen zur Verfügung gestellt wird. - Endnote]

+0

Können Sie mir helfen, p18 zu verstehen? Ist "Wertberechnung" ein Synonym für "Load-from-Atomic" und "Side-Effect" Synonym für "Store-to-Atomic"? –

+0

@ TobiasBrüll Die Last ist eine Wertberechnung; Der Laden ist ein Nebeneffekt. –

+0

Welche anderen Arten von Wertberechnungen gibt es? Und welche anderen Nebenwirkungen? –

4

Per C++ 11 [intro.multithread]/6: "Alle Änderungen an ein bestimmtes Objekt Atom M in einer bestimmten Gesamt Reihenfolge auftreten, die Änderung der Reihenfolge der M genannt" Folglich werden Lesevorgänge eines atomaren Objekts durch einen bestimmten Thread niemals "ältere" Werte sehen, als sie der Thread bereits beobachtet hat. Beachten Sie, dass hier keine Speicherreihenfolgen erwähnt werden. Daher gilt diese Eigenschaft für alle - seq_cst bis relaxed.

In dem im OP angegebenen Beispiel kann die Änderungsreihenfolge x entweder (0,1,2) oder (0,2,1) lauten. Ein Thread, der einen bestimmten Wert in dieser Modifikationsreihenfolge beobachtet hat, kann später keinen früheren Wert mehr beobachten. Das Ergebnis impliziert, dass die Änderungsreihenfolge von x ist, aber r3==2, r4==1 bedeutet, dass es (0,2,1) ist, ein Widerspruch. Daher ist das Ergebnis bei einer C++ 11-konformen Implementierung nicht möglich.

Verwandte Themen