Frage

Ich denke dabei an, ob es möglich ist, für die Atom Variable den alten Wert in acquire-Release Paar zu laden. Nehmen wir an, wir atomare Variable x, und wir speichern diese Variable mit Release-Semantik und später laden Sie es mit acquire Semantik ist es theoretisch möglich, den alten Wert zu lesen?

std::atomic<int> x = 0;

void thread_1()
{
   x.store(1, std::memory_order_release);
}
void thread_2()
{
   assert(x.load(std::memory_order_acquire) != 0);
}

, wenn die Funktion Thread 1 ist beendet, wenn Gewinde 2 lädt die x (so wird der neue Wert gespeichert ist) ist es möglich, für Gewinde 2 alten Wert von x zu laden? Mit anderen Worten, wenn tatsächliche Speicher x erfolgt, bevor die Last für assert Feuer es möglich ist?

Soweit ich verstand von Artikeln in Internet es möglich ist, aber ich kann nicht verstehen, warum. Speicher Zaun erzeugt durch Speicher x Garantien zu leeren Speicherpuffer, während acquire Speicher Zaun in Last von x zu entkräften Cache-Zeile gewährleistet ist, so hat es lesen up-to-date-Wert.

hinzugefügt

Bedeutet es, dass acquire Release selbst hat keine erzwungene Ordnung? Es ist nur etwas, was getan wurde vor der Freigabe vor der Freigabe und alles passieren wird, das nach dem acquire getan wird, nachdem es geschehen, so acquire-Release Paar erzwingt auf den anderen Operationen der Bestellung (warum ??). Habe ich es richtig gesagt? Bedeutet es, dass in dem Code unten assert garantiert wird nicht Feuer

std::atomic<int> x = 0;
std::atomic<int> y = 0;

void thread_1()
{
   y.store(1, std::memory_order_relaxed);
   x.store(1, std::memory_order_release);
}
void thread_2()
{
   x.load(std::memory_order_acquire);
   assert(y.load(std::memory_order_relaxed) != 0);
}

natürlich wieder, wenn der Faden 1 wurde bereits das Geschäft abgeschlossen. Wenn wir x.load mit while (x.load () == 0) wird zu 100% Arbeit ersetzen, aber ich weiß nicht, was dies verursacht zu arbeiten.

Und was ist, wenn ich den Code mit dem Code unten

ersetzen
std::atomic<int> x = 0;

void thread_1()
{
   x.exchange(1, std::memory_order_acq_rel);
}
void thread_2()
{
   assert(x.exchange(0, std::memory_order_acq_rel) != 0);
}

Gibt es etwas ändern?

Danke.

War es hilfreich?

Lösung

Sie können Speicher / Ladefunktionen mit Release / acquire Speichern, um als der folgenden Pseudo-Code betrachten:

template<class T>
struct weak_atomic
{
   void store(T newValue)
   {
      ReleaseBarrier();
      m_value = newValue;
   }

   T load()
   {
      T value = m_value;
      AcquireBarrier();
      return value;      
   }

   volatile T m_value;
}

Du hast gesagt,

Speicher Zaun durch Speicher x erzeugt Garantien zu leeren Speicherpuffer

Wie ich verstehe, wird die Release-Speicherbarriere, um die CPU veranlassen, seine Speicherpuffer zu spülen, aber es wird getan werden, bevor die Anwendung neuen Wert x. So scheint es möglich, alten Wert von x von einer anderen CPU zu lesen.

Wie auch immer, schwach atomics ist sehr komplexer Bereich. Stellen Sie sicher, dass Sie Speicher Barrieren zu verstehen, bevor mit Lock-freier Programmierung fortfahren.

ADDED

Es scheint, Sie sind immer noch mit Speicherbarrieren verwechselt. Dies ist ein ziemlich typisches Beispiel für ihre Verwendung.

volatile int  x;
volatile bool ok;

void thread_1()
{
   x = 100;
   ok = true;
}

void thread_2()
{
   if (ok)
   {
      assert(x == 100);
   }
}

Durch Out-of-Order-Ausführung können Sie die folgende Sequenz erhalten:

thread 1 sets ok to true
thread 2 checks ok is true and reads some garbage from x
thread 1 sets x to 100 but it is too late

Eine weitere mögliche Folge:

thread 2 reads some garbage from x
thread 2 checks for ok value

Wir können das in Ordnung bringen mit dem Release und acquire Speicherbarrieren.

volatile int  x;
volatile bool ok;

void thread_1()
{
   x = 100;
   ReleaseBarrier();
   ok = true;
}

void thread_2()
{
   if (ok)
   {
      AcquireBarrier();
      assert(x == 100);
   }
}

ReleaseBarrier() garantiert, dass Speicher schreibt nicht die Barriere springen. Es bedeutet, dass ok nur true gesetzt wird, wenn x bereits gültigen Wert enthält.

AcquireBarrier() garantiert, dass Speicher liest, kann nicht die Barriere springen. Es bedeutet, dass der Wert von x erst nach Überprüfung ok Zustand gelesen wird.

Dies ist, wie Freigabe- / acquire Paar soll verwendet werden. Wir können dieses Beispiel mit meinem weak_atomic umschreiben.

volatile int  x;
weak_atomic<bool> ok;

void thread_1()
{
   x = 100;
   ok.store(true);
}

void thread_2()
{
   if (ok.load())
   {
      assert(x == 100);
   }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top