What is wrong with the below code? I expect to see 10 to be produced by consumer1 and consumer2, but I see -1 sometimes.
#include <thread>
#include <atomic>
#include <cassert>
#include <string>
std::atomic<int> global;
void producer()
{
global.store(10, std::memory_order_release);
}
void consumer1()
{
int a = global.load(std::memory_order_acquire);
printf("a in consumer1 %d\n", a);
}
void consumer2()
{
int a = global.load(std::memory_order_acquire);
printf("a in consumer2 %d\n", a);
}
int main()
{
global.store(-1, std::memory_order_seq_cst);
std::thread t1(producer);
std::thread t2(consumer1);
std::thread t3(consumer2);
t1.join(); t2.join(); t3.join();
}
I see
a in consumer1 10
a in consumer2 10
and
a in consumer1 -1
a in consumer2 10
If I understand correctly, the thread which does memory_order_acquire
always syncs with the thread which does memory_order_release
. Am I wrong?
I am running on x86-64 bit machine. I am compiling with
g++ file.cpp -pthread -std=c++11
Atomic variables have the very nice property that the value read is a value that has been written before. And with release/acquire semantics it's even the last value written.
In this case, you have 2 writes and two reads. Only the write of -1 is sequenced-before the reads, the write of 10 is not sequenced. Therefore either value may be the last written. It's guaranteed that you read -1 or 10 and not garbage.
If you add a sleep before
global.store(10, std::memory_order_release);
then you can observe consistently a -1.
The key point is that std::memory_order is not a sempaphore-like syncronization, but a rather more subtle matter. See cppreference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With