Kann die Hardware eine atomare Last, gefolgt von einem atomaren Speicher, neu anordnen, wenn der Speicher von der Last aC++

Programme in C++. Entwicklerforum
Anonymous
 Kann die Hardware eine atomare Last, gefolgt von einem atomaren Speicher, neu anordnen, wenn der Speicher von der Last a

Post by Anonymous »

Kann die Hardware eine atomare Last, gefolgt von einem atomaren Speicher, neu anordnen, wenn der Speicher von der Last abhängig ist? Es wäre höchst unintuitiv, wenn dies passieren könnte, denn wenn Thread1 spekulativ aufgrund einer Verzweigungsvorhersage oder aus irgendeinem Grund y = 1 schreibt, bevor die Bedingung in der if-Anweisung als wahr bestätigt wird, dann gibt es keine Möglichkeit, den Schaden rückgängig zu machen (die Änderungen rückgängig zu machen), wenn er später herausfindet, dass die Bedingung in „falsch“ aufgelöst wird, da möglicherweise bereits ein anderer Thread den aktualisierten Wert von y gelesen hat!
Das tue ich nicht Ich denke, die Release- und Acquire-Semantik wird in diesem Fall hilfreich sein. Ein std::memory_order_release auf y.store() würde verwendet werden, um frühere Schreibvorgänge für andere Threads sichtbar zu machen, die den Wert von y gesehen haben, aber in diesem Fall kann Thread1 nichts tun, um die Sichtbarkeit von x auf anderen Threads zu beeinflussen, da x nicht von Thread1 geschrieben wurde. Die Beispiele, die ich in der C++-Dokumentation für Acquire- und Release-Semantik gesehen habe, beziehen sich nur auf ein Paar Threads, bei denen einer reiner Schreiber und der andere reiner Leser ist.
Beispiel:

Code: Select all

std::atomic x;
std::atomic y;

void thread1() {
int val = x.load(std::memory_order_relaxed);
if( val == 42 ){
y.store(1, std::memory_order_relaxed);
}
}
BEARBEITEN: Ich wurde gebeten, Beispiele einschließlich anderer Threads bereitzustellen. Bei dem einen geht es um die Reihenfolge von Speichern, wie sie von Beobachtern wahrgenommen wird, während es beim anderen um die Möglichkeit einer spekulativen Ausführung von Speichern geht.
Nachdem ich diese Beispiele erstellt und noch einmal über das Problem nachgedacht habe, kann ich die Frage weiter klären:
  • Wenn Sie eine entspannte atomare Ladung haben, gefolgt von einer entspannten atomaren Speicherung auf eine andere Variable, und die Speicherung (durch eine if-Anweisung) vom Ergebnis der Ladung abhängig ist (das ist es, was Thread1 tut). Beispiel), richtet die if-Anweisung dann tatsächlich einen Lade-Speicher-Zaun ein, was bedeutet, dass der Ladevorgang abgeschlossen sein muss, bevor der Speicher für einen anderen Thread (oder eine andere beobachtende Entität wie ein Gerät mit direktem Speicherzugriff) sichtbar werden kann? Stellt die if-Anweisung in der C++-Terminologie ein Vorhergehen zwischen dem Speicher und dem Ladevorgang her? Ärgerlicherweise wird in der C++-Dokumentation zur Speicherreihenfolge nichts über bedingte Speicherungen erwähnt. Im C++-Formalismus wird ein Passes-Before eingerichtet, wenn der Store die Release-Reihenfolge verwendet. Aber die Release-Reihenfolge stoppt auch die Neuordnung von Store-Store und ist daher strenger. Wenn meine Idee also funktioniert und Sie nur die Load-Store-Reihenfolge benötigen, könnte die if-Anweisung ohne explizite Speichergrenzen effizienter sein als eine store_release. Ich halte es für wahrscheinlich, dass dies immer auf echter Hardware funktioniert, aber die C++-Dokumentation ist einfach unvollständig und gibt schwächere Garantien als nötig, was ein Verhalten ermöglicht, das auf echter Hardware in der realen Welt niemals passieren kann.

Code: Select all

// This example is about ordering.
// Will thread3 see the new value of x, if thread1 has seen it?
std::atomic x;
std::atomic y;

void thread1() {
int val = x.load(std::memory_order_relaxed);
if( val == 42 ){
y.store(1, std::memory_order_relaxed);
}
}

void thread2() {
x.store(42, std::memory_order_relaxed);
}

void thread3() {
if( y.load(std::memory_order_relaxed) == 1 ){
std::atomic_thread_fence(memory_order_acquire);
int r = x.load(std::memory_order_relaxed);
assert(r == 42); // Can this go wrong?
}
}

Code: Select all

// Similar, but we're putting it inside a loop
// to make it a little more interesting.
// This focuses on speculative execution.
std::atomic x;
std::atomic y;
std::atomic terminate;

void thread1() {
while( !terminate.load(std::memory_order_relaxed) ){

int val = x.load(std::memory_order_relaxed);
if( val == 42 ){
// Can y.store() be done speculatively?
y.store(1, std::memory_order_relaxed);
break;
}

}
}

void thread2() {
// This will count down and write to x,
// but should never actually store the value 42.
for(int idx = 10000000; idx > 42; --idx){
x.store(idx, std::memory_order_relaxed);
}
sleep_seconds(10);
terminate = true;
}

void thread3() {
while( !terminate.load(std::memory_order_relaxed) ){

if( y.load(std::memory_order_relaxed) == 1 ){
// This should never happen!
Open_Pandoras_Box();
Launch_Nuclear_Missiles();
Unleash_Armageddon();
break;
}

}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post