Yes, your interpretation is correct: the program contains a data race due to the unconditional read of A
. The program is simplified to be a minimal example to demonstrate the workings of acquire-release for the blog: the author discusses only how the memory ordering enforces that the "reader" thread must read 42 from A
if it reads 1
from Ready
. He doesn't talk about the alternative because it's not germaine.
In a real program, the "reader" thread would probably wait in a loop on Ready
to get the desired semantics:
int A = 0;
std::atomic<int> Ready(0);
void write_thread() {
A = 42;
Ready.store(1, std::memory_order_release);
}
void read_thread() {
while (!Ready.load(std::memory_order_acquire))
;
int r2 = A;
assert(r2 == 42);
}
Or use a conditional as in your example:
int A = 0;
std::atomic<int> Ready(0);
void write_thread() {
A = 42;
Ready.store(1, std::memory_order_release);
}
void read_thread() {
while (true) {
if (Ready.load(std::memory_order_acquire)) {
int r2 = A;
assert(r2 == 42);
break;
}
std::cout << "Not ready yet - try again later.\n" << std:flush;
std::this_thread::sleep_for(std::chrono::milliseconds{125});
}
}