2010-10-22 7 views
11

Ich lese Speicher Barrieren von Paul E. McKenney http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf alles in großen Details erklärt zu verstehen und wenn ich sehe, dass alles klar ist, ich einen Satz stoßen, die alles stultifies und ich denke dass ich nichts verstand. Lassen Sie mich das Beispiel zeigenSpeicher Zäune - Hilfe nötig ist

void foo(void) 
{ 
    a = 1; #1 
    b = 1; #2 
} 

void bar(void) 
{ 
    while (b == 0) continue; #3 
    assert(a == 1); #4 
} 

Lassen Sie uns sagen, dass diese beiden Funktionen auf einem anderen Prozessoren ausgeführt werden. Was nun passieren könnte ist, dass die Speicherung auf # 1 nach dem Speichern auf b # 2 durch den zweiten Prozessor zu sehen ist, weil die ersten Prozessorwarteschlangen auf "a" speichern und mit der Speicherung der b-Anweisung fortfahren. OK, das ist in Ordnung, wir fügen einen Schreibzaun in die Zeile zwischen # 1 und # 2 ein, aber dieser Code kann immer noch fehlschlagen, weil der zweite Prozessor die Nachricht invalidieren könnte, also fügen wir einen weiteren Speicherzaun hinzu (Lesezaun dieses Mal) die Linie zwischen # 4 und # 4.

void foo(void) 
{ 
    a = 1; #1 
    write_memory_barrier(); 
    b = 1; #2 
} 

void bar(void) 
{ 
    while (b == 0) continue; #3 
    read_memory_barrier(); 
    assert(a == 1); #4 
} 

Dieser zweiten Prozessor erzwingt alle Nachrichten in der Warteschlange zu verarbeiten (a ungültig machen) und erneut gelesen von 4 MESI Nachricht zum ersten Prozessor auf # lesen sendet. OK. Als nächstes wird der Artikel

Viele CPU-Architekturen sagt deshalb bieten schwächer Speicher-Barriere Anweisungen, die nur eine oder die andere dieser beiden tun. Grob gesagt, eine "Lesespeicherbarriere" markiert nur die ungültig Warteschlange und eine "Schreibspeicher Barriere" markiert nur den Speicherpuffer. während eine vollwertige Speicherbarriere beides tut.

Große, das ist klar, aber danach sehe ich

Der Effekt davon ist, dass Speichersperraufträge nur Lasten auf die CPU, die es ausführt, eine lesen, so dass alle Lasten vor dem Lesen Speicher Barriere scheint vor jeder Belastung nach dem Lesen Speicherbarriere abgeschlossen sein. Ähnlich wird ein Schreibspeicher Barrierenaufträge nur speichert, wieder auf der CPU, die sie ausführt, und wieder so, dass alle Geschäfte vor der Schreibspeicherbarriere zu angezeigt haben, bevor jeder Laden abgeschlossen nach dem Schreibspeicherbarriere.

so

alle Lasten der Lesespeicherbarriere vorhergehenden wird erscheinen, bevor eine Last Barriere, die die Lesespeicher folgende abgeschlossen haben

, das alles mischt, was zuvor erläutert wurde. Was heißt das? Welche Last in der Funktion "bar" muss vor dem Laden von "a" # 4 abgeschlossen sein? Ich verstehe, dass die Assertion in dieser Funktion ohne Speicherbarriere versagen könnte, nur weil der Prozessor einen alten Wert lesen kann, weil er es immer noch nicht geschafft hat, seine Cache-Zeile ungültig zu machen, wo sich das Objekt "a" befindet.

Erklärung im Detail wäre wirklich hilfreich, ich versuche es den ganzen Tag zu verstehen.

Vielen Dank im Voraus.

Antwort

10

Was bedeutet das?

Es bedeutet, dass, wenn Sie:

read 
read 
read 
READ BARRIER 
read 
read 
read 

dann die Lesebarriere einen fungiert als „join Punkt“ Dividieren diese in zwei Chargen lesen. Alle Lesevorgänge, die der Lesebarriere vorangehen, wurden durchgeführt, bevor irgendein Lesen, das der Lesebarriere folgt, begonnen wird.

Welche Lasten in bar() müssen abgeschlossen sein, bevor die Last von a (# 4) gestartet wird?

Alle Lesevorgänge von b (# 3) müssen vor jedem Lesen von a (# 4) stehen. Das bedeutet, dass a nicht gelesen wird, bis b nicht mehr 0 ist. Weil foo() eine Schreibsperre verwendet, um sicherzustellen, dass a bereits geändert wurde 1 (# 1) bis die b geändert wird (# 2). Die beiden Barrieren wirken so zusammen, um sicherzustellen, dass die Behauptung immer erfolgreich ist.

+0

Vielen Dank für Ihre Antwort, aber wenn wir uns Beispiel Punkt 4.3 in dem Artikel ansehen, sehen wir ein Beispiel, wenn tatsächlich alle Lesevorgänge von b (# 3) dem Lesen eines ohne Speicherbarriere vorausgehen und Assert immer noch fehlschlägt, weil CPU 1 führt das assert (a == 1) aus, und da der alte Wert von "a" immer noch im Cache der CPU 1 ist, schlägt diese Behauptung fehl, . – confucius

+0

Im festen Code (mit Lesebarriere) führt die CPU 1 das assert (a == 1) aus, und da die Cachezeile, die "a" enthält, nicht mehr in CPU 1's Cache ist, weil die Lesbarriere gezwungen ist, die Cachezeile ungültig zu machen), sendet es eine "gelesene" Nachricht. – confucius

+0

Es ist also nicht nur eine Bestellung, oder? Ich sehe nicht, wie es erklärt werden könnte, wenn man nur sagt, dass es die Ordnung zwingt. Ich denke, dass es etwas gibt, das ich nicht verstehe, ein grundlegendes Detail, das es mir nicht erlaubt, mich mit all den Informationen, die ich habe, zu verbinden und das endgültige Bild zu bekommen. – confucius