Is the following code standards compliant? (or can it be made compliant without making x
atomic or volatile
?)
This is similar to an earlier question, however I would like a citation to the relevant section of the C++ standard, please.
My concern is that atomic store()
and load()
do not provide sufficient compiler barriers for the non-atomic variables (x
in the example below) to have correct release and acquire semantics.
My goal is to implement lock-free primitives, such as queues, that can transfer pointers to regular C++ data structures between threads.
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
int x; // regular variable, could be a complex data structure
std::atomic<int> flag { 0 };
void writer_thread() {
x = 42;
// release value x to reader thread
flag.store(1, std::memory_order_release);
}
bool poll() {
return (flag.load(std::memory_order_acquire) == 1);
}
int main() {
x = 0;
std::thread t(writer_thread);
// "reader thread" ...
// sleep-wait is just for the test.
// production code calls poll() at specific points
while (!poll())
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << x << std::endl;
t.join();
}
With acquire/release, yes, this will be enough. Relevant quotes (from cppreference—as good as the standard in most cases):
Memory Model
When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless either
both conflicting evaluations are atomic operations (seestd::atomic
)- one of the conflicting evaluations happens-before another (see
std::memory_order
)std::memory_order
Release-Acquire ordering
If an atomic store in thread A is tagged
memory_order_release
and an atomic load in thread B from the same variable is taggedmemory_order_acquire
, all memory writes (non-atomic and relaxed atomic) that happened-before the atomic store from the point of view of thread A, become visible side-effects in thread B, that is, once the atomic load is completed, thread B is guaranteed to see everything thread A wrote to memory.
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