hao
hao

Reputation: 1

Why different threads can see different memory operation orders?

The following code is an example from the book C++ Concurrency in Action (2nd edition). The author mentions that threads Ta and Tb can observe different memory states:

  1. Tc observes x == true and y == false.
  2. Td observes x == false and y == true.

As a result, the value of z could be 0.


std::atomic<bool> x(false),y(false);
std::atomic<int> z(0);
void write_x() { // Ta
  x.store(true, std::memory_order_release); // A
}
void write_y() { // Tb
 y.store(true, std::memory_order_release);  // B
}
void read_x_then_y() { // Tc
 while(!x.load(std::memory_order_acquire)); // C
 if(y.load(std::memory_order_acquire))      // D
   ++z;
}
void read_y_then_x() { // Td
 while(!y.load(std::memory_order_acquire)); // E
 if(x.load(std::memory_order_acquire))      // F
   ++z;
}
int main() {
 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.load() != 0);
}

Here is my understanding: Statements A and B are independent of each other, so they can execute in any order. In a particular execution of the program, there will be a specific order, such as AB or BA. For example, assuming the order is AB:

  1. When thread Tc reaches D, x == true, but y could still be false, so ++z will not execute.
  2. When thread Td reaches F, y == true. Since B runs after A, x must already be true, so ++z will execute, resulting in z > 0.

Why is my understanding wrong?

Initially, I suspected that the result of std::atomic<T>::store might not be immediately visible to other threads. For example, even though A has executed, Td might still see x == false, preventing ++z from executing. However, after researching the visibility of atomic operations, I found that if x.store runs before x.load, then x.load should see the result of x.store, as described in this question about memory_order_relaxed and visibility.

So, why can Ta and Tb observe different states?

Upvotes: -1

Views: 77

Answers (1)

user2357112
user2357112

Reputation: 280182

In a particular execution of the program, there will be a specific order, such as AB or BA.

This is wrong. You need to use memory_order_seq_cst (the default) if you want that. With acquire/release operations, you only get per-atomic-object modification orders. These cannot be combined into a global order across multiple atomic objects.

Upvotes: 2

Related Questions