samedi 18 décembre 2021

Understanding C++ memory orders

While trying to understand memory orders I stumbled upon this video. The video claims that the assertion at the end of the main function may fail, but I do not understand why or if this is correct.

What I understand from std::memory_order_release is that no reads or writes in the current thread can be re-ordererd after this store. And for std::memory_order_acquire no reads or writes in the current thread can be re-ordered before this load. But for each reading thread in the example given there is a wait for a different writer thread, and the if from a reading thread cannot be re-ordered before the while, because of the std::memory_order_acquire. So, shouldn't at least one thread increment the z variable?

#include <atomic>
#include <thread>
#include <memory>
#include <cassert>

std::atomic<bool> x;
std::atomic<bool> y;
std::atomic<int> z;

void write_x() {
  x.store(true, std::memory_order_release);
}

void write_y() {
  y.store(true, std::memory_order_release);
}

void read_x_then_y() {

  while (!x.load(std::memory_order_acquire));

  if (y.load(std::memory_order_acquire)) {
    z++;
  }
}

void read_y_then_x() {

  while (!y.load(std::memory_order_acquire));

  if (x.load(std::memory_order_acquire)) {
    z++;
  }
}

int main() {

  x = false;
  y = false;
  z = 0;

  std::thread a(write_x);
  std::thread b(write_y);
  std::thread c(read_x_then_y);
  std::thread d(read_y_then_x);

  a.join();
  b.join();
  c.join();
  d.join();

  assert(z != 0);

  return 0;
}

Compiled with CPPFLAGS="-latomic -pthread" make main

Aucun commentaire:

Enregistrer un commentaire