Reputation: 1
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:
x == true
and y == false
.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:
x == true
, but y could still be false, so ++z will not execute.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
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