2016-04-05 5 views
1

Gegen Ende seines talk über Speicher Barrieren (Zäune) "Warum Standalone Zäune suboptimal sind", gab er das folgende Beispiel (Hinweis: global ist nicht atomarer Typ):Herb Sutter Atomic Weapons

// thread 1          // thread 2 
widget *temp = new widget(); 
global = temp; 
               global->do_something(); 
               global->do_something_else(); 

Später sagte er, dass wir volle Zäune haben sollte wie die folgende:

// thread 1          // thread 2 
    widget *temp = new widget(); 
XX mb(); XXXXXXXXXXXXXXXXXXXXX 
    global = temp; 
                temp2 = global; 
               XX mb(); XXXXXXXXXXXXXXXX 
                temp2->do_something(); 
                temp2 = global; 
               XX mb(); XXXXXXXXXXXXXXXX 
                temp2->do_something_else(); 

ich frage mich, warum in Thread 1 Sie eine Barriere benötigen? global hängt von temp und Compiler würde global = temp; über die Konstruktion von temp sowieso nicht verschieben. Ein Grund, warum ich daran denke, dass die Speicherbarriere ist, dass die Aussage global=temp; irgendwie in der Mitte der Konstruktion von new widget() getan werden kann und Thread 2 würde dann eine teilweise aufgebaut global sehen. Ist es möglich, dass die Zuweisung an global in der Mitte des Neubaus widget geplant wird? Oder die Speicherbarriere hat andere Gründe?

Auch in Thread 2, brauchen Sie nicht eine andere Barriere nach temp2->do_something();? Wie in der derzeit transformierter Form, können die folgenden Aussagen noch während der Ausführung neu geordnet werden:

            temp2 = global; 
               XX mb(); XXXXXXXXXXXXXXXX 

                temp2 = global; 
                temp2->do_something(); 

               XX mb(); XXXXXXXXXXXXXXXX 
                temp2->do_something_else(); 

Und das ist nicht das, was Sie da jetzt soll Ihnen nur Mitgliederfunktionen auf einem temp2 statt Lesen Sie einen neuen Wert von global aufrufen vor Ausführen do_something_else().

Wenn eine solche Neuordnung in Thread 2 nicht möglich ist, warum brauchen wir dann die Barrieren an erster Stelle in Thread 2, wenn temp2->do_something(); nicht vor temp2 = global; neu geordnet werden kann.

Antwort

1

Ich frage mich, warum in Thread 1 Sie eine Barriere benötigen? global hängt von Temp und Compiler würde nicht verschieben global = temp; über der Konstruktion von sowieso Temp.

Es hat mit der Initialisierung der inneren Mitglieder von temp zu tun. Aufgrund CPU-Caching und Neuordnung, ohne Speicherschranke global hier möglicherweise die Adresse von neuen temp, aber Speicher, der von temp gezeigt wird, scheint nicht initialisiert erscheinen.

Was die zweite Frage, obviosuly

temp2->do_something(); 
temp2 = global; 

nicht als

temp2 = global; 
temp2->do_something(); 

neu geordnet werden, da es etwas auf dem ganz anderen Objekt tun!

+0

Ok. Wie ich vermutet habe. Was ist mit Frage zu Thread 2? Brauchen Sie eine andere Barriere nach 'temp2-> do_something();'? – Rich

+0

@Rich, antwortete das auch. – SergeyA

+0

Ich verstehe Ihren Kommentar zu Thread 2 nicht ganz. Warum können sie nicht nachbestellt werden? Erachten Compiler und Hardware die Reihenfolge der Schreibvorgänge nach dem Lesen? und welche verschiedenen Objekte sind beteiligt? – Rich